From c7009dcbfcaea3ffbb7f06f5a2908e5262352856 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Fri, 8 May 2026 16:33:59 -0600 Subject: [PATCH 01/62] First version of the Central adapter base class and factory functions. Implemented both factory functions that construct a CentralAdapter. Implemented a workaround for fetching Central's application and protocol versions. --- src/cbshm/include/cbshm/central_adapter.h | 54 ++++++++ src/cbshm/src/central_adapter_factory.cpp | 153 ++++++++++++++++++++++ 2 files changed, 207 insertions(+) create mode 100644 src/cbshm/include/cbshm/central_adapter.h create mode 100644 src/cbshm/src/central_adapter_factory.cpp diff --git a/src/cbshm/include/cbshm/central_adapter.h b/src/cbshm/include/cbshm/central_adapter.h new file mode 100644 index 00000000..9ee1cc3c --- /dev/null +++ b/src/cbshm/include/cbshm/central_adapter.h @@ -0,0 +1,54 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file central_adapter.h +/// @author Caden Shmookler +/// @date 2026-05-05 +/// +/// @brief The base class of Central-compatible shared memory adapters +/// +/// This module provides the interface (base class) of adapters that attach to +/// the shared memory of specific supported versions of Central. +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#ifndef CBSHM_CENTRAL_ADAPTER_H +#define CBSHM_CENTRAL_ADAPTER_H + +namespace cbshm { + +#ifdef _WIN32 + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Base-class adapter for Central-compatible shared memory access +/// +/// This module provides the interface for adapters that attach to the shared +/// memory of specific supported versions of Central. +/// +class CentralAdapter { +public: + virtual ~CentralAdapter() = default; + + // TODO: Declare required methods +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Instantiate a shared memory adapter for Central that corresponds to +/// Central's protocol version. +/// +cbutil::Result makeCentralAdapter(); + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Instantiate a shared memory adapter for Central that corresponds to +/// a specific protocol version. +/// +cbutil::Result makeCentralAdapter(cbproto_protocol_version_t protocol_version); + +#endif + +} // namespace cbshm + +#endif // CBSHM_CENTRAL_ADAPTER_H diff --git a/src/cbshm/src/central_adapter_factory.cpp b/src/cbshm/src/central_adapter_factory.cpp new file mode 100644 index 00000000..d650665e --- /dev/null +++ b/src/cbshm/src/central_adapter_factory.cpp @@ -0,0 +1,153 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file central_adapter_factory.cpp +/// @author Caden Shmookler +/// @date 2026-05-05 +/// +/// @brief Factory functions for the base class of Central-compatible shared memory adapters +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "platform_first.h" + +#include +#include +#include + +namespace cbshm { + +#ifdef _WIN32 + +static Result getCentralAppVersion() { + // As of 2026-05-07, the 'version' field in Central's shared memory + // configuration buffer is set to a magic number, 96, instead of a meaningful + // value that indicates the application or protocol version. The only other + // field in Central's shared memory with version information is + // procinfo[].version, but it's byte offset changes between protocol versions + // so it is unusable. This function infers Central's protocol version by + // inspecting VersionInfo.ProductVersion in Central.exe and converting from + // application version to protocol version. + + // Get Central's application version by inspecting the properties of the Central.exe binary + + std::string central_path = "C:\\Program Files\\Blackrock Microsystems\\Cerebus Central Suite\\Central.exe"; + + DWORD handle = 0; + DWORD block_size = GetFileVersionInfoSizeA(central_path.c_str(), &handle); + if (block_size == 0) { + return Result::error("Failed to get the length of the resource block containing Central's application version"); + } + + std::vector block(block_size); + if (!GetFileVersionInfoA(central_path.c_str(), handle, block_size, block.data())) { + return Result::error("Failed to extract the version resource block from Central"); + } + + struct LangCodePage { + WORD lang; + WORD codepage; + } *translate = nullptr; + UINT translate_size = 0; + if (!VerQueryValueA(block.data(), "\\VarFileInfo\\Translation", (LPVOID*)&translate, &translate_size) || translate_size == 0) { + return Result::error("Failed to lookup the available version translations for Central"); + } + + char sub_block[64]; + sprintf_s(sub_block, sizeof(sub_block), "\\StringFileInfo\\%04x%04x\\ProductVersion", translate[0].lang, translate[0].codepage); + + char* value = nullptr; + UINT value_size = 0; + if (!VerQueryValueA(block.data(), sub_block, (LPVOID*)&value, &value_size) || value_size == 0) { + return Result::error("Failed to extract Central's version from the resource block"); + } + std::string app_version = std::string(value, value_size - 1); // strip trailing null byte + + return Result::ok(app_version); +} + +Result makeCentralAdapter() { + Result app_version_result = getCentralAppVersion(); + if (! app_version_result.isOk()) { + return Result::error("Failed to extract the application version from Central"); + } + std::string& app_version = app_version_result.value(); + + // Get the indicies of both dots in the version string + size_t ldot_idx = app_version.find("."); + size_t rdot_idx = app_version.rfind("."); + if (ldot_idx == std::string::npos or rdot_idx == std::string::npos) { + return Result::error("Failed to find both dots separating the major, minor, and patch version values in '" + app_version + "'"); + } + + // Extract the major version number + char* major_version_begin = app_version.data(); + char* major_version_end = app_version.data() + ldot_idx; + uint32_t major_version; + std::from_chars_result result{ .ptr=nullptr, .ec=std::errc(0) }; + result = std::from_chars(major_version_begin, major_version_end, major_version); + if (result.ec == std::errc(0) && result.ptr == major_version_end) { + return Result::error("Failed to isolate the major version value from '" + app_version + "'"); + } + + // Extract the minor version number + char* minor_version_begin = app_version.data() + ldot_idx + 1; + char* minor_version_end = app_version.data() + rdot_idx; + uint32_t minor_version; + result.ptr = nullptr; + result.ec = std::errc(0); + result = std::from_chars(minor_version_begin, minor_version_end, minor_version); + if (result.ec == std::errc(0) && result.ptr == minor_version_end) { + return Result::error("Failed to isolate the minor version value from '" + app_version + "'"); + } + + // Convert application version to protocol version + cbproto_protocol_version_t protocol_version = CBPROTO_PROTOCOL_UNKNOWN; + switch(major_version) { + case 7: + switch (minor_version) { + case 8: + /* fallthrough */ + case 7: + protocol_version = CBPROTO_PROTOCOL_CURRENT; + break; + case 6: + protocol_version = CBPROTO_PROTOCOL_410; + break; + case 5: + protocol_version = CBPROTO_PROTOCOL_400; + break; + case 0: + protocol_version = CBPROTO_PROTOCOL_311; + break; + default: + return Result::error("Unrecognized minor version number for version '" + app_version + "'"); + } + break; + default: + return Result::error("Unrecognized major version number for version '" + app_version + "'"); + } + + return makeCentralAdapter(protocol_version); +} + +Result makeCentralAdapter(cbproto_protocol_version_t protocol_version) { + switch (protocol_version) { + // // TODO: Implement legacy layouts + // case CBPROTO_PROTOCOL_CURRENT: + // return CentralAdapterV420(); + // case CBPROTO_PROTOCOL_410: + // return CentralAdapterV410(); + // case CBPROTO_PROTOCOL_400: + // return CentralAdapterV400(); + // case CBPROTO_PROTOCOL_311: + // return CentralAdapterV311(); + case CBPROTO_PROTOCOL_UNKNOWN: + /* fallthrough */ + default: + return Result::error("Unrecognized protocol version, enum value: " + std::to_string(protocol_version)); + } +} + +#endif + +} // namespace cbshm + From da77bc202d0c821cb2bdf1d36a1e31c16cb027ea Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Mon, 11 May 2026 12:35:27 -0600 Subject: [PATCH 02/62] Add an example for the Central adapter --- examples/CMakeLists.txt | 1 + examples/CentralAdapter/central_adapter.cpp | 233 ++++++++++++++++++++ 2 files changed, 234 insertions(+) create mode 100644 examples/CentralAdapter/central_adapter.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 48df406e..e311fe3b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -6,6 +6,7 @@ set(CBSDK_EXAMPLES "gemini_example:GeminiExample/gemini_example.cpp" "simple_device:SimpleDevice/simple_device.cpp" "central_client:CentralClient/central_client.cpp" + "central_adapter:CentralAdapter/central_adapter.cpp" "ccf_test:CCFTest/ccf_test.cpp" "recording_test:RecordingTest/recording_test.cpp" ) diff --git a/examples/CentralAdapter/central_adapter.cpp b/examples/CentralAdapter/central_adapter.cpp new file mode 100644 index 00000000..90261d4b --- /dev/null +++ b/examples/CentralAdapter/central_adapter.cpp @@ -0,0 +1,233 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file central_adapter.cpp +/// @brief Diagnostic tool for testing CereLink and Central compatibility +/// +/// Instantiates a CentralAdapter in order to attach to Central's shared memory. +/// +/// Usage: +/// central_adapter [instance] +/// central_adapter # Default: instance 0 +/// central_adapter 1 # Instance 1 (for multi-instance setups) +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace cbshm; + +std::atomic g_running{true}; + +void signalHandler(int) { g_running = false; } + +static std::string makeName(const char* base, int instance) { + if (instance == 0) return base; + return std::string(base) + std::to_string(instance); +} + +int main(int argc, char* argv[]) { + int instance = 0; + if (argc >= 2) instance = std::atoi(argv[1]); + + signal(SIGINT, signalHandler); + signal(SIGTERM, signalHandler); + + std::cout << "==============================================\n"; + std::cout << " CereLink CentralAdapter Diagnostic\n"; + std::cout << "==============================================\n\n"; + + auto centralAdapter = cbshm::makeCentralAdapter(); + if (centralAdapter.isError()) { + std::cout << centralAdapter.error() << std::endl; + } + + // // Print struct sizes for comparison with Central + // std::cout << "=== Struct Size Verification ===\n"; + // std::cout << " sizeof(CentralLegacyCFGBUFF): " << sizeof(CentralLegacyCFGBUFF) << "\n"; + // std::cout << " sizeof(CentralReceiveBuffer): " << sizeof(CentralReceiveBuffer) << "\n"; + // std::cout << " sizeof(CentralTransmitBuffer): " << sizeof(CentralTransmitBuffer) << "\n"; + // std::cout << " sizeof(CentralTransmitBufferLocal): " << sizeof(CentralTransmitBufferLocal) << "\n"; + // std::cout << " sizeof(CentralPCStatus): " << sizeof(CentralPCStatus) << "\n"; + // std::cout << " sizeof(CentralSpikeBuffer): " << sizeof(CentralSpikeBuffer) << "\n"; + // std::cout << " sizeof(CentralSpikeCache): " << sizeof(CentralSpikeCache) << "\n"; + // std::cout << " sizeof(CentralAppWorkspace): " << sizeof(CentralAppWorkspace) << "\n"; + // std::cout << "\n"; + // + // // Print key constants + // std::cout << "=== Key Constants ===\n"; + // std::cout << " CENTRAL_cbMAXPROCS: " << CENTRAL_cbMAXPROCS << "\n"; + // std::cout << " CENTRAL_cbNUM_FE_CHANS: " << CENTRAL_cbNUM_FE_CHANS << "\n"; + // std::cout << " CENTRAL_cbMAXCHANS: " << CENTRAL_cbMAXCHANS << "\n"; + // std::cout << " CENTRAL_cbMAXBANKS: " << CENTRAL_cbMAXBANKS << "\n"; + // std::cout << " CENTRAL_cbMAXNTRODES: " << CENTRAL_cbMAXNTRODES << "\n"; + // std::cout << " CENTRAL_AOUT_NUM_GAIN_CHANS: " << CENTRAL_AOUT_NUM_GAIN_CHANS << "\n"; + // std::cout << " CENTRAL_cbPKT_SPKCACHELINECNT: " << CENTRAL_cbPKT_SPKCACHELINECNT << "\n"; + // std::cout << " CENTRAL_cbMAXAPPWORKSPACES: " << CENTRAL_cbMAXAPPWORKSPACES << "\n"; + // std::cout << " sizeof(PROCTIME): " << sizeof(PROCTIME) << "\n"; + // std::cout << "\n"; + // + // // Construct names for this instance + // std::string cfg_name = makeName("cbCFGbuffer", instance); + // std::string rec_name = makeName("cbRECbuffer", instance); + // std::string xmt_name = makeName("XmtGlobal", instance); + // std::string xmtl_name = makeName("XmtLocal", instance); + // std::string status_name = makeName("cbSTATUSbuffer", instance); + // std::string spk_name = makeName("cbSPKbuffer", instance); + // std::string signal_name = makeName("cbSIGNALevent", instance); + // + // std::cout << "=== Attempting Central CLIENT mode (instance " << instance << ") ===\n"; + // std::cout << " Config: " << cfg_name << "\n"; + // std::cout << " Receive: " << rec_name << "\n"; + // std::cout << " XmtGlob: " << xmt_name << "\n"; + // std::cout << " XmtLoc: " << xmtl_name << "\n"; + // std::cout << " Status: " << status_name << "\n"; + // std::cout << " Spike: " << spk_name << "\n"; + // std::cout << " Signal: " << signal_name << "\n\n"; + // + // auto result = ShmemSession::create( + // cfg_name, rec_name, xmt_name, xmtl_name, + // status_name, spk_name, signal_name, + // Mode::CLIENT, ShmemLayout::CENTRAL_COMPAT); + // + // if (result.isError()) { + // std::cerr << "FAILED to attach to Central's shared memory: " << result.error() << "\n"; + // std::cerr << "\nIs Central running?\n"; + // return 1; + // } + // + // auto session = std::move(result.value()); + // std::cout << "SUCCESS: Attached to Central's shared memory!\n\n"; + // + // // Read config buffer + // auto* cfg = session.getLegacyConfigBuffer(); + // if (!cfg) { + // std::cerr << "ERROR: getLegacyConfigBuffer() returned null\n"; + // return 1; + // } + // + // std::cout << "=== Config Buffer Contents ===\n"; + // std::cout << " version: " << cfg->version << "\n"; + // std::cout << " sysflags: 0x" << std::hex << cfg->sysflags << std::dec << "\n"; + // + // // Read procinfo for each instrument + // std::cout << "\n=== Processor Info ===\n"; + // for (uint32_t i = 0; i < CENTRAL_cbMAXPROCS; ++i) { + // auto& proc = cfg->procinfo[i]; + // // procinfo version field = (major << 16) | minor + // uint32_t ver = proc.cbpkt_header.type; // Version is stored in a known field + // std::cout << " Proc[" << i << "]:" + // << " time=" << proc.cbpkt_header.time + // << " chid=" << proc.cbpkt_header.chid + // << " type=0x" << std::hex << proc.cbpkt_header.type << std::dec + // << " dlen=" << proc.cbpkt_header.dlen + // << " inst=" << (int)proc.cbpkt_header.instrument + // << "\n"; + // } + // + // // Detect protocol version + // auto proto = session.getCompatProtocolVersion(); + // std::cout << "\n=== Detected Protocol ===\n"; + // std::cout << " Protocol version: "; + // switch (proto) { + // case CBPROTO_PROTOCOL_311: std::cout << "3.11\n"; break; + // case CBPROTO_PROTOCOL_400: std::cout << "4.0\n"; break; + // case CBPROTO_PROTOCOL_410: std::cout << "4.1\n"; break; + // case CBPROTO_PROTOCOL_CURRENT: std::cout << "CURRENT (4.2+)\n"; break; + // default: std::cout << "UNKNOWN\n"; break; + // } + // + // // Read status buffer + // std::cout << "\n=== PC Status ===\n"; + // auto num_total = session.getNumTotalChans(); + // if (num_total.isOk()) { + // std::cout << " Total channels: " << num_total.value() << "\n"; + // } + // for (uint32_t i = 0; i < CENTRAL_cbMAXPROCS; ++i) { + // auto nsp = session.getNspStatus(cbproto::InstrumentId::fromIndex(i)); + // if (nsp.isOk()) { + // const char* status_str = "?"; + // switch (nsp.value()) { + // case NSPStatus::NSP_INIT: status_str = "INIT"; break; + // case NSPStatus::NSP_NOIPADDR: status_str = "NOIPADDR"; break; + // case NSPStatus::NSP_NOREPLY: status_str = "NOREPLY"; break; + // case NSPStatus::NSP_FOUND: status_str = "FOUND"; break; + // case NSPStatus::NSP_INVALID: status_str = "INVALID"; break; + // } + // std::cout << " NSP[" << i << "] status: " << status_str << "\n"; + // } + // } + // auto gemini = session.isGeminiSystem(); + // if (gemini.isOk()) { + // std::cout << " Gemini system: " << (gemini.value() ? "YES" : "NO") << "\n"; + // } + // + // // Read some channel info + // std::cout << "\n=== Sample Channel Info ===\n"; + // for (uint32_t ch = 0; ch < 5 && ch < CENTRAL_cbMAXCHANS; ++ch) { + // auto ci = session.getChanInfo(ch); + // if (ci.isOk()) { + // auto& chan = ci.value(); + // std::cout << " Chan[" << std::setw(3) << ch << "]: " + // << " chid=" << chan.cbpkt_header.chid + // << " type=0x" << std::hex << chan.cbpkt_header.type << std::dec + // << " dlen=" << chan.cbpkt_header.dlen + // << " smpgroup=" << chan.smpgroup + // << " label=\"" << chan.label << "\"" + // << "\n"; + // } + // } + // + // // Now monitor receive buffer for packets + // std::cout << "\n=== Monitoring Receive Buffer ===\n"; + // std::cout << "Waiting for packets (Ctrl+C to stop)...\n\n"; + // + // // Set instrument filter for Hub1 (index 0 in GEMSTART=2 mapping) + // session.setInstrumentFilter(0); + // + // uint64_t total_packets = 0; + // auto start = std::chrono::steady_clock::now(); + // + // while (g_running) { + // auto wait_result = session.waitForData(500); + // + // cbPKT_GENERIC packets[64]; + // size_t packets_read = 0; + // auto read_result = session.readReceiveBuffer(packets, 64, packets_read); + // + // if (read_result.isOk() && packets_read > 0) { + // total_packets += packets_read; + // + // // Print first packet details periodically + // if (total_packets <= 10 || total_packets % 10000 == 0) { + // auto& pkt = packets[0]; + // std::cout << "[" << total_packets << "] " + // << "time=" << pkt.cbpkt_header.time + // << " chid=" << pkt.cbpkt_header.chid + // << " type=0x" << std::hex << pkt.cbpkt_header.type << std::dec + // << " dlen=" << pkt.cbpkt_header.dlen + // << " inst=" << (int)pkt.cbpkt_header.instrument + // << "\n"; + // } + // } + // + // auto now = std::chrono::steady_clock::now(); + // int elapsed = std::chrono::duration_cast(now - start).count(); + // if (elapsed > 0 && total_packets > 0) { + // std::cout << "\r Packets: " << total_packets + // << " (" << (total_packets / elapsed) << "/sec)" + // << std::flush; + // } + // } + // + // std::cout << "\n\nTotal packets read: " << total_packets << "\n"; + // std::cout << "Done.\n"; + return 0; +} From 76af836689dfc3c7220bf264add5f6f1736c731d Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Mon, 11 May 2026 12:36:52 -0600 Subject: [PATCH 03/62] Fix factory functions for CentralAdapter so they compile on Windows The translation units containing the factory functions now link with the correct Windows libraries. --- src/cbshm/CMakeLists.txt | 3 +- src/cbshm/include/cbshm/central_adapter.h | 5 ---- src/cbshm/src/central_adapter_factory.cpp | 34 +++++++++++++++++------ 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/cbshm/CMakeLists.txt b/src/cbshm/CMakeLists.txt index b5456a7e..300821a0 100644 --- a/src/cbshm/CMakeLists.txt +++ b/src/cbshm/CMakeLists.txt @@ -9,6 +9,7 @@ project(cbshm # Library sources set(CBSHMEM_SOURCES src/shmem_session.cpp + src/central_adapter_factory.cpp ) # Build as STATIC library @@ -34,7 +35,7 @@ target_compile_features(cbshm PUBLIC cxx_std_17) if(WIN32) # Windows shared memory APIs (kernel32 is linked by default) target_compile_definitions(cbshm PRIVATE _WIN32_WINNT=0x0601) - + target_link_libraries(cbshm PRIVATE Version) elseif(APPLE) # macOS shared memory APIs target_link_libraries(cbshm PRIVATE pthread) diff --git a/src/cbshm/include/cbshm/central_adapter.h b/src/cbshm/include/cbshm/central_adapter.h index 9ee1cc3c..34495584 100644 --- a/src/cbshm/include/cbshm/central_adapter.h +++ b/src/cbshm/include/cbshm/central_adapter.h @@ -13,15 +13,12 @@ #include #include #include -#include #ifndef CBSHM_CENTRAL_ADAPTER_H #define CBSHM_CENTRAL_ADAPTER_H namespace cbshm { -#ifdef _WIN32 - /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Base-class adapter for Central-compatible shared memory access /// @@ -47,8 +44,6 @@ cbutil::Result makeCentralAdapter(); /// cbutil::Result makeCentralAdapter(cbproto_protocol_version_t protocol_version); -#endif - } // namespace cbshm #endif // CBSHM_CENTRAL_ADAPTER_H diff --git a/src/cbshm/src/central_adapter_factory.cpp b/src/cbshm/src/central_adapter_factory.cpp index d650665e..74a407d0 100644 --- a/src/cbshm/src/central_adapter_factory.cpp +++ b/src/cbshm/src/central_adapter_factory.cpp @@ -7,17 +7,23 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// +// Platform headers MUST be included first (before cbproto) #include "platform_first.h" +#ifdef _WIN32 + #include +#endif + #include #include #include -namespace cbshm { +#include // TODO: REMOVE THIS -#ifdef _WIN32 +namespace cbshm { static Result getCentralAppVersion() { +#ifdef _WIN32 // As of 2026-05-07, the 'version' field in Central's shared memory // configuration buffer is set to a magic number, 96, instead of a meaningful // value that indicates the application or protocol version. The only other @@ -62,9 +68,13 @@ static Result getCentralAppVersion() { std::string app_version = std::string(value, value_size - 1); // strip trailing null byte return Result::ok(app_version); +#else + return Result::error("The CentralAdapter is only usable on Windows"); +#endif } Result makeCentralAdapter() { +#ifdef _WIN32 Result app_version_result = getCentralAppVersion(); if (! app_version_result.isOk()) { return Result::error("Failed to extract the application version from Central"); @@ -74,7 +84,7 @@ Result makeCentralAdapter() { // Get the indicies of both dots in the version string size_t ldot_idx = app_version.find("."); size_t rdot_idx = app_version.rfind("."); - if (ldot_idx == std::string::npos or rdot_idx == std::string::npos) { + if (ldot_idx == std::string::npos || rdot_idx == std::string::npos) { return Result::error("Failed to find both dots separating the major, minor, and patch version values in '" + app_version + "'"); } @@ -82,9 +92,11 @@ Result makeCentralAdapter() { char* major_version_begin = app_version.data(); char* major_version_end = app_version.data() + ldot_idx; uint32_t major_version; - std::from_chars_result result{ .ptr=nullptr, .ec=std::errc(0) }; + std::from_chars_result result{}; + result.ptr = nullptr; + result.ec = std::errc(0); result = std::from_chars(major_version_begin, major_version_end, major_version); - if (result.ec == std::errc(0) && result.ptr == major_version_end) { + if (result.ec != std::errc(0) || result.ptr != major_version_end) { return Result::error("Failed to isolate the major version value from '" + app_version + "'"); } @@ -95,7 +107,7 @@ Result makeCentralAdapter() { result.ptr = nullptr; result.ec = std::errc(0); result = std::from_chars(minor_version_begin, minor_version_end, minor_version); - if (result.ec == std::errc(0) && result.ptr == minor_version_end) { + if (result.ec != std::errc(0) || result.ptr != minor_version_end) { return Result::error("Failed to isolate the minor version value from '" + app_version + "'"); } @@ -127,9 +139,14 @@ Result makeCentralAdapter() { } return makeCentralAdapter(protocol_version); +#else + return Result::error("The CentralAdapter is only usable on Windows"); +#endif } Result makeCentralAdapter(cbproto_protocol_version_t protocol_version) { +#ifdef _WIN32 + std::cout << protocol_version << std::endl; switch (protocol_version) { // // TODO: Implement legacy layouts // case CBPROTO_PROTOCOL_CURRENT: @@ -145,9 +162,10 @@ Result makeCentralAdapter(cbproto_protocol_version_t protocol_ve default: return Result::error("Unrecognized protocol version, enum value: " + std::to_string(protocol_version)); } -} - +#else + return Result::error("The CentralAdapter is only usable on Windows"); #endif +} } // namespace cbshm From 7cd4a5a07c73da0288debdccecdf85080a3edaf4 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Wed, 13 May 2026 16:45:57 -0600 Subject: [PATCH 04/62] Merge the CentralAdapter with ShmemSession::Impl Remove the example for the CentralAdapter now that it's an implementation detail of ShmemSession. Add new compatibility version detection logic to ShmemSession::Impl. Split detectCompatProtocol into two separate methods: one for inspecting Central's binary for version information and another for inspecting the shared memory as the original function did. Compatability version detection for a STANDALONE + CENTRAL_COMPAT CereLink instance is (theoretically) supported, but this logic is dead because this configuration is never created by SdkSession::create. --- examples/CMakeLists.txt | 1 - examples/CentralAdapter/central_adapter.cpp | 233 -------------------- src/cbshm/CMakeLists.txt | 3 +- src/cbshm/include/cbshm/central_adapter.h | 49 ---- src/cbshm/src/central_adapter_factory.cpp | 171 -------------- src/cbshm/src/platform_first.h | 2 + src/cbshm/src/shmem_session.cpp | 202 +++++++++++++++-- 7 files changed, 191 insertions(+), 470 deletions(-) delete mode 100644 examples/CentralAdapter/central_adapter.cpp delete mode 100644 src/cbshm/include/cbshm/central_adapter.h delete mode 100644 src/cbshm/src/central_adapter_factory.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e311fe3b..48df406e 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -6,7 +6,6 @@ set(CBSDK_EXAMPLES "gemini_example:GeminiExample/gemini_example.cpp" "simple_device:SimpleDevice/simple_device.cpp" "central_client:CentralClient/central_client.cpp" - "central_adapter:CentralAdapter/central_adapter.cpp" "ccf_test:CCFTest/ccf_test.cpp" "recording_test:RecordingTest/recording_test.cpp" ) diff --git a/examples/CentralAdapter/central_adapter.cpp b/examples/CentralAdapter/central_adapter.cpp deleted file mode 100644 index 90261d4b..00000000 --- a/examples/CentralAdapter/central_adapter.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file central_adapter.cpp -/// @brief Diagnostic tool for testing CereLink and Central compatibility -/// -/// Instantiates a CentralAdapter in order to attach to Central's shared memory. -/// -/// Usage: -/// central_adapter [instance] -/// central_adapter # Default: instance 0 -/// central_adapter 1 # Instance 1 (for multi-instance setups) -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace cbshm; - -std::atomic g_running{true}; - -void signalHandler(int) { g_running = false; } - -static std::string makeName(const char* base, int instance) { - if (instance == 0) return base; - return std::string(base) + std::to_string(instance); -} - -int main(int argc, char* argv[]) { - int instance = 0; - if (argc >= 2) instance = std::atoi(argv[1]); - - signal(SIGINT, signalHandler); - signal(SIGTERM, signalHandler); - - std::cout << "==============================================\n"; - std::cout << " CereLink CentralAdapter Diagnostic\n"; - std::cout << "==============================================\n\n"; - - auto centralAdapter = cbshm::makeCentralAdapter(); - if (centralAdapter.isError()) { - std::cout << centralAdapter.error() << std::endl; - } - - // // Print struct sizes for comparison with Central - // std::cout << "=== Struct Size Verification ===\n"; - // std::cout << " sizeof(CentralLegacyCFGBUFF): " << sizeof(CentralLegacyCFGBUFF) << "\n"; - // std::cout << " sizeof(CentralReceiveBuffer): " << sizeof(CentralReceiveBuffer) << "\n"; - // std::cout << " sizeof(CentralTransmitBuffer): " << sizeof(CentralTransmitBuffer) << "\n"; - // std::cout << " sizeof(CentralTransmitBufferLocal): " << sizeof(CentralTransmitBufferLocal) << "\n"; - // std::cout << " sizeof(CentralPCStatus): " << sizeof(CentralPCStatus) << "\n"; - // std::cout << " sizeof(CentralSpikeBuffer): " << sizeof(CentralSpikeBuffer) << "\n"; - // std::cout << " sizeof(CentralSpikeCache): " << sizeof(CentralSpikeCache) << "\n"; - // std::cout << " sizeof(CentralAppWorkspace): " << sizeof(CentralAppWorkspace) << "\n"; - // std::cout << "\n"; - // - // // Print key constants - // std::cout << "=== Key Constants ===\n"; - // std::cout << " CENTRAL_cbMAXPROCS: " << CENTRAL_cbMAXPROCS << "\n"; - // std::cout << " CENTRAL_cbNUM_FE_CHANS: " << CENTRAL_cbNUM_FE_CHANS << "\n"; - // std::cout << " CENTRAL_cbMAXCHANS: " << CENTRAL_cbMAXCHANS << "\n"; - // std::cout << " CENTRAL_cbMAXBANKS: " << CENTRAL_cbMAXBANKS << "\n"; - // std::cout << " CENTRAL_cbMAXNTRODES: " << CENTRAL_cbMAXNTRODES << "\n"; - // std::cout << " CENTRAL_AOUT_NUM_GAIN_CHANS: " << CENTRAL_AOUT_NUM_GAIN_CHANS << "\n"; - // std::cout << " CENTRAL_cbPKT_SPKCACHELINECNT: " << CENTRAL_cbPKT_SPKCACHELINECNT << "\n"; - // std::cout << " CENTRAL_cbMAXAPPWORKSPACES: " << CENTRAL_cbMAXAPPWORKSPACES << "\n"; - // std::cout << " sizeof(PROCTIME): " << sizeof(PROCTIME) << "\n"; - // std::cout << "\n"; - // - // // Construct names for this instance - // std::string cfg_name = makeName("cbCFGbuffer", instance); - // std::string rec_name = makeName("cbRECbuffer", instance); - // std::string xmt_name = makeName("XmtGlobal", instance); - // std::string xmtl_name = makeName("XmtLocal", instance); - // std::string status_name = makeName("cbSTATUSbuffer", instance); - // std::string spk_name = makeName("cbSPKbuffer", instance); - // std::string signal_name = makeName("cbSIGNALevent", instance); - // - // std::cout << "=== Attempting Central CLIENT mode (instance " << instance << ") ===\n"; - // std::cout << " Config: " << cfg_name << "\n"; - // std::cout << " Receive: " << rec_name << "\n"; - // std::cout << " XmtGlob: " << xmt_name << "\n"; - // std::cout << " XmtLoc: " << xmtl_name << "\n"; - // std::cout << " Status: " << status_name << "\n"; - // std::cout << " Spike: " << spk_name << "\n"; - // std::cout << " Signal: " << signal_name << "\n\n"; - // - // auto result = ShmemSession::create( - // cfg_name, rec_name, xmt_name, xmtl_name, - // status_name, spk_name, signal_name, - // Mode::CLIENT, ShmemLayout::CENTRAL_COMPAT); - // - // if (result.isError()) { - // std::cerr << "FAILED to attach to Central's shared memory: " << result.error() << "\n"; - // std::cerr << "\nIs Central running?\n"; - // return 1; - // } - // - // auto session = std::move(result.value()); - // std::cout << "SUCCESS: Attached to Central's shared memory!\n\n"; - // - // // Read config buffer - // auto* cfg = session.getLegacyConfigBuffer(); - // if (!cfg) { - // std::cerr << "ERROR: getLegacyConfigBuffer() returned null\n"; - // return 1; - // } - // - // std::cout << "=== Config Buffer Contents ===\n"; - // std::cout << " version: " << cfg->version << "\n"; - // std::cout << " sysflags: 0x" << std::hex << cfg->sysflags << std::dec << "\n"; - // - // // Read procinfo for each instrument - // std::cout << "\n=== Processor Info ===\n"; - // for (uint32_t i = 0; i < CENTRAL_cbMAXPROCS; ++i) { - // auto& proc = cfg->procinfo[i]; - // // procinfo version field = (major << 16) | minor - // uint32_t ver = proc.cbpkt_header.type; // Version is stored in a known field - // std::cout << " Proc[" << i << "]:" - // << " time=" << proc.cbpkt_header.time - // << " chid=" << proc.cbpkt_header.chid - // << " type=0x" << std::hex << proc.cbpkt_header.type << std::dec - // << " dlen=" << proc.cbpkt_header.dlen - // << " inst=" << (int)proc.cbpkt_header.instrument - // << "\n"; - // } - // - // // Detect protocol version - // auto proto = session.getCompatProtocolVersion(); - // std::cout << "\n=== Detected Protocol ===\n"; - // std::cout << " Protocol version: "; - // switch (proto) { - // case CBPROTO_PROTOCOL_311: std::cout << "3.11\n"; break; - // case CBPROTO_PROTOCOL_400: std::cout << "4.0\n"; break; - // case CBPROTO_PROTOCOL_410: std::cout << "4.1\n"; break; - // case CBPROTO_PROTOCOL_CURRENT: std::cout << "CURRENT (4.2+)\n"; break; - // default: std::cout << "UNKNOWN\n"; break; - // } - // - // // Read status buffer - // std::cout << "\n=== PC Status ===\n"; - // auto num_total = session.getNumTotalChans(); - // if (num_total.isOk()) { - // std::cout << " Total channels: " << num_total.value() << "\n"; - // } - // for (uint32_t i = 0; i < CENTRAL_cbMAXPROCS; ++i) { - // auto nsp = session.getNspStatus(cbproto::InstrumentId::fromIndex(i)); - // if (nsp.isOk()) { - // const char* status_str = "?"; - // switch (nsp.value()) { - // case NSPStatus::NSP_INIT: status_str = "INIT"; break; - // case NSPStatus::NSP_NOIPADDR: status_str = "NOIPADDR"; break; - // case NSPStatus::NSP_NOREPLY: status_str = "NOREPLY"; break; - // case NSPStatus::NSP_FOUND: status_str = "FOUND"; break; - // case NSPStatus::NSP_INVALID: status_str = "INVALID"; break; - // } - // std::cout << " NSP[" << i << "] status: " << status_str << "\n"; - // } - // } - // auto gemini = session.isGeminiSystem(); - // if (gemini.isOk()) { - // std::cout << " Gemini system: " << (gemini.value() ? "YES" : "NO") << "\n"; - // } - // - // // Read some channel info - // std::cout << "\n=== Sample Channel Info ===\n"; - // for (uint32_t ch = 0; ch < 5 && ch < CENTRAL_cbMAXCHANS; ++ch) { - // auto ci = session.getChanInfo(ch); - // if (ci.isOk()) { - // auto& chan = ci.value(); - // std::cout << " Chan[" << std::setw(3) << ch << "]: " - // << " chid=" << chan.cbpkt_header.chid - // << " type=0x" << std::hex << chan.cbpkt_header.type << std::dec - // << " dlen=" << chan.cbpkt_header.dlen - // << " smpgroup=" << chan.smpgroup - // << " label=\"" << chan.label << "\"" - // << "\n"; - // } - // } - // - // // Now monitor receive buffer for packets - // std::cout << "\n=== Monitoring Receive Buffer ===\n"; - // std::cout << "Waiting for packets (Ctrl+C to stop)...\n\n"; - // - // // Set instrument filter for Hub1 (index 0 in GEMSTART=2 mapping) - // session.setInstrumentFilter(0); - // - // uint64_t total_packets = 0; - // auto start = std::chrono::steady_clock::now(); - // - // while (g_running) { - // auto wait_result = session.waitForData(500); - // - // cbPKT_GENERIC packets[64]; - // size_t packets_read = 0; - // auto read_result = session.readReceiveBuffer(packets, 64, packets_read); - // - // if (read_result.isOk() && packets_read > 0) { - // total_packets += packets_read; - // - // // Print first packet details periodically - // if (total_packets <= 10 || total_packets % 10000 == 0) { - // auto& pkt = packets[0]; - // std::cout << "[" << total_packets << "] " - // << "time=" << pkt.cbpkt_header.time - // << " chid=" << pkt.cbpkt_header.chid - // << " type=0x" << std::hex << pkt.cbpkt_header.type << std::dec - // << " dlen=" << pkt.cbpkt_header.dlen - // << " inst=" << (int)pkt.cbpkt_header.instrument - // << "\n"; - // } - // } - // - // auto now = std::chrono::steady_clock::now(); - // int elapsed = std::chrono::duration_cast(now - start).count(); - // if (elapsed > 0 && total_packets > 0) { - // std::cout << "\r Packets: " << total_packets - // << " (" << (total_packets / elapsed) << "/sec)" - // << std::flush; - // } - // } - // - // std::cout << "\n\nTotal packets read: " << total_packets << "\n"; - // std::cout << "Done.\n"; - return 0; -} diff --git a/src/cbshm/CMakeLists.txt b/src/cbshm/CMakeLists.txt index 300821a0..d053e369 100644 --- a/src/cbshm/CMakeLists.txt +++ b/src/cbshm/CMakeLists.txt @@ -9,7 +9,6 @@ project(cbshm # Library sources set(CBSHMEM_SOURCES src/shmem_session.cpp - src/central_adapter_factory.cpp ) # Build as STATIC library @@ -35,7 +34,7 @@ target_compile_features(cbshm PUBLIC cxx_std_17) if(WIN32) # Windows shared memory APIs (kernel32 is linked by default) target_compile_definitions(cbshm PRIVATE _WIN32_WINNT=0x0601) - target_link_libraries(cbshm PRIVATE Version) + target_link_libraries(cbshm PRIVATE Kernel32 Version) elseif(APPLE) # macOS shared memory APIs target_link_libraries(cbshm PRIVATE pthread) diff --git a/src/cbshm/include/cbshm/central_adapter.h b/src/cbshm/include/cbshm/central_adapter.h deleted file mode 100644 index 34495584..00000000 --- a/src/cbshm/include/cbshm/central_adapter.h +++ /dev/null @@ -1,49 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file central_adapter.h -/// @author Caden Shmookler -/// @date 2026-05-05 -/// -/// @brief The base class of Central-compatible shared memory adapters -/// -/// This module provides the interface (base class) of adapters that attach to -/// the shared memory of specific supported versions of Central. -/// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - -#ifndef CBSHM_CENTRAL_ADAPTER_H -#define CBSHM_CENTRAL_ADAPTER_H - -namespace cbshm { - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Base-class adapter for Central-compatible shared memory access -/// -/// This module provides the interface for adapters that attach to the shared -/// memory of specific supported versions of Central. -/// -class CentralAdapter { -public: - virtual ~CentralAdapter() = default; - - // TODO: Declare required methods -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Instantiate a shared memory adapter for Central that corresponds to -/// Central's protocol version. -/// -cbutil::Result makeCentralAdapter(); - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Instantiate a shared memory adapter for Central that corresponds to -/// a specific protocol version. -/// -cbutil::Result makeCentralAdapter(cbproto_protocol_version_t protocol_version); - -} // namespace cbshm - -#endif // CBSHM_CENTRAL_ADAPTER_H diff --git a/src/cbshm/src/central_adapter_factory.cpp b/src/cbshm/src/central_adapter_factory.cpp deleted file mode 100644 index 74a407d0..00000000 --- a/src/cbshm/src/central_adapter_factory.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file central_adapter_factory.cpp -/// @author Caden Shmookler -/// @date 2026-05-05 -/// -/// @brief Factory functions for the base class of Central-compatible shared memory adapters -/// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -// Platform headers MUST be included first (before cbproto) -#include "platform_first.h" - -#ifdef _WIN32 - #include -#endif - -#include -#include -#include - -#include // TODO: REMOVE THIS - -namespace cbshm { - -static Result getCentralAppVersion() { -#ifdef _WIN32 - // As of 2026-05-07, the 'version' field in Central's shared memory - // configuration buffer is set to a magic number, 96, instead of a meaningful - // value that indicates the application or protocol version. The only other - // field in Central's shared memory with version information is - // procinfo[].version, but it's byte offset changes between protocol versions - // so it is unusable. This function infers Central's protocol version by - // inspecting VersionInfo.ProductVersion in Central.exe and converting from - // application version to protocol version. - - // Get Central's application version by inspecting the properties of the Central.exe binary - - std::string central_path = "C:\\Program Files\\Blackrock Microsystems\\Cerebus Central Suite\\Central.exe"; - - DWORD handle = 0; - DWORD block_size = GetFileVersionInfoSizeA(central_path.c_str(), &handle); - if (block_size == 0) { - return Result::error("Failed to get the length of the resource block containing Central's application version"); - } - - std::vector block(block_size); - if (!GetFileVersionInfoA(central_path.c_str(), handle, block_size, block.data())) { - return Result::error("Failed to extract the version resource block from Central"); - } - - struct LangCodePage { - WORD lang; - WORD codepage; - } *translate = nullptr; - UINT translate_size = 0; - if (!VerQueryValueA(block.data(), "\\VarFileInfo\\Translation", (LPVOID*)&translate, &translate_size) || translate_size == 0) { - return Result::error("Failed to lookup the available version translations for Central"); - } - - char sub_block[64]; - sprintf_s(sub_block, sizeof(sub_block), "\\StringFileInfo\\%04x%04x\\ProductVersion", translate[0].lang, translate[0].codepage); - - char* value = nullptr; - UINT value_size = 0; - if (!VerQueryValueA(block.data(), sub_block, (LPVOID*)&value, &value_size) || value_size == 0) { - return Result::error("Failed to extract Central's version from the resource block"); - } - std::string app_version = std::string(value, value_size - 1); // strip trailing null byte - - return Result::ok(app_version); -#else - return Result::error("The CentralAdapter is only usable on Windows"); -#endif -} - -Result makeCentralAdapter() { -#ifdef _WIN32 - Result app_version_result = getCentralAppVersion(); - if (! app_version_result.isOk()) { - return Result::error("Failed to extract the application version from Central"); - } - std::string& app_version = app_version_result.value(); - - // Get the indicies of both dots in the version string - size_t ldot_idx = app_version.find("."); - size_t rdot_idx = app_version.rfind("."); - if (ldot_idx == std::string::npos || rdot_idx == std::string::npos) { - return Result::error("Failed to find both dots separating the major, minor, and patch version values in '" + app_version + "'"); - } - - // Extract the major version number - char* major_version_begin = app_version.data(); - char* major_version_end = app_version.data() + ldot_idx; - uint32_t major_version; - std::from_chars_result result{}; - result.ptr = nullptr; - result.ec = std::errc(0); - result = std::from_chars(major_version_begin, major_version_end, major_version); - if (result.ec != std::errc(0) || result.ptr != major_version_end) { - return Result::error("Failed to isolate the major version value from '" + app_version + "'"); - } - - // Extract the minor version number - char* minor_version_begin = app_version.data() + ldot_idx + 1; - char* minor_version_end = app_version.data() + rdot_idx; - uint32_t minor_version; - result.ptr = nullptr; - result.ec = std::errc(0); - result = std::from_chars(minor_version_begin, minor_version_end, minor_version); - if (result.ec != std::errc(0) || result.ptr != minor_version_end) { - return Result::error("Failed to isolate the minor version value from '" + app_version + "'"); - } - - // Convert application version to protocol version - cbproto_protocol_version_t protocol_version = CBPROTO_PROTOCOL_UNKNOWN; - switch(major_version) { - case 7: - switch (minor_version) { - case 8: - /* fallthrough */ - case 7: - protocol_version = CBPROTO_PROTOCOL_CURRENT; - break; - case 6: - protocol_version = CBPROTO_PROTOCOL_410; - break; - case 5: - protocol_version = CBPROTO_PROTOCOL_400; - break; - case 0: - protocol_version = CBPROTO_PROTOCOL_311; - break; - default: - return Result::error("Unrecognized minor version number for version '" + app_version + "'"); - } - break; - default: - return Result::error("Unrecognized major version number for version '" + app_version + "'"); - } - - return makeCentralAdapter(protocol_version); -#else - return Result::error("The CentralAdapter is only usable on Windows"); -#endif -} - -Result makeCentralAdapter(cbproto_protocol_version_t protocol_version) { -#ifdef _WIN32 - std::cout << protocol_version << std::endl; - switch (protocol_version) { - // // TODO: Implement legacy layouts - // case CBPROTO_PROTOCOL_CURRENT: - // return CentralAdapterV420(); - // case CBPROTO_PROTOCOL_410: - // return CentralAdapterV410(); - // case CBPROTO_PROTOCOL_400: - // return CentralAdapterV400(); - // case CBPROTO_PROTOCOL_311: - // return CentralAdapterV311(); - case CBPROTO_PROTOCOL_UNKNOWN: - /* fallthrough */ - default: - return Result::error("Unrecognized protocol version, enum value: " + std::to_string(protocol_version)); - } -#else - return Result::error("The CentralAdapter is only usable on Windows"); -#endif -} - -} // namespace cbshm - diff --git a/src/cbshm/src/platform_first.h b/src/cbshm/src/platform_first.h index 50b64b0d..3046390e 100644 --- a/src/cbshm/src/platform_first.h +++ b/src/cbshm/src/platform_first.h @@ -26,6 +26,8 @@ #ifndef NOMINMAX #define NOMINMAX #endif + #undef UNICODE + #undef _UNICODE #include #endif diff --git a/src/cbshm/src/shmem_session.cpp b/src/cbshm/src/shmem_session.cpp index ea26eb5d..59bcb232 100644 --- a/src/cbshm/src/shmem_session.cpp +++ b/src/cbshm/src/shmem_session.cpp @@ -13,6 +13,15 @@ // Platform headers MUST be included first (before cbproto) #include "platform_first.h" +#ifdef _WIN32 + #include + #include + + #include + #include +#endif + +#include // TODO: REMOVE THIS!!! #ifndef _WIN32 #include @@ -371,7 +380,7 @@ struct ShmemSession::Impl { uint32_t pkt_size_words = cbPKT_HEADER_32SIZE + pkt.cbpkt_header.dlen; if (pkt_size_words > rec_buffer_len) { - return Result::error("Packet too large for receive buffer"); + return Result::error("Packet too large for receive buffwither"); } uint32_t head = recHeadindex(); @@ -605,8 +614,27 @@ struct ShmemSession::Impl { rec_tailwrap = shm_load_relaxed_u32(&recHeadwrap()); } - // Detect protocol version for CENTRAL_COMPAT mode - detectCompatProtocol(); + if (mode == Mode::CLIENT && layout == ShmemLayout::CENTRAL_COMPAT) { + // Detect protocol version for CLIENT + CENTRAL_COMPAT mode + auto compat_central = detectCompatProtocolCentral(); // Try Central first + if (compat_central.isError()) { + // It's theoretically possible for CereLink to run in + // STANDALONE + CENTRAL_COMPAT, so it must be possible to + // connect as a client as well. + auto compat_cerelink = detectCompatProtocolCereLink(); + if (compat_cerelink.isError()) { + return Result::error("Failed to detect the protocol version for compatibility with Central's shared memory layout:\n-- Central version detection returned: " + compat_central.error() + "\n-- CereLink version detection returned: " + compat_cerelink.error()); + } else { + compat_protocol = compat_cerelink.value(); + } + } else { + compat_protocol = compat_central.value(); + } + } else { + // The compatibility protocol is ignored for NATIVE or CENTRAL + // layouts and is always current for STANDALONE mode. + compat_protocol = CBPROTO_PROTOCOL_CURRENT; + } return Result::ok(); } @@ -780,17 +808,162 @@ struct ShmemSession::Impl { } } - /// @brief Detect protocol version from config buffer (CENTRAL_COMPAT only) - void detectCompatProtocol() { - if (layout != ShmemLayout::CENTRAL_COMPAT) { - compat_protocol = CBPROTO_PROTOCOL_CURRENT; - return; + /// @brief Detect the protocol version from Central's binary (CENTRAL_COMPAT only). + Result detectCompatProtocolCentral() { +#ifdef _WIN32 + // The 'version' field in Central's shared memory configuration buffer + // is set to a magic number, 96, instead of a meaningful value that + // indicates the application or protocol version. The only other field + // in Central's shared memory with version information is + // procinfo[].version, but it's byte offset changes between protocol versions + // so it is unusable. This function infers Central's protocol version by + // inspecting VersionInfo.ProductVersion in Central.exe and converting from + // application version to protocol version. + + // Get the path to Central's executable file from the running processes list. + + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (snapshot == INVALID_HANDLE_VALUE) { + return Result::error("Failed to get a snapshot of the running processes from the Tool Help library"); + } + + PROCESSENTRY32 process_entry{}; + process_entry.dwSize = sizeof(process_entry); + if (! Process32First(snapshot, &process_entry)) { + return Result::error("Failed to get the first process from the running processes snapshot"); + } + + // Enumerate the running processes and identify Central by it's process name. + DWORD central_pid = 0; + do { + if (std::string(process_entry.szExeFile) == "Central.exe") { + central_pid = process_entry.th32ProcessID; + break; + } + } while(Process32Next(snapshot, &process_entry)); + if (central_pid == 0) { + return Result::error("Failed to find Central among the currently running processes. Is Central running?"); + } + + HANDLE central = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, central_pid); + if (! central) { + return Result::error("Failed to inspect Central's process"); + } + + char central_path[MAX_PATH] = {0}; + DWORD central_path_size = MAX_PATH; + if (! QueryFullProcessImageNameA(central, NULL, central_path, ¢ral_path_size)) { + CloseHandle(central); + return Result::error("Failed to get the path to Central's executable"); + } + CloseHandle(central); + + // Get Central's application version by inspecting the properties of the + // Central.exe binary + + DWORD handle = 0; + DWORD block_size = GetFileVersionInfoSizeA(central_path, &handle); + if (block_size == 0) { + return Result::error("Failed to get the length of the resource block containing Central's application version"); + } + + std::vector block(block_size); + if (!GetFileVersionInfoA(central_path, handle, block_size, block.data())) { + return Result::error("Failed to extract the version resource block from Central"); + } + + struct LangCodePage { + WORD lang; + WORD codepage; + } *translate = nullptr; + UINT translate_size = 0; + if (!VerQueryValueA(block.data(), "\\VarFileInfo\\Translation", (LPVOID*)&translate, &translate_size) || translate_size == 0) { + return Result::error("Failed to lookup the available version translations for Central"); + } + + char sub_block[64]; + sprintf_s(sub_block, sizeof(sub_block), "\\StringFileInfo\\%04x%04x\\ProductVersion", translate[0].lang, translate[0].codepage); + + char* value = nullptr; + UINT value_size = 0; + if (!VerQueryValueA(block.data(), sub_block, (LPVOID*)&value, &value_size) || value_size == 0) { + return Result::error("Failed to extract Central's version from the resource block"); + } + std::string app_version = std::string(value, value_size - 1); // strip trailing null byte + + // Get the indicies of both dots in the version string + size_t ldot_idx = app_version.find("."); + size_t rdot_idx = app_version.rfind("."); + if (ldot_idx == std::string::npos || rdot_idx == std::string::npos) { + return Result::error("Failed to find both dots separating the major, minor, and patch version values in '" + app_version + "'"); + } + + // Extract the major version number + char* major_version_begin = app_version.data(); + char* major_version_end = app_version.data() + ldot_idx; + uint32_t major_version; + std::from_chars_result result{}; + result.ptr = nullptr; + result.ec = std::errc(0); + result = std::from_chars(major_version_begin, major_version_end, major_version); + if (result.ec != std::errc(0) || result.ptr != major_version_end) { + return Result::error("Failed to isolate the major version value from '" + app_version + "'"); + } + + // Extract the minor version number + char* minor_version_begin = app_version.data() + ldot_idx + 1; + char* minor_version_end = app_version.data() + rdot_idx; + uint32_t minor_version; + result.ptr = nullptr; + result.ec = std::errc(0); + result = std::from_chars(minor_version_begin, minor_version_end, minor_version); + if (result.ec != std::errc(0) || result.ptr != minor_version_end) { + return Result::error("Failed to isolate the minor version value from '" + app_version + "'"); + } + + // Convert application version to protocol version + switch(major_version) { + case 7: + switch (minor_version) { + case 8: + /* fallthrough */ + case 7: + return Result::ok(CBPROTO_PROTOCOL_CURRENT); + case 6: + return Result::ok(CBPROTO_PROTOCOL_410); + case 5: + return Result::ok(CBPROTO_PROTOCOL_400); + case 0: + return Result::ok(CBPROTO_PROTOCOL_311); + default: + return Result::error("Unrecognized minor version number in version '" + app_version + "'"); + } + break; + case 6: + /* fallthrough */ + case 5: + /* fallthrough */ + case 4: + /* fallthrough */ + case 3: + /* fallthrough */ + case 2: + /* fallthrough */ + case 1: + return Result::error("Unsupported major version number in version '" + app_version + "'. Please update Central to a newer version"); + default: + return Result::error("Unrecognized major version number in version '" + app_version + "'" ); } +#else + return Result::error("Compatability with Central requires Windows"); +#endif + } + /// @brief Detect the protocol version from CereLink's Central-compatible config buffer (CENTRAL_COMPAT only). + Result detectCompatProtocolCereLink() { auto* cfg = legacyCfg(); if (!cfg) { - compat_protocol = CBPROTO_PROTOCOL_CURRENT; - return; + return Result::error("Failed to get the legacy configuration buffer"); } // procinfo[0].version = MAKELONG(minor, major) = (major << 16) | minor @@ -799,13 +972,14 @@ struct ShmemSession::Impl { uint16_t minor = ver & 0xFFFF; if (major < 4) { - compat_protocol = CBPROTO_PROTOCOL_311; + return Result::ok(CBPROTO_PROTOCOL_311); } else if (major == 4 && minor == 0) { - compat_protocol = CBPROTO_PROTOCOL_400; + return Result::ok(CBPROTO_PROTOCOL_400); } else if (major == 4 && minor == 1) { - compat_protocol = CBPROTO_PROTOCOL_410; + return Result::ok(CBPROTO_PROTOCOL_410); } else { - compat_protocol = CBPROTO_PROTOCOL_CURRENT; + // Higher versions default to the current up-to-date version. + return Result::ok(CBPROTO_PROTOCOL_CURRENT); } } }; From d930fdb8aa699e0dfa58aa46a4529687188688e7 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Wed, 13 May 2026 17:24:12 -0600 Subject: [PATCH 05/62] Remove shared memory version detection when connecting to STANDALONE + CENTRAL_COMPAT CereLink instances This configuration (STANDALONE + CENTRAL_COMPAT) appears to only be theoretical and is never instantiated by SdkSession. --- src/cbshm/src/shmem_session.cpp | 60 +++++++++------------------------ 1 file changed, 16 insertions(+), 44 deletions(-) diff --git a/src/cbshm/src/shmem_session.cpp b/src/cbshm/src/shmem_session.cpp index 59bcb232..3bc02800 100644 --- a/src/cbshm/src/shmem_session.cpp +++ b/src/cbshm/src/shmem_session.cpp @@ -616,20 +616,11 @@ struct ShmemSession::Impl { if (mode == Mode::CLIENT && layout == ShmemLayout::CENTRAL_COMPAT) { // Detect protocol version for CLIENT + CENTRAL_COMPAT mode - auto compat_central = detectCompatProtocolCentral(); // Try Central first - if (compat_central.isError()) { - // It's theoretically possible for CereLink to run in - // STANDALONE + CENTRAL_COMPAT, so it must be possible to - // connect as a client as well. - auto compat_cerelink = detectCompatProtocolCereLink(); - if (compat_cerelink.isError()) { - return Result::error("Failed to detect the protocol version for compatibility with Central's shared memory layout:\n-- Central version detection returned: " + compat_central.error() + "\n-- CereLink version detection returned: " + compat_cerelink.error()); - } else { - compat_protocol = compat_cerelink.value(); - } - } else { - compat_protocol = compat_central.value(); + auto compat_result = detectCompatProtocol(); + if (compat_result.isError()) { + return Result::error("Failed to detect Central's shared memory: " + compat_result.error()); } + compat_protocol = compat_result.value(); } else { // The compatibility protocol is ignored for NATIVE or CENTRAL // layouts and is always current for STANDALONE mode. @@ -809,16 +800,21 @@ struct ShmemSession::Impl { } /// @brief Detect the protocol version from Central's binary (CENTRAL_COMPAT only). - Result detectCompatProtocolCentral() { + Result detectCompatProtocol() { #ifdef _WIN32 // The 'version' field in Central's shared memory configuration buffer // is set to a magic number, 96, instead of a meaningful value that // indicates the application or protocol version. The only other field - // in Central's shared memory with version information is - // procinfo[].version, but it's byte offset changes between protocol versions - // so it is unusable. This function infers Central's protocol version by - // inspecting VersionInfo.ProductVersion in Central.exe and converting from - // application version to protocol version. + // in Central's shared memory with version information is procinfo[].version, + // but it's byte offset changes between protocol versions so it is unusable. + // This function infers Central's protocol version by inspecting + // VersionInfo.ProductVersion in Central.exe and converting from application + // version to protocol version. + // + // This process for inferring the protocol version is indirect and brittle. + // If a future version of Central were to have a different executable name, + // version field name, or version format, then this detection method would + // fail to deduce the protocol version. // Get the path to Central's executable file from the running processes list. @@ -955,33 +951,9 @@ struct ShmemSession::Impl { return Result::error("Unrecognized major version number in version '" + app_version + "'" ); } #else - return Result::error("Compatability with Central requires Windows"); + return Result::error("Compatibility with Central requires Windows"); #endif } - - /// @brief Detect the protocol version from CereLink's Central-compatible config buffer (CENTRAL_COMPAT only). - Result detectCompatProtocolCereLink() { - auto* cfg = legacyCfg(); - if (!cfg) { - return Result::error("Failed to get the legacy configuration buffer"); - } - - // procinfo[0].version = MAKELONG(minor, major) = (major << 16) | minor - uint32_t ver = cfg->procinfo[0].version; - uint16_t major = (ver >> 16) & 0xFFFF; - uint16_t minor = ver & 0xFFFF; - - if (major < 4) { - return Result::ok(CBPROTO_PROTOCOL_311); - } else if (major == 4 && minor == 0) { - return Result::ok(CBPROTO_PROTOCOL_400); - } else if (major == 4 && minor == 1) { - return Result::ok(CBPROTO_PROTOCOL_410); - } else { - // Higher versions default to the current up-to-date version. - return Result::ok(CBPROTO_PROTOCOL_CURRENT); - } - } }; /////////////////////////////////////////////////////////////////////////////////////////////////// From 3bd94bdbe43bbf7e25cde810261bc6ed9d88177b Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Fri, 15 May 2026 16:47:50 -0600 Subject: [PATCH 06/62] Split central_types.h into multiple version-specific types files. Add central types for 4.2, 4.1, and 4.0. Move CentralConfigBuffer into config_buffer.h. Place version-specific constants and structs in namespaces and remove CENTRAL_ prefixes. --- .../include/cbshm/central_types/current.h | 25 ++ src/cbshm/include/cbshm/central_types/v4_0.h | 259 ++++++++++++++++++ src/cbshm/include/cbshm/central_types/v4_1.h | 259 ++++++++++++++++++ .../{central_types.h => central_types/v4_2.h} | 169 +++++------- src/cbshm/include/cbshm/config_buffer.h | 73 ++--- src/cbshm/include/cbshm/native_types.h | 7 +- src/cbshm/include/cbshm/receive_buffer.h | 5 - 7 files changed, 664 insertions(+), 133 deletions(-) create mode 100644 src/cbshm/include/cbshm/central_types/current.h create mode 100644 src/cbshm/include/cbshm/central_types/v4_0.h create mode 100644 src/cbshm/include/cbshm/central_types/v4_1.h rename src/cbshm/include/cbshm/{central_types.h => central_types/v4_2.h} (58%) diff --git a/src/cbshm/include/cbshm/central_types/current.h b/src/cbshm/include/cbshm/central_types/current.h new file mode 100644 index 00000000..d02932ba --- /dev/null +++ b/src/cbshm/include/cbshm/central_types/current.h @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file current.h +/// @author Caden Shmookler +/// @date 2026-05-15 +/// +/// @brief Default version selection for Central-compatible shared memory +/// structure definitions +/// +/// Central-compatible shared memory structure definitions have been moved to +/// version-specific files in central_types/. +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef CBSHM_CENTRAL_TYPES_CURRENT_H +#define CBSHM_CENTRAL_TYPES_CURRENT_H + +#include + +namespace cbshm { + +namespace central = cbshm::central_v4_2; + +} // namespace cbshm + +#endif // CBSHMEM_CENTRAL_TYPES_CURRENT_H diff --git a/src/cbshm/include/cbshm/central_types/v4_0.h b/src/cbshm/include/cbshm/central_types/v4_0.h new file mode 100644 index 00000000..73cf940c --- /dev/null +++ b/src/cbshm/include/cbshm/central_types/v4_0.h @@ -0,0 +1,259 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v4_0.h +/// @author Caden Shmookler +/// @date 2026-05-15 +/// +/// @brief Central-compatible shared memory structure definitions +/// +/// This file defines the shared memory structures using Central's constants to +/// ensure compatibility with Central when it creates shared memory. +/// +/// CRITICAL: These structures MUST match Central's cbhwlib.h exactly! +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef CBSHM_CENTRAL_TYPES_V4_0_H +#define CBSHM_CENTRAL_TYPES_V4_0_H + +#include + +// Include InstrumentId from protocol module +#include + +// Ensure tight packing for shared memory structures +#pragma pack(push, 1) + +namespace cbshm { + +namespace central_v4_0 { + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Central Constants +/// @{ + +// These MUST match Central's constants +constexpr uint32_t cbMAXPROCS = 2; ///< Central supports up to 2 NSPs +constexpr uint32_t cbNUM_FE_CHANS = 512; ///< Central supports 512 FE channels +constexpr uint32_t cbMAXGROUPS = 8; ///< Sample rate groups +constexpr uint32_t cbMAXFILTS = 32; ///< Digital filters +constexpr uint32_t cbMAXVIDEOSOURCE = 1; +constexpr uint32_t cbMAXTRACKOBJ = 20; +constexpr uint32_t cbMAXHOOPS = 4; +constexpr uint32_t cbMAX_AOUT_TRIGGER = 5; + +// Channel counts +constexpr uint32_t cbNUM_ANAIN_CHANS = 16 * cbMAXPROCS; +constexpr uint32_t cbNUM_ANALOG_CHANS = cbNUM_FE_CHANS + cbNUM_ANAIN_CHANS; +constexpr uint32_t cbNUM_ANAOUT_CHANS = 4 * cbMAXPROCS; +constexpr uint32_t cbNUM_AUDOUT_CHANS = 2 * cbMAXPROCS; +constexpr uint32_t cbNUM_ANALOGOUT_CHANS = cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS; +constexpr uint32_t cbNUM_DIGIN_CHANS = 1 * cbMAXPROCS; +constexpr uint32_t cbNUM_SERIAL_CHANS = 1 * cbMAXPROCS; +constexpr uint32_t cbNUM_DIGOUT_CHANS = 4 * cbMAXPROCS; + +// Total channels +constexpr uint32_t cbMAXCHANS = (cbNUM_ANALOG_CHANS + cbNUM_ANALOGOUT_CHANS + + cbNUM_DIGIN_CHANS + cbNUM_SERIAL_CHANS + + cbNUM_DIGOUT_CHANS); + +// Bank definitions +constexpr uint32_t cbCHAN_PER_BANK = 32; +constexpr uint32_t cbNUM_FE_BANKS = cbNUM_FE_CHANS / cbCHAN_PER_BANK; +constexpr uint32_t cbNUM_ANAIN_BANKS = 1; +constexpr uint32_t cbNUM_ANAOUT_BANKS = 1; +constexpr uint32_t cbNUM_AUDOUT_BANKS = 1; +constexpr uint32_t cbNUM_DIGIN_BANKS = 1; +constexpr uint32_t cbNUM_SERIAL_BANKS = 1; +constexpr uint32_t cbNUM_DIGOUT_BANKS = 1; + +constexpr uint32_t cbMAXBANKS = (cbNUM_FE_BANKS + cbNUM_ANAIN_BANKS + + cbNUM_ANAOUT_BANKS + cbNUM_AUDOUT_BANKS + + cbNUM_DIGIN_BANKS + cbNUM_SERIAL_BANKS + + cbNUM_DIGOUT_BANKS); + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Buffer Size Constants (must be defined before structures) +/// @{ + +/// Max UDP packet size (from Central) +constexpr uint32_t cbCER_UDP_SIZE_MAX = 58080; + +/// Transmit buffer sizes (Central-compatible) +constexpr uint32_t cbXMT_GLOBAL_BUFFLEN = ((cbCER_UDP_SIZE_MAX / 4) * 5000 + 2); ///< Room for 5000 packet-sized slots +constexpr uint32_t cbXMT_LOCAL_BUFFLEN = ((cbCER_UDP_SIZE_MAX / 4) * 2000 + 2); ///< Room for 2000 packet-sized slots + +/// N-Trode count +constexpr uint32_t cbMAXNTRODES = cbNUM_ANALOG_CHANS / 2; ///< = 272 + +/// Analog output gain channels (Central's multi-instrument count) +constexpr uint32_t AOUT_NUM_GAIN_CHANS = cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS; ///< = 12 + +/// Spike cache constants +constexpr uint32_t cbPKT_SPKCACHEPKTCNT = 400; ///< Packets per channel cache +constexpr uint32_t cbPKT_SPKCACHELINECNT = cbMAXCHANS; ///< One cache per channel (Central uses cbMAXCHANS, not cbNUM_ANALOG_CHANS) + +/// Receive buffer size +constexpr uint32_t cbRECBUFFLEN = cbNUM_FE_CHANS * 32768 * 4; + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Instrument status flags (bit field) +/// +/// Used to track which instruments are active in shared memory +/// +enum class InstrumentStatus : uint32_t { + INACTIVE = 0x00000000, ///< Instrument slot is not in use + ACTIVE = 0x00000001, ///< Instrument is active and has data +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Central's actual binary layout (CentralLegacyCFGBUFF) +/// +/// This struct matches Central's cbCFGBUFF field order EXACTLY (from cbhwlib.h). +/// It is NOT the same as CereLink's cbConfigBuffer (which reorders fields and adds +/// instrument_status). This struct is used in CENTRAL_COMPAT mode to read Central's +/// shared memory as a CLIENT. +/// +/// Key differences from CereLink's cbConfigBuffer: +/// - optiontable/colortable: 3rd/4th fields here (after sysflags), last fields in CereLink +/// - instrument_status: absent here (Central has no such concept) +/// - isLnc: after isWaveform here, before chaninfo in CereLink +/// - hwndCentral: omitted (at end, variable size, not needed) +/// +struct CentralLegacyCFGBUFF { + uint32_t version; + uint32_t sysflags; + cbOPTIONTABLE optiontable; + cbCOLORTABLE colortable; + cbPKT_SYSINFO sysinfo; + cbPKT_PROCINFO procinfo[cbMAXPROCS]; + cbPKT_BANKINFO bankinfo[cbMAXPROCS][cbMAXBANKS]; + cbPKT_GROUPINFO groupinfo[cbMAXPROCS][cbMAXGROUPS]; + cbPKT_FILTINFO filtinfo[cbMAXPROCS][cbMAXFILTS]; + cbPKT_ADAPTFILTINFO adaptinfo[cbMAXPROCS]; + cbPKT_REFELECFILTINFO refelecinfo[cbMAXPROCS]; + cbPKT_CHANINFO chaninfo[cbMAXCHANS]; + cbSPIKE_SORTING isSortingOptions; + cbPKT_NTRODEINFO isNTrodeInfo[cbMAXNTRODES]; + cbPKT_AOUT_WAVEFORM isWaveform[AOUT_NUM_GAIN_CHANS][cbMAX_AOUT_TRIGGER]; + cbPKT_LNC isLnc[cbMAXPROCS]; + cbPKT_NPLAY isNPlay; + cbVIDEOSOURCE isVideoSource[cbMAXVIDEOSOURCE]; + cbTRACKOBJ isTrackObj[cbMAXTRACKOBJ]; + cbPKT_FILECFG fileinfo; + // hwndCentral omitted (at end, variable size, not needed by CereLink) +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Transmit buffer for outgoing packets (Global - sent to device) +/// +/// Ring buffer for packets waiting to be transmitted to device via UDP. +/// Buffer stores raw packet data as uint32_t words (Central's format). +/// +/// This is stored in a separate shared memory segment (not embedded in config buffer) +/// to match Central's architecture. +/// +struct CentralTransmitBuffer { + uint32_t transmitted; ///< How many packets have been sent + uint32_t headindex; ///< First empty position (write index) + uint32_t tailindex; ///< One past last emptied position (read index) + uint32_t last_valid_index; ///< Greatest valid starting index + uint32_t bufferlen; ///< Number of indices in buffer + uint32_t buffer[cbXMT_GLOBAL_BUFFLEN]; ///< Ring buffer for packet data +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Local transmit buffer (IPC-only packets) +/// +/// Smaller than Global buffer, used for cbSendLoopbackPacket() - packets meant only for +/// local processes, not sent to device. +/// +struct CentralTransmitBufferLocal { + uint32_t transmitted; ///< How many packets have been sent + uint32_t headindex; ///< First empty position (write index) + uint32_t tailindex; ///< One past last emptied position (read index) + uint32_t last_valid_index; ///< Greatest valid starting index + uint32_t bufferlen; ///< Number of indices in buffer + uint32_t buffer[cbXMT_LOCAL_BUFFLEN]; ///< Ring buffer for packet data +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Spike cache buffer +/// +/// Caches recent spike packets for each channel to allow quick access without +/// scanning the entire receive buffer. +/// +struct CentralSpikeCache { + uint32_t chid; ///< Channel ID + uint32_t pktcnt; ///< Number of packets that can be saved + uint32_t pktsize; ///< Size of individual packet + uint32_t head; ///< Where to place next packet (circular) + uint32_t valid; ///< How many packets since last config + cbPKT_SPK spkpkt[cbPKT_SPKCACHEPKTCNT]; ///< Circular buffer of cached spikes +}; + +struct CentralSpikeBuffer { + uint32_t flags; ///< Status flags + uint32_t chidmax; ///< Maximum channel ID + uint32_t linesize; ///< Size of each cache line + uint32_t spkcount; ///< Total spike count + CentralSpikeCache cache[cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief PC Status buffer (flattened from cbPcStatus class) +/// +/// IMPROVEMENT: Flattened to C struct for ABI stability and cross-compiler compatibility. +/// Central uses a C++ class which is fragile across different build environments. +/// +enum class NSPStatus : uint32_t { + NSP_INIT = 0, + NSP_NOIPADDR = 1, + NSP_NOREPLY = 2, + NSP_FOUND = 3, + NSP_INVALID = 4 +}; + +struct CentralPCStatus { + // Public data + cbPKT_UNIT_SELECTION isSelection[cbMAXPROCS]; ///< Unit selection per instrument + + // Status fields (was private in cbPcStatus) + int32_t m_iBlockRecording; ///< Recording block counter + uint32_t m_nPCStatusFlags; ///< PC status flags + uint32_t m_nNumFEChans; ///< Number of FE channels + uint32_t m_nNumAnainChans; ///< Number of analog input channels + uint32_t m_nNumAnalogChans; ///< Number of analog channels + uint32_t m_nNumAoutChans; ///< Number of analog output channels + uint32_t m_nNumAudioChans; ///< Number of audio channels + uint32_t m_nNumAnalogoutChans; ///< Number of analog output channels + uint32_t m_nNumDiginChans; ///< Number of digital input channels + uint32_t m_nNumSerialChans; ///< Number of serial channels + uint32_t m_nNumDigoutChans; ///< Number of digital output channels + uint32_t m_nNumTotalChans; ///< Total channel count + NSPStatus m_nNspStatus[cbMAXPROCS]; ///< NSP status per instrument + uint32_t m_nNumNTrodesPerInstrument[cbMAXPROCS];///< NTrode count per instrument + uint32_t m_nGeminiSystem; ///< Gemini system flag +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Receive buffer for incoming packets (simplified for Phase 2) +/// +struct CentralReceiveBuffer { + uint32_t received; ///< Number of packets received + PROCTIME lasttime; ///< Last timestamp + uint32_t headwrap; ///< Head wrap counter + uint32_t headindex; ///< Current head index + uint32_t buffer[cbRECBUFFLEN]; ///< Packet buffer +}; + +} // namespace central_v4_0 + +} // namespace cbshm + +#pragma pack(pop) + +#endif // CBSHMEM_CENTRAL_TYPES_V4_0_H diff --git a/src/cbshm/include/cbshm/central_types/v4_1.h b/src/cbshm/include/cbshm/central_types/v4_1.h new file mode 100644 index 00000000..a8cbe25b --- /dev/null +++ b/src/cbshm/include/cbshm/central_types/v4_1.h @@ -0,0 +1,259 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v4_1.h +/// @author Caden Shmookler +/// @date 2026-05-15 +/// +/// @brief Central-compatible shared memory structure definitions +/// +/// This file defines the shared memory structures using Central's constants to +/// ensure compatibility with Central when it creates shared memory. +/// +/// CRITICAL: These structures MUST match Central's cbhwlib.h exactly! +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef CBSHM_CENTRAL_TYPES_V4_1_H +#define CBSHM_CENTRAL_TYPES_V4_1_H + +#include + +// Include InstrumentId from protocol module +#include + +// Ensure tight packing for shared memory structures +#pragma pack(push, 1) + +namespace cbshm { + +namespace central_v4_1 { + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Central Constants +/// @{ + +// These MUST match Central's constants +constexpr uint32_t cbMAXPROCS = 3; ///< Central supports up to 3 NSPs +constexpr uint32_t cbNUM_FE_CHANS = 512; ///< Central supports 512 FE channels +constexpr uint32_t cbMAXGROUPS = 8; ///< Sample rate groups +constexpr uint32_t cbMAXFILTS = 32; ///< Digital filters +constexpr uint32_t cbMAXVIDEOSOURCE = 1; +constexpr uint32_t cbMAXTRACKOBJ = 20; +constexpr uint32_t cbMAXHOOPS = 4; +constexpr uint32_t cbMAX_AOUT_TRIGGER = 5; + +// Channel counts +constexpr uint32_t cbNUM_ANAIN_CHANS = 16 * cbMAXPROCS; +constexpr uint32_t cbNUM_ANALOG_CHANS = cbNUM_FE_CHANS + cbNUM_ANAIN_CHANS; +constexpr uint32_t cbNUM_ANAOUT_CHANS = 4 * cbMAXPROCS; +constexpr uint32_t cbNUM_AUDOUT_CHANS = 2 * cbMAXPROCS; +constexpr uint32_t cbNUM_ANALOGOUT_CHANS = cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS; +constexpr uint32_t cbNUM_DIGIN_CHANS = 1 * cbMAXPROCS; +constexpr uint32_t cbNUM_SERIAL_CHANS = 1 * cbMAXPROCS; +constexpr uint32_t cbNUM_DIGOUT_CHANS = 4 * cbMAXPROCS; + +// Total channels +constexpr uint32_t cbMAXCHANS = (cbNUM_ANALOG_CHANS + cbNUM_ANALOGOUT_CHANS + + cbNUM_DIGIN_CHANS + cbNUM_SERIAL_CHANS + + cbNUM_DIGOUT_CHANS); + +// Bank definitions +constexpr uint32_t cbCHAN_PER_BANK = 32; +constexpr uint32_t cbNUM_FE_BANKS = cbNUM_FE_CHANS / cbCHAN_PER_BANK; +constexpr uint32_t cbNUM_ANAIN_BANKS = 1; +constexpr uint32_t cbNUM_ANAOUT_BANKS = 1; +constexpr uint32_t cbNUM_AUDOUT_BANKS = 1; +constexpr uint32_t cbNUM_DIGIN_BANKS = 1; +constexpr uint32_t cbNUM_SERIAL_BANKS = 1; +constexpr uint32_t cbNUM_DIGOUT_BANKS = 1; + +constexpr uint32_t cbMAXBANKS = (cbNUM_FE_BANKS + cbNUM_ANAIN_BANKS + + cbNUM_ANAOUT_BANKS + cbNUM_AUDOUT_BANKS + + cbNUM_DIGIN_BANKS + cbNUM_SERIAL_BANKS + + cbNUM_DIGOUT_BANKS); + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Buffer Size Constants (must be defined before structures) +/// @{ + +/// Max UDP packet size (from Central) +constexpr uint32_t cbCER_UDP_SIZE_MAX = 58080; + +/// Transmit buffer sizes (Central-compatible) +constexpr uint32_t cbXMT_GLOBAL_BUFFLEN = ((cbCER_UDP_SIZE_MAX / 4) * 5000 + 2); ///< Room for 5000 packet-sized slots +constexpr uint32_t cbXMT_LOCAL_BUFFLEN = ((cbCER_UDP_SIZE_MAX / 4) * 2000 + 2); ///< Room for 2000 packet-sized slots + +/// N-Trode count +constexpr uint32_t cbMAXNTRODES = cbNUM_ANALOG_CHANS / 2; ///< = 280 + +/// Analog output gain channels (Central's multi-instrument count) +constexpr uint32_t AOUT_NUM_GAIN_CHANS = cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS; ///< = 18 + +/// Spike cache constants +constexpr uint32_t cbPKT_SPKCACHEPKTCNT = 400; ///< Packets per channel cache +constexpr uint32_t cbPKT_SPKCACHELINECNT = cbMAXCHANS; ///< One cache per channel (Central uses cbMAXCHANS, not cbNUM_ANALOG_CHANS) + +/// Receive buffer size +constexpr uint32_t cbRECBUFFLEN = cbNUM_FE_CHANS * 32768 * 4; + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Instrument status flags (bit field) +/// +/// Used to track which instruments are active in shared memory +/// +enum class InstrumentStatus : uint32_t { + INACTIVE = 0x00000000, ///< Instrument slot is not in use + ACTIVE = 0x00000001, ///< Instrument is active and has data +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Central's actual binary layout (CentralLegacyCFGBUFF) +/// +/// This struct matches Central's cbCFGBUFF field order EXACTLY (from cbhwlib.h). +/// It is NOT the same as CereLink's cbConfigBuffer (which reorders fields and adds +/// instrument_status). This struct is used in CENTRAL_COMPAT mode to read Central's +/// shared memory as a CLIENT. +/// +/// Key differences from CereLink's cbConfigBuffer: +/// - optiontable/colortable: 3rd/4th fields here (after sysflags), last fields in CereLink +/// - instrument_status: absent here (Central has no such concept) +/// - isLnc: after isWaveform here, before chaninfo in CereLink +/// - hwndCentral: omitted (at end, variable size, not needed) +/// +struct CentralLegacyCFGBUFF { + uint32_t version; + uint32_t sysflags; + cbOPTIONTABLE optiontable; + cbCOLORTABLE colortable; + cbPKT_SYSINFO sysinfo; + cbPKT_PROCINFO procinfo[cbMAXPROCS]; + cbPKT_BANKINFO bankinfo[cbMAXPROCS][cbMAXBANKS]; + cbPKT_GROUPINFO groupinfo[cbMAXPROCS][cbMAXGROUPS]; + cbPKT_FILTINFO filtinfo[cbMAXPROCS][cbMAXFILTS]; + cbPKT_ADAPTFILTINFO adaptinfo[cbMAXPROCS]; + cbPKT_REFELECFILTINFO refelecinfo[cbMAXPROCS]; + cbPKT_CHANINFO chaninfo[cbMAXCHANS]; + cbSPIKE_SORTING isSortingOptions; + cbPKT_NTRODEINFO isNTrodeInfo[cbMAXNTRODES]; + cbPKT_AOUT_WAVEFORM isWaveform[AOUT_NUM_GAIN_CHANS][cbMAX_AOUT_TRIGGER]; + cbPKT_LNC isLnc[cbMAXPROCS]; + cbPKT_NPLAY isNPlay; + cbVIDEOSOURCE isVideoSource[cbMAXVIDEOSOURCE]; + cbTRACKOBJ isTrackObj[cbMAXTRACKOBJ]; + cbPKT_FILECFG fileinfo; + // hwndCentral omitted (at end, variable size, not needed by CereLink) +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Transmit buffer for outgoing packets (Global - sent to device) +/// +/// Ring buffer for packets waiting to be transmitted to device via UDP. +/// Buffer stores raw packet data as uint32_t words (Central's format). +/// +/// This is stored in a separate shared memory segment (not embedded in config buffer) +/// to match Central's architecture. +/// +struct CentralTransmitBuffer { + uint32_t transmitted; ///< How many packets have been sent + uint32_t headindex; ///< First empty position (write index) + uint32_t tailindex; ///< One past last emptied position (read index) + uint32_t last_valid_index; ///< Greatest valid starting index + uint32_t bufferlen; ///< Number of indices in buffer + uint32_t buffer[cbXMT_GLOBAL_BUFFLEN]; ///< Ring buffer for packet data +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Local transmit buffer (IPC-only packets) +/// +/// Smaller than Global buffer, used for cbSendLoopbackPacket() - packets meant only for +/// local processes, not sent to device. +/// +struct CentralTransmitBufferLocal { + uint32_t transmitted; ///< How many packets have been sent + uint32_t headindex; ///< First empty position (write index) + uint32_t tailindex; ///< One past last emptied position (read index) + uint32_t last_valid_index; ///< Greatest valid starting index + uint32_t bufferlen; ///< Number of indices in buffer + uint32_t buffer[cbXMT_LOCAL_BUFFLEN]; ///< Ring buffer for packet data +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Spike cache buffer +/// +/// Caches recent spike packets for each channel to allow quick access without +/// scanning the entire receive buffer. +/// +struct CentralSpikeCache { + uint32_t chid; ///< Channel ID + uint32_t pktcnt; ///< Number of packets that can be saved + uint32_t pktsize; ///< Size of individual packet + uint32_t head; ///< Where to place next packet (circular) + uint32_t valid; ///< How many packets since last config + cbPKT_SPK spkpkt[cbPKT_SPKCACHEPKTCNT]; ///< Circular buffer of cached spikes +}; + +struct CentralSpikeBuffer { + uint32_t flags; ///< Status flags + uint32_t chidmax; ///< Maximum channel ID + uint32_t linesize; ///< Size of each cache line + uint32_t spkcount; ///< Total spike count + CentralSpikeCache cache[cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief PC Status buffer (flattened from cbPcStatus class) +/// +/// IMPROVEMENT: Flattened to C struct for ABI stability and cross-compiler compatibility. +/// Central uses a C++ class which is fragile across different build environments. +/// +enum class NSPStatus : uint32_t { + NSP_INIT = 0, + NSP_NOIPADDR = 1, + NSP_NOREPLY = 2, + NSP_FOUND = 3, + NSP_INVALID = 4 +}; + +struct CentralPCStatus { + // Public data + cbPKT_UNIT_SELECTION isSelection[cbMAXPROCS]; ///< Unit selection per instrument + + // Status fields (was private in cbPcStatus) + int32_t m_iBlockRecording; ///< Recording block counter + uint32_t m_nPCStatusFlags; ///< PC status flags + uint32_t m_nNumFEChans; ///< Number of FE channels + uint32_t m_nNumAnainChans; ///< Number of analog input channels + uint32_t m_nNumAnalogChans; ///< Number of analog channels + uint32_t m_nNumAoutChans; ///< Number of analog output channels + uint32_t m_nNumAudioChans; ///< Number of audio channels + uint32_t m_nNumAnalogoutChans; ///< Number of analog output channels + uint32_t m_nNumDiginChans; ///< Number of digital input channels + uint32_t m_nNumSerialChans; ///< Number of serial channels + uint32_t m_nNumDigoutChans; ///< Number of digital output channels + uint32_t m_nNumTotalChans; ///< Total channel count + NSPStatus m_nNspStatus[cbMAXPROCS]; ///< NSP status per instrument + uint32_t m_nNumNTrodesPerInstrument[cbMAXPROCS];///< NTrode count per instrument + uint32_t m_nGeminiSystem; ///< Gemini system flag +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Receive buffer for incoming packets (simplified for Phase 2) +/// +struct CentralReceiveBuffer { + uint32_t received; ///< Number of packets received + PROCTIME lasttime; ///< Last timestamp + uint32_t headwrap; ///< Head wrap counter + uint32_t headindex; ///< Current head index + uint32_t buffer[cbRECBUFFLEN]; ///< Packet buffer +}; + +} // namespace central_v4_1 + +} // namespace cbshm + +#pragma pack(pop) + +#endif // CBSHMEM_CENTRAL_TYPES_V4_1_H diff --git a/src/cbshm/include/cbshm/central_types.h b/src/cbshm/include/cbshm/central_types/v4_2.h similarity index 58% rename from src/cbshm/include/cbshm/central_types.h rename to src/cbshm/include/cbshm/central_types/v4_2.h index 784aaa32..3912e46c 100644 --- a/src/cbshm/include/cbshm/central_types.h +++ b/src/cbshm/include/cbshm/central_types/v4_2.h @@ -1,74 +1,75 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file central_types.h -/// @author CereLink Development Team -/// @date 2025-11-11 +/// @file v4_2.h +/// @author Caden Shmookler +/// @date 2026-05-15 /// /// @brief Central-compatible shared memory structure definitions /// -/// This file defines the shared memory structures using Central's constants (cbMAXPROCS=4, -/// cbNUM_FE_CHANS=768) to ensure compatibility with Central when it creates shared memory. +/// This file defines the shared memory structures using Central's constants to +/// ensure compatibility with Central when it creates shared memory. /// /// CRITICAL: These structures MUST match Central's cbhwlib.h exactly! /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifndef CBSHM_CENTRAL_TYPES_H -#define CBSHM_CENTRAL_TYPES_H +#ifndef CBSHM_CENTRAL_TYPES_V4_2_H +#define CBSHM_CENTRAL_TYPES_V4_2_H + +#include // Include InstrumentId from protocol module #include -// Include packet structure definitions from cbproto -#include -#include -#include - -#include - // Ensure tight packing for shared memory structures #pragma pack(push, 1) namespace cbshm { +namespace central_v4_2 { + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @name Central Constants /// @{ // These MUST match Central's constants -constexpr uint32_t CENTRAL_cbMAXPROCS = 4; ///< Central supports up to 4 NSPs -constexpr uint32_t CENTRAL_cbNUM_FE_CHANS = 768; ///< Central supports 768 FE channels -constexpr uint32_t CENTRAL_cbMAXGROUPS = 8; ///< Sample rate groups -constexpr uint32_t CENTRAL_cbMAXFILTS = 32; ///< Digital filters +constexpr uint32_t cbMAXPROCS = 4; ///< Central supports up to 4 NSPs +constexpr uint32_t cbNUM_FE_CHANS = 768; ///< Central supports 768 FE channels +constexpr uint32_t cbMAXGROUPS = 8; ///< Sample rate groups +constexpr uint32_t cbMAXFILTS = 32; ///< Digital filters +constexpr uint32_t cbMAXVIDEOSOURCE = 1; +constexpr uint32_t cbMAXTRACKOBJ = 20; +constexpr uint32_t cbMAXHOOPS = 4; +constexpr uint32_t cbMAX_AOUT_TRIGGER = 5; // Channel counts -constexpr uint32_t CENTRAL_cbNUM_ANAIN_CHANS = 16 * CENTRAL_cbMAXPROCS; -constexpr uint32_t CENTRAL_cbNUM_ANALOG_CHANS = CENTRAL_cbNUM_FE_CHANS + CENTRAL_cbNUM_ANAIN_CHANS; -constexpr uint32_t CENTRAL_cbNUM_ANAOUT_CHANS = 4 * CENTRAL_cbMAXPROCS; -constexpr uint32_t CENTRAL_cbNUM_AUDOUT_CHANS = 2 * CENTRAL_cbMAXPROCS; -constexpr uint32_t CENTRAL_cbNUM_ANALOGOUT_CHANS = CENTRAL_cbNUM_ANAOUT_CHANS + CENTRAL_cbNUM_AUDOUT_CHANS; -constexpr uint32_t CENTRAL_cbNUM_DIGIN_CHANS = 1 * CENTRAL_cbMAXPROCS; -constexpr uint32_t CENTRAL_cbNUM_SERIAL_CHANS = 1 * CENTRAL_cbMAXPROCS; -constexpr uint32_t CENTRAL_cbNUM_DIGOUT_CHANS = 4 * CENTRAL_cbMAXPROCS; +constexpr uint32_t cbNUM_ANAIN_CHANS = 16 * cbMAXPROCS; +constexpr uint32_t cbNUM_ANALOG_CHANS = cbNUM_FE_CHANS + cbNUM_ANAIN_CHANS; +constexpr uint32_t cbNUM_ANAOUT_CHANS = 4 * cbMAXPROCS; +constexpr uint32_t cbNUM_AUDOUT_CHANS = 2 * cbMAXPROCS; +constexpr uint32_t cbNUM_ANALOGOUT_CHANS = cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS; +constexpr uint32_t cbNUM_DIGIN_CHANS = 1 * cbMAXPROCS; +constexpr uint32_t cbNUM_SERIAL_CHANS = 1 * cbMAXPROCS; +constexpr uint32_t cbNUM_DIGOUT_CHANS = 4 * cbMAXPROCS; // Total channels -constexpr uint32_t CENTRAL_cbMAXCHANS = (CENTRAL_cbNUM_ANALOG_CHANS + CENTRAL_cbNUM_ANALOGOUT_CHANS + - CENTRAL_cbNUM_DIGIN_CHANS + CENTRAL_cbNUM_SERIAL_CHANS + - CENTRAL_cbNUM_DIGOUT_CHANS); +constexpr uint32_t cbMAXCHANS = (cbNUM_ANALOG_CHANS + cbNUM_ANALOGOUT_CHANS + + cbNUM_DIGIN_CHANS + cbNUM_SERIAL_CHANS + + cbNUM_DIGOUT_CHANS); // Bank definitions -constexpr uint32_t CENTRAL_cbCHAN_PER_BANK = 32; -constexpr uint32_t CENTRAL_cbNUM_FE_BANKS = CENTRAL_cbNUM_FE_CHANS / CENTRAL_cbCHAN_PER_BANK; -constexpr uint32_t CENTRAL_cbNUM_ANAIN_BANKS = 1; -constexpr uint32_t CENTRAL_cbNUM_ANAOUT_BANKS = 1; -constexpr uint32_t CENTRAL_cbNUM_AUDOUT_BANKS = 1; -constexpr uint32_t CENTRAL_cbNUM_DIGIN_BANKS = 1; -constexpr uint32_t CENTRAL_cbNUM_SERIAL_BANKS = 1; -constexpr uint32_t CENTRAL_cbNUM_DIGOUT_BANKS = 1; - -constexpr uint32_t CENTRAL_cbMAXBANKS = (CENTRAL_cbNUM_FE_BANKS + CENTRAL_cbNUM_ANAIN_BANKS + - CENTRAL_cbNUM_ANAOUT_BANKS + CENTRAL_cbNUM_AUDOUT_BANKS + - CENTRAL_cbNUM_DIGIN_BANKS + CENTRAL_cbNUM_SERIAL_BANKS + - CENTRAL_cbNUM_DIGOUT_BANKS); +constexpr uint32_t cbCHAN_PER_BANK = 32; +constexpr uint32_t cbNUM_FE_BANKS = cbNUM_FE_CHANS / cbCHAN_PER_BANK; +constexpr uint32_t cbNUM_ANAIN_BANKS = 1; +constexpr uint32_t cbNUM_ANAOUT_BANKS = 1; +constexpr uint32_t cbNUM_AUDOUT_BANKS = 1; +constexpr uint32_t cbNUM_DIGIN_BANKS = 1; +constexpr uint32_t cbNUM_SERIAL_BANKS = 1; +constexpr uint32_t cbNUM_DIGOUT_BANKS = 1; + +constexpr uint32_t cbMAXBANKS = (cbNUM_FE_BANKS + cbNUM_ANAIN_BANKS + + cbNUM_ANAOUT_BANKS + cbNUM_AUDOUT_BANKS + + cbNUM_DIGIN_BANKS + cbNUM_SERIAL_BANKS + + cbNUM_DIGOUT_BANKS); /// @} @@ -77,24 +78,24 @@ constexpr uint32_t CENTRAL_cbMAXBANKS = (CENTRAL_cbNUM_FE_BANKS + CENTRAL_cbNUM_ /// @{ /// Max UDP packet size (from Central) -constexpr uint32_t CENTRAL_cbCER_UDP_SIZE_MAX = 58080; +constexpr uint32_t cbCER_UDP_SIZE_MAX = 58080; /// Transmit buffer sizes (Central-compatible) -constexpr uint32_t CENTRAL_cbXMT_GLOBAL_BUFFLEN = ((CENTRAL_cbCER_UDP_SIZE_MAX / 4) * 5000 + 2); ///< Room for 5000 packet-sized slots -constexpr uint32_t CENTRAL_cbXMT_LOCAL_BUFFLEN = ((CENTRAL_cbCER_UDP_SIZE_MAX / 4) * 2000 + 2); ///< Room for 2000 packet-sized slots +constexpr uint32_t cbXMT_GLOBAL_BUFFLEN = ((cbCER_UDP_SIZE_MAX / 4) * 5000 + 2); ///< Room for 5000 packet-sized slots +constexpr uint32_t cbXMT_LOCAL_BUFFLEN = ((cbCER_UDP_SIZE_MAX / 4) * 2000 + 2); ///< Room for 2000 packet-sized slots /// N-Trode count (Central uses cbNUM_FE_CHANS / 2, not cbNUM_ANALOG_CHANS / 2) -constexpr uint32_t CENTRAL_cbMAXNTRODES = CENTRAL_cbNUM_FE_CHANS / 2; ///< = 384 +constexpr uint32_t cbMAXNTRODES = cbNUM_FE_CHANS / 2; ///< = 384 /// Analog output gain channels (Central's multi-instrument count) -constexpr uint32_t CENTRAL_AOUT_NUM_GAIN_CHANS = CENTRAL_cbNUM_ANAOUT_CHANS + CENTRAL_cbNUM_AUDOUT_CHANS; ///< = 24 +constexpr uint32_t AOUT_NUM_GAIN_CHANS = cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS; ///< = 24 /// Spike cache constants -constexpr uint32_t CENTRAL_cbPKT_SPKCACHEPKTCNT = 400; ///< Packets per channel cache -constexpr uint32_t CENTRAL_cbPKT_SPKCACHELINECNT = CENTRAL_cbMAXCHANS; ///< One cache per channel (Central uses cbMAXCHANS, not cbNUM_ANALOG_CHANS) +constexpr uint32_t cbPKT_SPKCACHEPKTCNT = 400; ///< Packets per channel cache +constexpr uint32_t cbPKT_SPKCACHELINECNT = cbMAXCHANS; ///< One cache per channel (Central uses cbMAXCHANS, not cbNUM_ANALOG_CHANS) /// Receive buffer size -constexpr uint32_t CENTRAL_cbRECBUFFLEN = CENTRAL_cbNUM_FE_CHANS * 65536 * 4 - 1; +constexpr uint32_t cbRECBUFFLEN = cbNUM_FE_CHANS * 65536 * 4 - 1; /// @} @@ -111,6 +112,8 @@ enum class InstrumentStatus : uint32_t { /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Central's actual binary layout (CentralLegacyCFGBUFF) /// +/// VER: 4.2+ (CURRENT) +/// /// This struct matches Central's cbCFGBUFF field order EXACTLY (from cbhwlib.h). /// It is NOT the same as CereLink's cbConfigBuffer (which reorders fields and adds /// instrument_status). This struct is used in CENTRAL_COMPAT mode to read Central's @@ -128,17 +131,17 @@ struct CentralLegacyCFGBUFF { cbOPTIONTABLE optiontable; cbCOLORTABLE colortable; cbPKT_SYSINFO sysinfo; - cbPKT_PROCINFO procinfo[CENTRAL_cbMAXPROCS]; - cbPKT_BANKINFO bankinfo[CENTRAL_cbMAXPROCS][CENTRAL_cbMAXBANKS]; - cbPKT_GROUPINFO groupinfo[CENTRAL_cbMAXPROCS][CENTRAL_cbMAXGROUPS]; - cbPKT_FILTINFO filtinfo[CENTRAL_cbMAXPROCS][CENTRAL_cbMAXFILTS]; - cbPKT_ADAPTFILTINFO adaptinfo[CENTRAL_cbMAXPROCS]; - cbPKT_REFELECFILTINFO refelecinfo[CENTRAL_cbMAXPROCS]; - cbPKT_CHANINFO chaninfo[CENTRAL_cbMAXCHANS]; + cbPKT_PROCINFO procinfo[cbMAXPROCS]; + cbPKT_BANKINFO bankinfo[cbMAXPROCS][cbMAXBANKS]; + cbPKT_GROUPINFO groupinfo[cbMAXPROCS][cbMAXGROUPS]; + cbPKT_FILTINFO filtinfo[cbMAXPROCS][cbMAXFILTS]; + cbPKT_ADAPTFILTINFO adaptinfo[cbMAXPROCS]; + cbPKT_REFELECFILTINFO refelecinfo[cbMAXPROCS]; + cbPKT_CHANINFO chaninfo[cbMAXCHANS]; cbSPIKE_SORTING isSortingOptions; - cbPKT_NTRODEINFO isNTrodeInfo[CENTRAL_cbMAXNTRODES]; - cbPKT_AOUT_WAVEFORM isWaveform[CENTRAL_AOUT_NUM_GAIN_CHANS][cbMAX_AOUT_TRIGGER]; - cbPKT_LNC isLnc[CENTRAL_cbMAXPROCS]; + cbPKT_NTRODEINFO isNTrodeInfo[cbMAXNTRODES]; + cbPKT_AOUT_WAVEFORM isWaveform[AOUT_NUM_GAIN_CHANS][cbMAX_AOUT_TRIGGER]; + cbPKT_LNC isLnc[cbMAXPROCS]; cbPKT_NPLAY isNPlay; cbVIDEOSOURCE isVideoSource[cbMAXVIDEOSOURCE]; cbTRACKOBJ isTrackObj[cbMAXTRACKOBJ]; @@ -161,31 +164,9 @@ struct CentralTransmitBuffer { uint32_t tailindex; ///< One past last emptied position (read index) uint32_t last_valid_index; ///< Greatest valid starting index uint32_t bufferlen; ///< Number of indices in buffer - uint32_t buffer[CENTRAL_cbXMT_GLOBAL_BUFFLEN]; ///< Ring buffer for packet data + uint32_t buffer[cbXMT_GLOBAL_BUFFLEN]; ///< Ring buffer for packet data }; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Central-compatible configuration buffer -/// -/// This is now an alias to cbConfigBuffer (defined in cbproto/config_buffer.h). -/// The structure maintains Central's cbCFGBUFF layout compatibility. -/// -/// The CENTRAL_* constants are kept for backward compatibility in this module, -/// while cbConfigBuffer uses cbCONFIG_* constants (which have the same values). -/// -/// Static asserts below verify the constants match. -/// -using CentralConfigBuffer = cbConfigBuffer; - -// Verify that CENTRAL_* constants match cbCONFIG_* constants -static_assert(CENTRAL_cbMAXPROCS == cbCONFIG_MAXPROCS, "CENTRAL_cbMAXPROCS must equal cbCONFIG_MAXPROCS"); -static_assert(CENTRAL_cbMAXGROUPS == cbCONFIG_MAXGROUPS, "CENTRAL_cbMAXGROUPS must equal cbCONFIG_MAXGROUPS"); -static_assert(CENTRAL_cbMAXFILTS == cbCONFIG_MAXFILTS, "CENTRAL_cbMAXFILTS must equal cbCONFIG_MAXFILTS"); -static_assert(CENTRAL_cbMAXCHANS == cbCONFIG_MAXCHANS, "CENTRAL_cbMAXCHANS must equal cbCONFIG_MAXCHANS"); -static_assert(CENTRAL_cbMAXBANKS == cbCONFIG_MAXBANKS, "CENTRAL_cbMAXBANKS must equal cbCONFIG_MAXBANKS"); -static_assert(CENTRAL_cbMAXNTRODES == cbCONFIG_MAXNTRODES, "CENTRAL_cbMAXNTRODES must equal cbCONFIG_MAXNTRODES"); -static_assert(CENTRAL_AOUT_NUM_GAIN_CHANS == cbCONFIG_AOUT_NUM_GAIN_CHANS, "CENTRAL_AOUT_NUM_GAIN_CHANS must equal cbCONFIG_AOUT_NUM_GAIN_CHANS"); - /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Local transmit buffer (IPC-only packets) /// @@ -198,7 +179,7 @@ struct CentralTransmitBufferLocal { uint32_t tailindex; ///< One past last emptied position (read index) uint32_t last_valid_index; ///< Greatest valid starting index uint32_t bufferlen; ///< Number of indices in buffer - uint32_t buffer[CENTRAL_cbXMT_LOCAL_BUFFLEN]; ///< Ring buffer for packet data + uint32_t buffer[cbXMT_LOCAL_BUFFLEN]; ///< Ring buffer for packet data }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -213,7 +194,7 @@ struct CentralSpikeCache { uint32_t pktsize; ///< Size of individual packet uint32_t head; ///< Where to place next packet (circular) uint32_t valid; ///< How many packets since last config - cbPKT_SPK spkpkt[CENTRAL_cbPKT_SPKCACHEPKTCNT]; ///< Circular buffer of cached spikes + cbPKT_SPK spkpkt[cbPKT_SPKCACHEPKTCNT]; ///< Circular buffer of cached spikes }; struct CentralSpikeBuffer { @@ -221,7 +202,7 @@ struct CentralSpikeBuffer { uint32_t chidmax; ///< Maximum channel ID uint32_t linesize; ///< Size of each cache line uint32_t spkcount; ///< Total spike count - CentralSpikeCache cache[CENTRAL_cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches + CentralSpikeCache cache[cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -243,7 +224,7 @@ enum class NSPStatus : uint32_t { /// Central uses `enLaunchView` (C++ enum, sizeof(int) = 4 bytes) for the application field. /// We use uint32_t for ABI compatibility. /// -constexpr uint32_t CENTRAL_cbMAXAPPWORKSPACES = 10; +constexpr uint32_t cbMAXAPPWORKSPACES = 10; struct CentralAppWorkspace { uint32_t m_nWorkspace; ///< Workspace number (1-based) @@ -257,7 +238,7 @@ struct CentralAppWorkspace { struct CentralPCStatus { // Public data - cbPKT_UNIT_SELECTION isSelection[CENTRAL_cbMAXPROCS]; ///< Unit selection per instrument + cbPKT_UNIT_SELECTION isSelection[cbMAXPROCS]; ///< Unit selection per instrument // Status fields (was private in cbPcStatus) int32_t m_iBlockRecording; ///< Recording block counter @@ -272,10 +253,10 @@ struct CentralPCStatus { uint32_t m_nNumSerialChans; ///< Number of serial channels uint32_t m_nNumDigoutChans; ///< Number of digital output channels uint32_t m_nNumTotalChans; ///< Total channel count - NSPStatus m_nNspStatus[CENTRAL_cbMAXPROCS]; ///< NSP status per instrument - uint32_t m_nNumNTrodesPerInstrument[CENTRAL_cbMAXPROCS];///< NTrode count per instrument + NSPStatus m_nNspStatus[cbMAXPROCS]; ///< NSP status per instrument + uint32_t m_nNumNTrodesPerInstrument[cbMAXPROCS];///< NTrode count per instrument uint32_t m_nGeminiSystem; ///< Gemini system flag - CentralAppWorkspace m_icAppWorkspace[CENTRAL_cbMAXAPPWORKSPACES]; ///< App workspace config + CentralAppWorkspace m_icAppWorkspace[cbMAXAPPWORKSPACES]; ///< App workspace config }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -286,11 +267,13 @@ struct CentralReceiveBuffer { PROCTIME lasttime; ///< Last timestamp uint32_t headwrap; ///< Head wrap counter uint32_t headindex; ///< Current head index - uint32_t buffer[CENTRAL_cbRECBUFFLEN]; ///< Packet buffer + uint32_t buffer[cbRECBUFFLEN]; ///< Packet buffer }; +} // namespace central_v4_2 + } // namespace cbshm #pragma pack(pop) -#endif // CBSHMEM_CENTRAL_TYPES_H +#endif // CBSHMEM_CENTRAL_TYPES_V4_2_H diff --git a/src/cbshm/include/cbshm/config_buffer.h b/src/cbshm/include/cbshm/config_buffer.h index 30926ade..f64f9eba 100644 --- a/src/cbshm/include/cbshm/config_buffer.h +++ b/src/cbshm/include/cbshm/config_buffer.h @@ -18,9 +18,7 @@ #include -#ifdef __cplusplus -extern "C" { -#endif +namespace cbshm { /////////////////////////////////////////////////////////////////////////////////////////////////// /// @name Configuration Buffer Constants @@ -28,71 +26,71 @@ extern "C" { /// Maximum number of instruments (NSPs) supported /// This matches Central's multi-instrument capability (up to 4 NSPs) -#define cbCONFIG_MAXPROCS 4 +constexpr uint32_t cbCONFIG_MAXPROCS = 4; /// Maximum number of sample rate groups per instrument -#define cbCONFIG_MAXGROUPS 8 +constexpr uint32_t cbCONFIG_MAXGROUPS = 8; /// Maximum number of digital filters per instrument -#define cbCONFIG_MAXFILTS 32 +constexpr uint32_t cbCONFIG_MAXFILTS = 32; /// Number of front-end channels per instrument (Gemini = 768) -#define cbCONFIG_NUM_FE_CHANS 768 +constexpr uint32_t cbCONFIG_NUM_FE_CHANS = 768; /// Number of analog input channels per instrument -#define cbCONFIG_NUM_ANAIN_CHANS (16 * cbCONFIG_MAXPROCS) +constexpr uint32_t cbCONFIG_NUM_ANAIN_CHANS = (16 * cbCONFIG_MAXPROCS); /// Total analog channels -#define cbCONFIG_NUM_ANALOG_CHANS (cbCONFIG_NUM_FE_CHANS + cbCONFIG_NUM_ANAIN_CHANS) +constexpr uint32_t cbCONFIG_NUM_ANALOG_CHANS = (cbCONFIG_NUM_FE_CHANS + cbCONFIG_NUM_ANAIN_CHANS); /// Number of analog output channels -#define cbCONFIG_NUM_ANAOUT_CHANS (4 * cbCONFIG_MAXPROCS) +constexpr uint32_t cbCONFIG_NUM_ANAOUT_CHANS = (4 * cbCONFIG_MAXPROCS); /// Number of audio output channels -#define cbCONFIG_NUM_AUDOUT_CHANS (2 * cbCONFIG_MAXPROCS) +constexpr uint32_t cbCONFIG_NUM_AUDOUT_CHANS = (2 * cbCONFIG_MAXPROCS); /// Total analog output channels -#define cbCONFIG_NUM_ANALOGOUT_CHANS (cbCONFIG_NUM_ANAOUT_CHANS + cbCONFIG_NUM_AUDOUT_CHANS) +constexpr uint32_t cbCONFIG_NUM_ANALOGOUT_CHANS = (cbCONFIG_NUM_ANAOUT_CHANS + cbCONFIG_NUM_AUDOUT_CHANS); /// Number of digital input channels -#define cbCONFIG_NUM_DIGIN_CHANS (1 * cbCONFIG_MAXPROCS) +constexpr uint32_t cbCONFIG_NUM_DIGIN_CHANS = (1 * cbCONFIG_MAXPROCS); /// Number of serial channels -#define cbCONFIG_NUM_SERIAL_CHANS (1 * cbCONFIG_MAXPROCS) +constexpr uint32_t cbCONFIG_NUM_SERIAL_CHANS = (1 * cbCONFIG_MAXPROCS); /// Number of digital output channels -#define cbCONFIG_NUM_DIGOUT_CHANS (4 * cbCONFIG_MAXPROCS) +constexpr uint32_t cbCONFIG_NUM_DIGOUT_CHANS = (4 * cbCONFIG_MAXPROCS); /// Total channels supported -#define cbCONFIG_MAXCHANS (cbCONFIG_NUM_ANALOG_CHANS + cbCONFIG_NUM_ANALOGOUT_CHANS + \ +constexpr uint32_t cbCONFIG_MAXCHANS = (cbCONFIG_NUM_ANALOG_CHANS + cbCONFIG_NUM_ANALOGOUT_CHANS + \ cbCONFIG_NUM_DIGIN_CHANS + cbCONFIG_NUM_SERIAL_CHANS + \ - cbCONFIG_NUM_DIGOUT_CHANS) + cbCONFIG_NUM_DIGOUT_CHANS); /// Channels per bank -#define cbCONFIG_CHAN_PER_BANK 32 +constexpr uint32_t cbCONFIG_CHAN_PER_BANK = 32; /// Number of front-end banks -#define cbCONFIG_NUM_FE_BANKS (cbCONFIG_NUM_FE_CHANS / cbCONFIG_CHAN_PER_BANK) +constexpr uint32_t cbCONFIG_NUM_FE_BANKS = (cbCONFIG_NUM_FE_CHANS / cbCONFIG_CHAN_PER_BANK); /// Number of banks per type -#define cbCONFIG_NUM_ANAIN_BANKS 1 -#define cbCONFIG_NUM_ANAOUT_BANKS 1 -#define cbCONFIG_NUM_AUDOUT_BANKS 1 -#define cbCONFIG_NUM_DIGIN_BANKS 1 -#define cbCONFIG_NUM_SERIAL_BANKS 1 -#define cbCONFIG_NUM_DIGOUT_BANKS 1 +constexpr uint32_t cbCONFIG_NUM_ANAIN_BANKS = 1; +constexpr uint32_t cbCONFIG_NUM_ANAOUT_BANKS = 1; +constexpr uint32_t cbCONFIG_NUM_AUDOUT_BANKS = 1; +constexpr uint32_t cbCONFIG_NUM_DIGIN_BANKS = 1; +constexpr uint32_t cbCONFIG_NUM_SERIAL_BANKS = 1; +constexpr uint32_t cbCONFIG_NUM_DIGOUT_BANKS = 1; /// Total banks per instrument -#define cbCONFIG_MAXBANKS (cbCONFIG_NUM_FE_BANKS + cbCONFIG_NUM_ANAIN_BANKS + \ +constexpr uint32_t cbCONFIG_MAXBANKS = (cbCONFIG_NUM_FE_BANKS + cbCONFIG_NUM_ANAIN_BANKS + \ cbCONFIG_NUM_ANAOUT_BANKS + cbCONFIG_NUM_AUDOUT_BANKS + \ cbCONFIG_NUM_DIGIN_BANKS + cbCONFIG_NUM_SERIAL_BANKS + \ - cbCONFIG_NUM_DIGOUT_BANKS) + cbCONFIG_NUM_DIGOUT_BANKS); /// Maximum n-trodes (stereotrode minimum) for multi-instrument config buffer -#define cbCONFIG_MAXNTRODES (cbCONFIG_NUM_FE_CHANS / 2) +constexpr uint32_t cbCONFIG_MAXNTRODES = (cbCONFIG_NUM_FE_CHANS / 2); /// Analog output gain channels for multi-instrument config buffer -#define cbCONFIG_AOUT_NUM_GAIN_CHANS (cbCONFIG_NUM_ANAOUT_CHANS + cbCONFIG_NUM_AUDOUT_CHANS) +constexpr uint32_t cbCONFIG_AOUT_NUM_GAIN_CHANS = (cbCONFIG_NUM_ANAOUT_CHANS + cbCONFIG_NUM_AUDOUT_CHANS); /// @} @@ -200,8 +198,19 @@ typedef struct { // Note: hwndCentral (HANDLE) is omitted - platform-specific and only used by Central } cbConfigBuffer; -#ifdef __cplusplus -} -#endif +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Central-compatible configuration buffer +/// +/// This is now an alias to cbConfigBuffer (defined in cbproto/config_buffer.h). +/// The structure maintains Central's cbCFGBUFF layout compatibility. +/// +/// The CENTRAL_* constants are kept for backward compatibility in this module, +/// while cbConfigBuffer uses cbCONFIG_* constants (which have the same values). +/// +/// Static asserts below verify the constants match. +/// +using CentralConfigBuffer = cbConfigBuffer; + +} // namespace cbshm #endif // CBPROTO_CONFIG_BUFFER_H diff --git a/src/cbshm/include/cbshm/native_types.h b/src/cbshm/include/cbshm/native_types.h index d1e8b417..87de941b 100644 --- a/src/cbshm/include/cbshm/native_types.h +++ b/src/cbshm/include/cbshm/native_types.h @@ -25,7 +25,8 @@ #include #include // For cbMAXBANKS -#include // For CentralSpikeCache reuse +#include // For cbRECBUFFLEN +#include #include #pragma pack(push, 1) @@ -55,7 +56,7 @@ constexpr uint32_t NATIVE_cbXMT_GLOBAL_BUFFLEN = (NATIVE_XMT_SLOT_WORDS * 5000 + constexpr uint32_t NATIVE_cbXMT_LOCAL_BUFFLEN = (NATIVE_XMT_SLOT_WORDS * 2000 + 2); /// Spike cache constants (one cache per native analog channel) -constexpr uint32_t NATIVE_cbPKT_SPKCACHEPKTCNT = CENTRAL_cbPKT_SPKCACHEPKTCNT; // 400 +constexpr uint32_t NATIVE_cbPKT_SPKCACHEPKTCNT = central::cbPKT_SPKCACHEPKTCNT; constexpr uint32_t NATIVE_cbPKT_SPKCACHELINECNT = NATIVE_NUM_ANALOG_CHANS; // 272 /// @} @@ -190,7 +191,7 @@ struct NativePCStatus { uint32_t m_nNumSerialChans; ///< Number of serial channels uint32_t m_nNumDigoutChans; ///< Number of digital output channels uint32_t m_nNumTotalChans; ///< Total channel count - NSPStatus m_nNspStatus; ///< NSP status (single instrument) + central::NSPStatus m_nNspStatus; ///< NSP status (single instrument) uint32_t m_nNumNTrodesPerInstrument; ///< NTrode count (single instrument) uint32_t m_nGeminiSystem; ///< Gemini system flag }; diff --git a/src/cbshm/include/cbshm/receive_buffer.h b/src/cbshm/include/cbshm/receive_buffer.h index 25d9e5ac..5f46a875 100644 --- a/src/cbshm/include/cbshm/receive_buffer.h +++ b/src/cbshm/include/cbshm/receive_buffer.h @@ -22,11 +22,6 @@ /// @name Receive Buffer Constants /// @{ -/// Maximum number of frontend channels (used for buffer size calculation) -#ifndef cbNUM_FE_CHANS -#define cbNUM_FE_CHANS 256 -#endif - /// Receive buffer length (matches Central's calculation) /// Formula: cbNUM_FE_CHANS * 65536 * 4 - 1 /// This provides enough space for a ring buffer of packets from all FE channels From 2997ce0e8a46096142b151b791a428d647a3687f Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Mon, 18 May 2026 15:34:17 -0600 Subject: [PATCH 07/62] Add central types for 3.11. --- src/cbshm/include/cbshm/central_types/v3_11.h | 259 ++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 src/cbshm/include/cbshm/central_types/v3_11.h diff --git a/src/cbshm/include/cbshm/central_types/v3_11.h b/src/cbshm/include/cbshm/central_types/v3_11.h new file mode 100644 index 00000000..143f33eb --- /dev/null +++ b/src/cbshm/include/cbshm/central_types/v3_11.h @@ -0,0 +1,259 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v3_11.h +/// @author Caden Shmookler +/// @date 2026-05-18 +/// +/// @brief Central-compatible shared memory structure definitions +/// +/// This file defines the shared memory structures using Central's constants to +/// ensure compatibility with Central when it creates shared memory. +/// +/// CRITICAL: These structures MUST match Central's cbhwlib.h exactly! +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef CBSHM_CENTRAL_TYPES_V3_11_H +#define CBSHM_CENTRAL_TYPES_V3_11_H + +#include + +// Include InstrumentId from protocol module +#include + +// Ensure tight packing for shared memory structures +#pragma pack(push, 1) + +namespace cbshm { + +namespace central_v3_11 { + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Central Constants +/// @{ + +// These MUST match Central's constants +constexpr uint32_t cbMAXPROCS = 1; ///< Central supports up to 1 NSPs +constexpr uint32_t cbNUM_FE_CHANS = 256; ///< Central supports 256 FE channels +constexpr uint32_t cbMAXGROUPS = 8; ///< Sample rate groups +constexpr uint32_t cbMAXFILTS = 32; ///< Digital filters +constexpr uint32_t cbMAXVIDEOSOURCE = 1; +constexpr uint32_t cbMAXTRACKOBJ = 20; +constexpr uint32_t cbMAXHOOPS = 4; +constexpr uint32_t cbMAX_AOUT_TRIGGER = 5; + +// Channel counts +constexpr uint32_t cbNUM_ANAIN_CHANS = 16 * cbMAXPROCS; +constexpr uint32_t cbNUM_ANALOG_CHANS = cbNUM_FE_CHANS + cbNUM_ANAIN_CHANS; +constexpr uint32_t cbNUM_ANAOUT_CHANS = 4 * cbMAXPROCS; +constexpr uint32_t cbNUM_AUDOUT_CHANS = 2 * cbMAXPROCS; +constexpr uint32_t cbNUM_ANALOGOUT_CHANS = cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS; +constexpr uint32_t cbNUM_DIGIN_CHANS = 1 * cbMAXPROCS; +constexpr uint32_t cbNUM_SERIAL_CHANS = 1 * cbMAXPROCS; +constexpr uint32_t cbNUM_DIGOUT_CHANS = 4 * cbMAXPROCS; + +// Total channels +constexpr uint32_t cbMAXCHANS = (cbNUM_ANALOG_CHANS + cbNUM_ANALOGOUT_CHANS + + cbNUM_DIGIN_CHANS + cbNUM_SERIAL_CHANS + + cbNUM_DIGOUT_CHANS); + +// Bank definitions +constexpr uint32_t cbCHAN_PER_BANK = 32; +constexpr uint32_t cbNUM_FE_BANKS = cbNUM_FE_CHANS / cbCHAN_PER_BANK; +constexpr uint32_t cbNUM_ANAIN_BANKS = 1; +constexpr uint32_t cbNUM_ANAOUT_BANKS = 1; +constexpr uint32_t cbNUM_AUDOUT_BANKS = 1; +constexpr uint32_t cbNUM_DIGIN_BANKS = 1; +constexpr uint32_t cbNUM_SERIAL_BANKS = 1; +constexpr uint32_t cbNUM_DIGOUT_BANKS = 1; + +constexpr uint32_t cbMAXBANKS = (cbNUM_FE_BANKS + cbNUM_ANAIN_BANKS + + cbNUM_ANAOUT_BANKS + cbNUM_AUDOUT_BANKS + + cbNUM_DIGIN_BANKS + cbNUM_SERIAL_BANKS + + cbNUM_DIGOUT_BANKS); + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Buffer Size Constants (must be defined before structures) +/// @{ + +/// Max UDP packet size (from Central) +constexpr uint32_t cbCER_UDP_SIZE_MAX = 1452; + +/// Transmit buffer sizes (Central-compatible) +constexpr uint32_t cbXMT_GLOBAL_BUFFLEN = ((cbCER_UDP_SIZE_MAX / 4) * 5000 + 2); ///< Room for 5000 packet-sized slots +constexpr uint32_t cbXMT_LOCAL_BUFFLEN = ((cbCER_UDP_SIZE_MAX / 4) * 2000 + 2); ///< Room for 2000 packet-sized slots + +/// N-Trode count +constexpr uint32_t cbMAXNTRODES = cbNUM_ANALOG_CHANS / 2; ///< = 136 + +/// Analog output gain channels (Central's multi-instrument count) +constexpr uint32_t AOUT_NUM_GAIN_CHANS = cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS; ///< = 6 + +/// Spike cache constants +constexpr uint32_t cbPKT_SPKCACHEPKTCNT = 400; ///< Packets per channel cache +constexpr uint32_t cbPKT_SPKCACHELINECNT = cbNUM_ANALOG_CHANS; ///< One cache per channel + +/// Receive buffer size +constexpr uint32_t cbRECBUFFLEN = cbNUM_FE_CHANS * 32768 * 4; + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Instrument status flags (bit field) +/// +/// Used to track which instruments are active in shared memory +/// +enum class InstrumentStatus : uint32_t { + INACTIVE = 0x00000000, ///< Instrument slot is not in use + ACTIVE = 0x00000001, ///< Instrument is active and has data +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Central's actual binary layout (CentralLegacyCFGBUFF) +/// +/// This struct matches Central's cbCFGBUFF field order EXACTLY (from cbhwlib.h). +/// It is NOT the same as CereLink's cbConfigBuffer (which reorders fields and adds +/// instrument_status). This struct is used in CENTRAL_COMPAT mode to read Central's +/// shared memory as a CLIENT. +/// +/// Key differences from CereLink's cbConfigBuffer: +/// - optiontable/colortable: 3rd/4th fields here (after sysflags), last fields in CereLink +/// - instrument_status: absent here (Central has no such concept) +/// - isLnc: after isWaveform here, before chaninfo in CereLink +/// - hwndCentral: omitted (at end, variable size, not needed) +/// +struct CentralLegacyCFGBUFF { + uint32_t version; + uint32_t sysflags; + cbOPTIONTABLE optiontable; + cbCOLORTABLE colortable; + cbPKT_SYSINFO sysinfo; + cbPKT_PROCINFO procinfo[cbMAXPROCS]; + cbPKT_BANKINFO bankinfo[cbMAXPROCS][cbMAXBANKS]; + cbPKT_GROUPINFO groupinfo[cbMAXPROCS][cbMAXGROUPS]; + cbPKT_FILTINFO filtinfo[cbMAXPROCS][cbMAXFILTS]; + cbPKT_ADAPTFILTINFO adaptinfo[cbMAXPROCS]; + cbPKT_REFELECFILTINFO refelecinfo[cbMAXPROCS]; + cbPKT_CHANINFO chaninfo[cbMAXCHANS]; + cbSPIKE_SORTING isSortingOptions; + cbPKT_NTRODEINFO isNTrodeInfo[cbMAXNTRODES]; + cbPKT_AOUT_WAVEFORM isWaveform[AOUT_NUM_GAIN_CHANS][cbMAX_AOUT_TRIGGER]; + cbPKT_LNC isLnc[cbMAXPROCS]; + cbPKT_NPLAY isNPlay; + cbVIDEOSOURCE isVideoSource[cbMAXVIDEOSOURCE]; + cbTRACKOBJ isTrackObj[cbMAXTRACKOBJ]; + cbPKT_FILECFG fileinfo; + // hwndCentral omitted (at end, variable size, not needed by CereLink) +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Transmit buffer for outgoing packets (Global - sent to device) +/// +/// Ring buffer for packets waiting to be transmitted to device via UDP. +/// Buffer stores raw packet data as uint32_t words (Central's format). +/// +/// This is stored in a separate shared memory segment (not embedded in config buffer) +/// to match Central's architecture. +/// +struct CentralTransmitBuffer { + uint32_t transmitted; ///< How many packets have been sent + uint32_t headindex; ///< First empty position (write index) + uint32_t tailindex; ///< One past last emptied position (read index) + uint32_t last_valid_index; ///< Greatest valid starting index + uint32_t bufferlen; ///< Number of indices in buffer + uint32_t buffer[cbXMT_GLOBAL_BUFFLEN]; ///< Ring buffer for packet data +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Local transmit buffer (IPC-only packets) +/// +/// Smaller than Global buffer, used for cbSendLoopbackPacket() - packets meant only for +/// local processes, not sent to device. +/// +struct CentralTransmitBufferLocal { + uint32_t transmitted; ///< How many packets have been sent + uint32_t headindex; ///< First empty position (write index) + uint32_t tailindex; ///< One past last emptied position (read index) + uint32_t last_valid_index; ///< Greatest valid starting index + uint32_t bufferlen; ///< Number of indices in buffer + uint32_t buffer[cbXMT_LOCAL_BUFFLEN]; ///< Ring buffer for packet data +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Spike cache buffer +/// +/// Caches recent spike packets for each channel to allow quick access without +/// scanning the entire receive buffer. +/// +struct CentralSpikeCache { + uint32_t chid; ///< Channel ID + uint32_t pktcnt; ///< Number of packets that can be saved + uint32_t pktsize; ///< Size of individual packet + uint32_t head; ///< Where to place next packet (circular) + uint32_t valid; ///< How many packets since last config + cbPKT_SPK spkpkt[cbPKT_SPKCACHEPKTCNT]; ///< Circular buffer of cached spikes +}; + +struct CentralSpikeBuffer { + uint32_t flags; ///< Status flags + uint32_t chidmax; ///< Maximum channel ID + uint32_t linesize; ///< Size of each cache line + uint32_t spkcount; ///< Total spike count + CentralSpikeCache cache[cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief PC Status buffer (flattened from cbPcStatus class) +/// +/// IMPROVEMENT: Flattened to C struct for ABI stability and cross-compiler compatibility. +/// Central uses a C++ class which is fragile across different build environments. +/// +enum class NSPStatus : uint32_t { + NSP_INIT = 0, + NSP_NOIPADDR = 1, + NSP_NOREPLY = 2, + NSP_FOUND = 3, + NSP_INVALID = 4 +}; + +struct CentralPCStatus { + // Public data + cbPKT_UNIT_SELECTION isSelection[cbMAXPROCS]; ///< Unit selection per instrument + + // Status fields (was private in cbPcStatus) + int32_t m_iBlockRecording; ///< Recording block counter + uint32_t m_nPCStatusFlags; ///< PC status flags + uint32_t m_nNumFEChans; ///< Number of FE channels + uint32_t m_nNumAnainChans; ///< Number of analog input channels + uint32_t m_nNumAnalogChans; ///< Number of analog channels + uint32_t m_nNumAoutChans; ///< Number of analog output channels + uint32_t m_nNumAudioChans; ///< Number of audio channels + uint32_t m_nNumAnalogoutChans; ///< Number of analog output channels + uint32_t m_nNumDiginChans; ///< Number of digital input channels + uint32_t m_nNumSerialChans; ///< Number of serial channels + uint32_t m_nNumDigoutChans; ///< Number of digital output channels + uint32_t m_nNumTotalChans; ///< Total channel count + NSPStatus m_nNspStatus[cbMAXPROCS]; ///< NSP status per instrument + uint32_t m_nNumNTrodesPerInstrument[cbMAXPROCS];///< NTrode count per instrument + uint32_t m_nGeminiSystem; ///< Gemini system flag +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Receive buffer for incoming packets (simplified for Phase 2) +/// +struct CentralReceiveBuffer { + uint32_t received; ///< Number of packets received + PROCTIME lasttime; ///< Last timestamp + uint32_t headwrap; ///< Head wrap counter + uint32_t headindex; ///< Current head index + uint32_t buffer[cbRECBUFFLEN]; ///< Packet buffer +}; + +} // namespace central_v3_11 + +} // namespace cbshm + +#pragma pack(pop) + +#endif // CBSHMEM_CENTRAL_TYPES_V3_11_H From cb348b7668d10c519ddb5829370334e3631d4fba Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Tue, 19 May 2026 14:26:35 -0600 Subject: [PATCH 08/62] Convert macros to global constants in cbproto Macros in cbproto collide with names in central_types/ matching those in Central's source, so switch to variables to respect namespaces. Add annotations of version differences with 'VER:' --- src/cbproto/include/cbproto/config.h | 6 - src/cbproto/include/cbproto/connection.h | 8 - src/cbproto/include/cbproto/types.h | 1302 +++++++++++----------- 3 files changed, 623 insertions(+), 693 deletions(-) diff --git a/src/cbproto/include/cbproto/config.h b/src/cbproto/include/cbproto/config.h index 284a6866..b1dc59ee 100644 --- a/src/cbproto/include/cbproto/config.h +++ b/src/cbproto/include/cbproto/config.h @@ -18,12 +18,6 @@ #include -// Constants not yet in types.h but needed for config structure -// TODO: Move these to types.h when updating from upstream -#ifndef cbMAXBANKS -#define cbMAXBANKS 15 ///< cbNUM_FE_BANKS(8) + ANAIN(1) + ANAOUT(1) + AUDOUT(1) + DIGIN(1) + SERIAL(1) + DIGOUT(1) -#endif - namespace cbproto { /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/cbproto/include/cbproto/connection.h b/src/cbproto/include/cbproto/connection.h index 1f6e43df..170fed84 100644 --- a/src/cbproto/include/cbproto/connection.h +++ b/src/cbproto/include/cbproto/connection.h @@ -24,10 +24,6 @@ #include -#ifdef __cplusplus -extern "C" { -#endif - /////////////////////////////////////////////////////////////////////////////////////////////////// /// @name Device Type Enumeration /// @brief Enumeration of supported Cerebus device types @@ -108,8 +104,4 @@ typedef enum cbproto_group_rate { /// @} -#ifdef __cplusplus -} -#endif - #endif // CBPROTO_CONNECTION_H diff --git a/src/cbproto/include/cbproto/types.h b/src/cbproto/include/cbproto/types.h index c9736dec..c9afdb90 100644 --- a/src/cbproto/include/cbproto/types.h +++ b/src/cbproto/include/cbproto/types.h @@ -23,15 +23,13 @@ #pragma pack(push, 1) #ifdef __cplusplus -extern "C" { -#endif /////////////////////////////////////////////////////////////////////////////////////////////////// /// @name Protocol Version /// @{ -#define cbVERSION_MAJOR 4 -#define cbVERSION_MINOR 2 +constexpr uint32_t cbVERSION_MAJOR = 4; +constexpr uint32_t cbVERSION_MINOR = 2; /// @} @@ -55,38 +53,23 @@ typedef int16_t A2D_DATA; /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @name Maximum Entity Ranges +/// @name Maximum Entity Ranges #1 /// /// Ground truth from upstream/cbproto/cbproto.h lines 237-262 /// These define the maximum number of instruments, channels, etc. /// @{ -#define cbNSP1 1 ///< First instrument ID (1-based) -#define cbNSP2 2 ///< Second instrument ID (1-based) -#define cbNSP3 3 ///< Third instrument ID (1-based) -#define cbNSP4 4 ///< Fourth instrument ID (1-based) - -#define cbMAXOPEN 4 ///< Maximum number of open cbhwlib's (instruments) -#define cbMAXPROCS 1 ///< Number of processors per NSP - -#define cbNUM_FE_CHANS 256 ///< Front-end channels per NSP - -#define cbRAWGROUP 6 ///< Group number for raw data feed -#define cbMAXGROUPS 8 ///< Number of sample rate groups -#define cbMAXFILTS 32 ///< Maximum number of filters -#define cbFIRST_DIGITAL_FILTER 13 ///< (0-based) filter number, must be less than cbMAXFILTS -#define cbNUM_DIGITAL_FILTERS 4 ///< Number of custom digital filters -#define cbMAXHOOPS 4 ///< Maximum number of hoops for spike sorting -#define cbMAXSITES 4 ///< Maximum number of electrodes in an n-trode group -#define cbMAXSITEPLOTS ((cbMAXSITES - 1) * cbMAXSITES / 2) ///< Combination of 2 out of n -#define cbMAXUNITS 5 ///< Maximum number of sorted units per channel -#define cbMAXNTRODES (cbNUM_ANALOG_CHANS / 2) ///< Maximum n-trodes (stereotrode minimum) -#define cbMAX_PNTS 128 ///< Maximum spike waveform points -#define cbMAXVIDEOSOURCE 1 ///< Maximum number of video sources -#define cbMAXTRACKOBJ 20 ///< Maximum number of trackable objects -#define cbMAX_AOUT_TRIGGER 5 ///< Maximum number of per-channel (analog output, or digital output) triggers +constexpr uint32_t cbNSP1 = 1; ///< First instrument ID (1-based) +constexpr uint32_t cbNSP2 = 2; ///< Second instrument ID (1-based) +constexpr uint32_t cbNSP3 = 3; ///< Third instrument ID (1-based) +constexpr uint32_t cbNSP4 = 4; ///< Fourth instrument ID (1-based) -/// @} +constexpr uint32_t cbMAXOPEN = 4; ///< Maximum number of open cbhwlib's (instruments) +constexpr uint32_t cbMAXPROCS = 1; ///< Number of processors per NSP + +constexpr uint32_t cbNUM_FE_CHANS = 256; ///< Front-end channels per NSP + +// @} /////////////////////////////////////////////////////////////////////////////////////////////////// /// @name Channel Counts @@ -95,43 +78,67 @@ typedef int16_t A2D_DATA; /// Note: Some channel counts depend on cbMAXPROCS /// @{ -#define cbNUM_ANAIN_CHANS (16 * cbMAXPROCS) ///< Analog input channels -#define cbNUM_ANALOG_CHANS (cbNUM_FE_CHANS + cbNUM_ANAIN_CHANS) ///< Total analog inputs -#define cbNUM_ANAOUT_CHANS (4 * cbMAXPROCS) ///< Analog output channels -#define cbNUM_AUDOUT_CHANS (2 * cbMAXPROCS) ///< Audio output channels -#define cbNUM_ANALOGOUT_CHANS (cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS) ///< Total analog outputs -#define cbNUM_DIGIN_CHANS (1 * cbMAXPROCS) ///< Digital input channels -#define cbNUM_SERIAL_CHANS (1 * cbMAXPROCS) ///< Serial input channels -#define cbNUM_DIGOUT_CHANS (4 * cbMAXPROCS) ///< Digital output channels +constexpr uint32_t cbNUM_ANAIN_CHANS = (16 * cbMAXPROCS); ///< Analog input channels +constexpr uint32_t cbNUM_ANALOG_CHANS = (cbNUM_FE_CHANS + cbNUM_ANAIN_CHANS); ///< Total analog inputs +constexpr uint32_t cbNUM_ANAOUT_CHANS = (4 * cbMAXPROCS); ///< Analog output channels +constexpr uint32_t cbNUM_AUDOUT_CHANS = (2 * cbMAXPROCS); ///< Audio output channels +constexpr uint32_t cbNUM_ANALOGOUT_CHANS = (cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS); ///< Total analog outputs +constexpr uint32_t cbNUM_DIGIN_CHANS = (1 * cbMAXPROCS); ///< Digital input channels +constexpr uint32_t cbNUM_SERIAL_CHANS = (1 * cbMAXPROCS); ///< Serial input channels +constexpr uint32_t cbNUM_DIGOUT_CHANS = (4 * cbMAXPROCS); ///< Digital output channels /// @brief Number of analog/audio output channels with gain /// This is the number of AOUT channels with gain. Conveniently, the 4 Analog Outputs /// and the 2 Audio Outputs are right next to each other in the channel numbering sequence. -#define AOUT_NUM_GAIN_CHANS (cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS) +constexpr uint32_t AOUT_NUM_GAIN_CHANS = (cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS); /// @brief Total number of channels -#define cbMAXCHANS (cbNUM_ANALOG_CHANS + cbNUM_ANALOGOUT_CHANS + \ - cbNUM_DIGIN_CHANS + cbNUM_SERIAL_CHANS + cbNUM_DIGOUT_CHANS) +constexpr uint32_t cbMAXCHANS = (cbNUM_ANALOG_CHANS + cbNUM_ANALOGOUT_CHANS + \ + cbNUM_DIGIN_CHANS + cbNUM_SERIAL_CHANS + cbNUM_DIGOUT_CHANS); -#define cbFIRST_FE_CHAN 0 ///< First Front end channel (0-based) +constexpr uint32_t cbFIRST_FE_CHAN = 0; ///< First Front end channel (0-based) // Bank definitions - if any channel types exceed cbCHAN_PER_BANK, banks must be increased -#define cbCHAN_PER_BANK 32 ///< Channels per bank -#define cbNUM_FE_BANKS (cbNUM_FE_CHANS / cbCHAN_PER_BANK) ///< Front end banks -#define cbNUM_ANAIN_BANKS 1 ///< Analog Input banks -#define cbNUM_ANAOUT_BANKS 1 ///< Analog Output banks -#define cbNUM_AUDOUT_BANKS 1 ///< Audio Output banks -#define cbNUM_DIGIN_BANKS 1 ///< Digital Input banks -#define cbNUM_SERIAL_BANKS 1 ///< Serial Input banks -#define cbNUM_DIGOUT_BANKS 1 ///< Digital Output banks - -#define cbMAXBANKS (cbNUM_FE_BANKS + cbNUM_ANAIN_BANKS + cbNUM_ANAOUT_BANKS + \ +constexpr uint32_t cbCHAN_PER_BANK = 32; ///< Channels per bank +constexpr uint32_t cbNUM_FE_BANKS = (cbNUM_FE_CHANS / cbCHAN_PER_BANK); ///< Front end banks +constexpr uint32_t cbNUM_ANAIN_BANKS = 1; ///< Analog Input banks +constexpr uint32_t cbNUM_ANAOUT_BANKS = 1; ///< Analog Output banks +constexpr uint32_t cbNUM_AUDOUT_BANKS = 1; ///< Audio Output banks +constexpr uint32_t cbNUM_DIGIN_BANKS = 1; ///< Digital Input banks +constexpr uint32_t cbNUM_SERIAL_BANKS = 1; ///< Serial Input banks +constexpr uint32_t cbNUM_DIGOUT_BANKS = 1; ///< Digital Output banks + +constexpr uint32_t cbMAXBANKS = (cbNUM_FE_BANKS + cbNUM_ANAIN_BANKS + cbNUM_ANAOUT_BANKS + \ cbNUM_AUDOUT_BANKS + cbNUM_DIGIN_BANKS + cbNUM_SERIAL_BANKS + \ - cbNUM_DIGOUT_BANKS) + cbNUM_DIGOUT_BANKS); + +constexpr uint32_t SCALE_LNC_COUNT = 17; +constexpr uint32_t SCALE_CONTINUOUS_COUNT = 17; +constexpr uint32_t SCALE_SPIKE_COUNT = 23; + +/// @} -#define SCALE_LNC_COUNT 17 -#define SCALE_CONTINUOUS_COUNT 17 -#define SCALE_SPIKE_COUNT 23 +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Maximum Entity Ranges #2 +/// +/// Ground truth from upstream/cbproto/cbproto.h lines 237-262 +/// These define the maximum number of instruments, channels, etc. +/// @{ + +constexpr uint32_t cbRAWGROUP = 6; ///< Group number for raw data feed +constexpr uint32_t cbMAXGROUPS = 8; ///< Number of sample rate groups +constexpr uint32_t cbMAXFILTS = 32; ///< Maximum number of filters +constexpr uint32_t cbFIRST_DIGITAL_FILTER = 13; ///< (0-based) filter number, must be less than cbMAXFILTS +constexpr uint32_t cbNUM_DIGITAL_FILTERS = 4; ///< Number of custom digital filters +constexpr uint32_t cbMAXHOOPS = 4; ///< Maximum number of hoops for spike sorting +constexpr uint32_t cbMAXSITES = 4; ///< Maximum number of electrodes in an n-trode group +constexpr uint32_t cbMAXSITEPLOTS = ((cbMAXSITES - 1) * cbMAXSITES / 2); ///< Combination of 2 out of n +constexpr uint32_t cbMAXUNITS = 5; ///< Maximum number of sorted units per channel +constexpr uint32_t cbMAXNTRODES = (cbNUM_ANALOG_CHANS / 2); ///< Maximum n-trodes (stereotrode minimum) +constexpr uint32_t cbMAX_PNTS = 128; ///< Maximum spike waveform points +constexpr uint32_t cbMAXVIDEOSOURCE = 1; ///< Maximum number of video sources +constexpr uint32_t cbMAXTRACKOBJ = 20; ///< Maximum number of trackable objects +constexpr uint32_t cbMAX_AOUT_TRIGGER = 5; ///< Maximum number of per-channel (analog output, or digital output) triggers /// @} @@ -141,32 +148,32 @@ typedef int16_t A2D_DATA; /// Ground truth from upstream/cbproto/cbproto.h lines 193-211 /// @{ -#define cbNET_UDP_ADDR_INST "192.168.137.1" ///< Cerebus default address -#define cbNET_UDP_ADDR_CNT "192.168.137.128" ///< Gemini NSP default control address -#define cbNET_UDP_ADDR_BCAST "192.168.137.255" ///< NSP default broadcast address -#define cbNET_UDP_PORT_BCAST 51002 ///< Neuroflow Data Port -#define cbNET_UDP_PORT_CNT 51001 ///< Neuroflow Control Port +inline constexpr const char* cbNET_UDP_ADDR_INST = "192.168.137.1"; ///< Cerebus default address +inline constexpr const char* cbNET_UDP_ADDR_CNT = "192.168.137.128"; ///< Gemini NSP default control address +inline constexpr const char* cbNET_UDP_ADDR_BCAST = "192.168.137.255"; ///< NSP default broadcast address +constexpr uint32_t cbNET_UDP_PORT_BCAST = 51002; ///< Neuroflow Data Port +constexpr uint32_t cbNET_UDP_PORT_CNT = 51001; ///< Neuroflow Control Port // Maximum UDP datagram size used to transport cerebus packets, taken from MTU size -#define cbCER_UDP_SIZE_MAX 58080 ///< Note that multiple packets may reside in one udp datagram as aggregate +constexpr uint32_t cbCER_UDP_SIZE_MAX = 58080; ///< Note that multiple packets may reside in one udp datagram as aggregate // Gemini network configuration -#define cbNET_TCP_PORT_GEMINI 51005 ///< Neuroflow Data Port -#define cbNET_TCP_ADDR_GEMINI_HUB "192.168.137.200" ///< NSP default control address - -#define cbNET_UDP_ADDR_HOST "192.168.137.199" ///< Cerebus (central) default address -#define cbNET_UDP_ADDR_GEMINI_NSP "192.168.137.128" ///< NSP default control address -#define cbNET_UDP_ADDR_GEMINI_HUB "192.168.137.200" ///< HUB default control address -#define cbNET_UDP_ADDR_GEMINI_HUB2 "192.168.137.201" ///< HUB2 default control address -#define cbNET_UDP_ADDR_GEMINI_HUB3 "192.168.137.202" ///< HUB3 default control address -#define cbNET_UDP_PORT_GEMINI_NSP 51001 ///< Gemini NSP Port -#define cbNET_UDP_PORT_GEMINI_HUB 51002 ///< Gemini HUB Port -#define cbNET_UDP_PORT_GEMINI_HUB2 51003 ///< Gemini HUB2 Port -#define cbNET_UDP_PORT_GEMINI_HUB3 51004 ///< Gemini HUB3 Port +constexpr uint32_t cbNET_TCP_PORT_GEMINI = 51005; ///< Neuroflow Data Port +inline constexpr const char* cbNET_TCP_ADDR_GEMINI_HUB = "192.168.137.200"; ///< NSP default control address + +inline constexpr const char* cbNET_UDP_ADDR_HOST = "192.168.137.199"; ///< Cerebus (central) default address +inline constexpr const char* cbNET_UDP_ADDR_GEMINI_NSP = "192.168.137.128"; ///< NSP default control address +inline constexpr const char* cbNET_UDP_ADDR_GEMINI_HUB = "192.168.137.200"; ///< HUB default control address +inline constexpr const char* cbNET_UDP_ADDR_GEMINI_HUB2 = "192.168.137.201"; ///< HUB2 default control address +inline constexpr const char* cbNET_UDP_ADDR_GEMINI_HUB3 = "192.168.137.202"; ///< HUB3 default control address +constexpr uint32_t cbNET_UDP_PORT_GEMINI_NSP = 51001; ///< Gemini NSP Port +constexpr uint32_t cbNET_UDP_PORT_GEMINI_HUB = 51002; ///< Gemini HUB Port +constexpr uint32_t cbNET_UDP_PORT_GEMINI_HUB2 = 51003; ///< Gemini HUB2 Port +constexpr uint32_t cbNET_UDP_PORT_GEMINI_HUB3 = 51004; ///< Gemini HUB3 Port // Protocol types -#define PROTOCOL_UDP 0 ///< UDP protocol -#define PROTOCOL_TCP 1 ///< TCP protocol +constexpr uint32_t PROTOCOL_UDP = 0; ///< UDP protocol +constexpr uint32_t PROTOCOL_TCP = 1; ///< TCP protocol /// @} @@ -174,12 +181,12 @@ typedef int16_t A2D_DATA; /// @name String Length Constants /// @{ -#define cbLEN_STR_UNIT 8 ///< Length of unit string -#define cbLEN_STR_LABEL 16 ///< Length of label string -#define cbLEN_STR_FILT_LABEL 16 ///< Length of filter label string -#define cbLEN_STR_IDENT 64 ///< Length of identity string -#define cbLEN_STR_COMMENT 256 ///< Length of comment string -#define cbMAX_COMMENT 128 ///< Maximum comment length (must be multiple of 4) +constexpr uint32_t cbLEN_STR_UNIT = 8; ///< Length of unit string +constexpr uint32_t cbLEN_STR_LABEL = 16; ///< Length of label string +constexpr uint32_t cbLEN_STR_FILT_LABEL = 16; ///< Length of filter label string +constexpr uint32_t cbLEN_STR_IDENT = 64; ///< Length of identity string +constexpr uint32_t cbLEN_STR_COMMENT = 256; ///< Length of comment string +constexpr uint32_t cbMAX_COMMENT = 128; ///< Maximum comment length (must be multiple of 4) /// @} @@ -189,33 +196,33 @@ typedef int16_t A2D_DATA; typedef unsigned int cbRESULT; -#define cbRESULT_OK 0 ///< Function executed normally -#define cbRESULT_NOLIBRARY 1 ///< The library was not properly initialized -#define cbRESULT_NOCENTRALAPP 2 ///< Unable to access the central application -#define cbRESULT_LIBINITERROR 3 ///< Error attempting to initialize library error -#define cbRESULT_MEMORYUNAVAIL 4 ///< Not enough memory available to complete the operation -#define cbRESULT_INVALIDADDRESS 5 ///< Invalid Processor or Bank address -#define cbRESULT_INVALIDCHANNEL 6 ///< Invalid channel ID passed to function -#define cbRESULT_INVALIDFUNCTION 7 ///< Channel exists, but requested function is not available -#define cbRESULT_NOINTERNALCHAN 8 ///< No internal channels available to connect hardware stream -#define cbRESULT_HARDWAREOFFLINE 9 ///< Hardware is offline or unavailable -#define cbRESULT_DATASTREAMING 10 ///< Hardware is streaming data and cannot be configured -#define cbRESULT_NONEWDATA 11 ///< There is no new data to be read in -#define cbRESULT_DATALOST 12 ///< The Central App incoming data buffer has wrapped -#define cbRESULT_INVALIDNTRODE 13 ///< Invalid NTrode number passed to function -#define cbRESULT_BUFRECALLOCERR 14 ///< Receive buffer could not be allocated -#define cbRESULT_BUFGXMTALLOCERR 15 ///< Global transmit buffer could not be allocated -#define cbRESULT_BUFLXMTALLOCERR 16 ///< Local transmit buffer could not be allocated -#define cbRESULT_BUFCFGALLOCERR 17 ///< Configuration buffer could not be allocated -#define cbRESULT_BUFPCSTATALLOCERR 18 ///< PC status buffer could not be allocated -#define cbRESULT_BUFSPKALLOCERR 19 ///< Spike cache buffer could not be allocated -#define cbRESULT_EVSIGERR 20 ///< Couldn't create shared event signal -#define cbRESULT_SOCKERR 21 ///< Generic socket creation error -#define cbRESULT_SOCKOPTERR 22 ///< Socket option error (possibly permission issue) -#define cbRESULT_SOCKMEMERR 23 ///< Socket memory assignment error -#define cbRESULT_INSTINVALID 24 ///< Invalid range or instrument address -#define cbRESULT_SOCKBIND 25 ///< Cannot bind to any address (possibly no Instrument network) -#define cbRESULT_SYSLOCK 26 ///< Cannot (un)lock the system resources (possibly resource busy) +constexpr uint32_t cbRESULT_OK = 0; ///< Function executed normally +constexpr uint32_t cbRESULT_NOLIBRARY = 1; ///< The library was not properly initialized +constexpr uint32_t cbRESULT_NOCENTRALAPP = 2; ///< Unable to access the central application +constexpr uint32_t cbRESULT_LIBINITERROR = 3; ///< Error attempting to initialize library error +constexpr uint32_t cbRESULT_MEMORYUNAVAIL = 4; ///< Not enough memory available to complete the operation +constexpr uint32_t cbRESULT_INVALIDADDRESS = 5; ///< Invalid Processor or Bank address +constexpr uint32_t cbRESULT_INVALIDCHANNEL = 6; ///< Invalid channel ID passed to function +constexpr uint32_t cbRESULT_INVALIDFUNCTION = 7; ///< Channel exists, but requested function is not available +constexpr uint32_t cbRESULT_NOINTERNALCHAN = 8; ///< No internal channels available to connect hardware stream +constexpr uint32_t cbRESULT_HARDWAREOFFLINE = 9; ///< Hardware is offline or unavailable +constexpr uint32_t cbRESULT_DATASTREAMING = 10; ///< Hardware is streaming data and cannot be configured +constexpr uint32_t cbRESULT_NONEWDATA = 11; ///< There is no new data to be read in +constexpr uint32_t cbRESULT_DATALOST = 12; ///< The Central App incoming data buffer has wrapped +constexpr uint32_t cbRESULT_INVALIDNTRODE = 13; ///< Invalid NTrode number passed to function +constexpr uint32_t cbRESULT_BUFRECALLOCERR = 14; ///< Receive buffer could not be allocated +constexpr uint32_t cbRESULT_BUFGXMTALLOCERR = 15; ///< Global transmit buffer could not be allocated +constexpr uint32_t cbRESULT_BUFLXMTALLOCERR = 16; ///< Local transmit buffer could not be allocated +constexpr uint32_t cbRESULT_BUFCFGALLOCERR = 17; ///< Configuration buffer could not be allocated +constexpr uint32_t cbRESULT_BUFPCSTATALLOCERR = 18; ///< PC status buffer could not be allocated +constexpr uint32_t cbRESULT_BUFSPKALLOCERR = 19; ///< Spike cache buffer could not be allocated +constexpr uint32_t cbRESULT_EVSIGERR = 20; ///< Couldn't create shared event signal +constexpr uint32_t cbRESULT_SOCKERR = 21; ///< Generic socket creation error +constexpr uint32_t cbRESULT_SOCKOPTERR = 22; ///< Socket option error (possibly permission issue) +constexpr uint32_t cbRESULT_SOCKMEMERR = 23; ///< Socket memory assignment error +constexpr uint32_t cbRESULT_INSTINVALID = 24; ///< Invalid range or instrument address +constexpr uint32_t cbRESULT_SOCKBIND = 25; ///< Cannot bind to any address (possibly no Instrument network) +constexpr uint32_t cbRESULT_SYSLOCK = 26; ///< Cannot (un)lock the system resources (possibly resource busy) /// @} @@ -230,15 +237,15 @@ typedef unsigned int cbRESULT; typedef struct { PROCTIME time; ///< System clock timestamp uint16_t chid; ///< Channel identifier - uint16_t type; ///< Packet type + uint16_t type; ///< Packet type // VER: 4.1+, type is uint16_t instead of uint8_t uint16_t dlen; ///< Length of data field in 32-bit chunks uint8_t instrument; ///< Instrument number (0-based in packet, despite cbNSP1=1!) uint8_t reserved; ///< Reserved for future use } cbPKT_HEADER; -#define cbPKT_MAX_SIZE 1024 ///< Maximum packet size in bytes -#define cbPKT_HEADER_SIZE sizeof(cbPKT_HEADER) ///< Packet header size in bytes -#define cbPKT_HEADER_32SIZE (cbPKT_HEADER_SIZE / 4) ///< Packet header size in uint32_t's +constexpr uint32_t cbPKT_MAX_SIZE = 1024; ///< Maximum packet size in bytes +constexpr uint32_t cbPKT_HEADER_SIZE = sizeof(cbPKT_HEADER); ///< Packet header size in bytes +constexpr uint32_t cbPKT_HEADER_32SIZE = (cbPKT_HEADER_SIZE / 4); ///< Packet header size in uint32_t's /// @} @@ -263,6 +270,8 @@ typedef struct { /////////////////////////////////////////////////////////////////////////////////////////////////// /// @name Old Packet Header and Generic (for CCF file compatibility) /// +/// VER: 3.11 and older +/// /// Ground truth from upstream/cbproto/cbproto.h lines 385-420 /// @{ @@ -276,7 +285,7 @@ typedef struct { uint8_t dlen; ///< length of data field in 32-bit chunks } cbPKT_HEADER_OLD; -#define cbPKT_HEADER_SIZE_OLD sizeof(cbPKT_HEADER_OLD) ///< define the size of the old packet header in bytes +constexpr uint32_t cbPKT_HEADER_SIZE_OLD = sizeof(cbPKT_HEADER_OLD); ///< define the size of the old packet header in bytes /// @brief Old Generic Cerebus packet data structure (1024 bytes total) /// @@ -296,14 +305,14 @@ typedef struct { /// @{ // Filter type flags (used in cbFILTDESC hptype/lptype fields) -#define cbFILTTYPE_PHYSICAL 0x0001 -#define cbFILTTYPE_DIGITAL 0x0002 -#define cbFILTTYPE_ADAPTIVE 0x0004 -#define cbFILTTYPE_NONLINEAR 0x0008 -#define cbFILTTYPE_BUTTERWORTH 0x0100 -#define cbFILTTYPE_CHEBYCHEV 0x0200 -#define cbFILTTYPE_BESSEL 0x0400 -#define cbFILTTYPE_ELLIPTICAL 0x0800 +constexpr uint32_t cbFILTTYPE_PHYSICAL = 0x0001; +constexpr uint32_t cbFILTTYPE_DIGITAL = 0x0002; +constexpr uint32_t cbFILTTYPE_ADAPTIVE = 0x0004; +constexpr uint32_t cbFILTTYPE_NONLINEAR = 0x0008; +constexpr uint32_t cbFILTTYPE_BUTTERWORTH = 0x0100; +constexpr uint32_t cbFILTTYPE_CHEBYCHEV = 0x0200; +constexpr uint32_t cbFILTTYPE_BESSEL = 0x0400; +constexpr uint32_t cbFILTTYPE_ELLIPTICAL = 0x0800; /// @brief Filter description structure /// @@ -418,161 +427,161 @@ typedef struct { /// @{ // System packets -#define cbPKTTYPE_SYSHEARTBEAT 0x00 ///< System heartbeat packet -#define cbPKTTYPE_SYSPROTOCOLMONITOR 0x01 ///< Protocol monitoring packet -#define cbPKTTYPE_PREVREPSTREAM 0x02 ///< Preview reply stream -#define cbPKTTYPE_PREVREP 0x03 ///< Preview reply -#define cbPKTTYPE_PREVREPLNC 0x04 ///< Preview reply LNC -#define cbPKTTYPE_REPCONFIGALL 0x08 ///< Response that NSP got your request -#define cbPKTTYPE_SYSREP 0x10 ///< System reply -#define cbPKTTYPE_SYSREPSPKLEN 0x11 ///< System reply spike length -#define cbPKTTYPE_SYSREPRUNLEV 0x12 ///< System reply runlevel +constexpr uint32_t cbPKTTYPE_SYSHEARTBEAT = 0x00; ///< System heartbeat packet +constexpr uint32_t cbPKTTYPE_SYSPROTOCOLMONITOR = 0x01; ///< Protocol monitoring packet +constexpr uint32_t cbPKTTYPE_PREVREPSTREAM = 0x02; ///< Preview reply stream +constexpr uint32_t cbPKTTYPE_PREVREP = 0x03; ///< Preview reply +constexpr uint32_t cbPKTTYPE_PREVREPLNC = 0x04; ///< Preview reply LNC +constexpr uint32_t cbPKTTYPE_REPCONFIGALL = 0x08; ///< Response that NSP got your request +constexpr uint32_t cbPKTTYPE_SYSREP = 0x10; ///< System reply +constexpr uint32_t cbPKTTYPE_SYSREPSPKLEN = 0x11; ///< System reply spike length +constexpr uint32_t cbPKTTYPE_SYSREPRUNLEV = 0x12; ///< System reply runlevel // Processor, bank, and filter information packets -#define cbPKTTYPE_PROCREP 0x21 ///< Processor information reply -#define cbPKTTYPE_BANKREP 0x22 ///< Bank information reply -#define cbPKTTYPE_FILTREP 0x23 ///< Filter information reply -#define cbPKTTYPE_CHANRESETREP 0x24 ///< Channel reset reply -#define cbPKTTYPE_ADAPTFILTREP 0x25 ///< Adaptive filter reply -#define cbPKTTYPE_REFELECFILTREP 0x26 ///< Reference electrode filter reply -#define cbPKTTYPE_REPNTRODEINFO 0x27 ///< N-Trode information reply -#define cbPKTTYPE_LNCREP 0x28 ///< LNC reply -#define cbPKTTYPE_VIDEOSYNCHREP 0x29 ///< Video sync reply +constexpr uint32_t cbPKTTYPE_PROCREP = 0x21; ///< Processor information reply +constexpr uint32_t cbPKTTYPE_BANKREP = 0x22; ///< Bank information reply +constexpr uint32_t cbPKTTYPE_FILTREP = 0x23; ///< Filter information reply +constexpr uint32_t cbPKTTYPE_CHANRESETREP = 0x24; ///< Channel reset reply +constexpr uint32_t cbPKTTYPE_ADAPTFILTREP = 0x25; ///< Adaptive filter reply +constexpr uint32_t cbPKTTYPE_REFELECFILTREP = 0x26; ///< Reference electrode filter reply +constexpr uint32_t cbPKTTYPE_REPNTRODEINFO = 0x27; ///< N-Trode information reply +constexpr uint32_t cbPKTTYPE_LNCREP = 0x28; ///< LNC reply +constexpr uint32_t cbPKTTYPE_VIDEOSYNCHREP = 0x29; ///< Video sync reply // Sample group and configuration packets -#define cbPKTTYPE_GROUPREP 0x30 ///< Sample group information reply -#define cbPKTTYPE_COMMENTREP 0x31 ///< Comment reply -#define cbPKTTYPE_NMREP 0x32 ///< NeuroMotive (NM) reply -#define cbPKTTYPE_WAVEFORMREP 0x33 ///< Waveform reply -#define cbPKTTYPE_STIMULATIONREP 0x34 ///< Stimulation reply +constexpr uint32_t cbPKTTYPE_GROUPREP = 0x30; ///< Sample group information reply +constexpr uint32_t cbPKTTYPE_COMMENTREP = 0x31; ///< Comment reply +constexpr uint32_t cbPKTTYPE_NMREP = 0x32; ///< NeuroMotive (NM) reply +constexpr uint32_t cbPKTTYPE_WAVEFORMREP = 0x33; ///< Waveform reply +constexpr uint32_t cbPKTTYPE_STIMULATIONREP = 0x34; ///< Stimulation reply // Channel information packets - Reply (0x40-0x4F) -#define cbPKTTYPE_CHANREP 0x40 ///< Channel information reply -#define cbPKTTYPE_CHANREPLABEL 0x41 ///< Channel label reply -#define cbPKTTYPE_CHANREPSCALE 0x42 ///< Channel scale reply -#define cbPKTTYPE_CHANREPDOUT 0x43 ///< Channel digital output reply -#define cbPKTTYPE_CHANREPDINP 0x44 ///< Channel digital input reply -#define cbPKTTYPE_CHANREPAOUT 0x45 ///< Channel analog output reply -#define cbPKTTYPE_CHANREPDISP 0x46 ///< Channel display reply -#define cbPKTTYPE_CHANREPAINP 0x47 ///< Channel analog input reply -#define cbPKTTYPE_CHANREPSMP 0x48 ///< Channel sampling reply -#define cbPKTTYPE_CHANREPSPK 0x49 ///< Channel spike reply -#define cbPKTTYPE_CHANREPSPKTHR 0x4A ///< Channel spike threshold reply -#define cbPKTTYPE_CHANREPSPKHPS 0x4B ///< Channel spike hoops reply -#define cbPKTTYPE_CHANREPUNITOVERRIDES 0x4C ///< Channel unit overrides reply -#define cbPKTTYPE_CHANREPNTRODEGROUP 0x4D ///< Channel n-trode group reply -#define cbPKTTYPE_CHANREPREJECTAMPLITUDE 0x4E ///< Channel reject amplitude reply -#define cbPKTTYPE_CHANREPAUTOTHRESHOLD 0x4F ///< Channel auto threshold reply +constexpr uint32_t cbPKTTYPE_CHANREP = 0x40; ///< Channel information reply +constexpr uint32_t cbPKTTYPE_CHANREPLABEL = 0x41; ///< Channel label reply +constexpr uint32_t cbPKTTYPE_CHANREPSCALE = 0x42; ///< Channel scale reply +constexpr uint32_t cbPKTTYPE_CHANREPDOUT = 0x43; ///< Channel digital output reply +constexpr uint32_t cbPKTTYPE_CHANREPDINP = 0x44; ///< Channel digital input reply +constexpr uint32_t cbPKTTYPE_CHANREPAOUT = 0x45; ///< Channel analog output reply +constexpr uint32_t cbPKTTYPE_CHANREPDISP = 0x46; ///< Channel display reply +constexpr uint32_t cbPKTTYPE_CHANREPAINP = 0x47; ///< Channel analog input reply +constexpr uint32_t cbPKTTYPE_CHANREPSMP = 0x48; ///< Channel sampling reply +constexpr uint32_t cbPKTTYPE_CHANREPSPK = 0x49; ///< Channel spike reply +constexpr uint32_t cbPKTTYPE_CHANREPSPKTHR = 0x4A; ///< Channel spike threshold reply +constexpr uint32_t cbPKTTYPE_CHANREPSPKHPS = 0x4B; ///< Channel spike hoops reply +constexpr uint32_t cbPKTTYPE_CHANREPUNITOVERRIDES = 0x4C; ///< Channel unit overrides reply +constexpr uint32_t cbPKTTYPE_CHANREPNTRODEGROUP = 0x4D; ///< Channel n-trode group reply +constexpr uint32_t cbPKTTYPE_CHANREPREJECTAMPLITUDE = 0x4E; ///< Channel reject amplitude reply +constexpr uint32_t cbPKTTYPE_CHANREPAUTOTHRESHOLD = 0x4F; ///< Channel auto threshold reply // Spike sorting packets - Reply (0x50-0x5F) -#define cbPKTTYPE_SS_MODELALLREP 0x50 ///< Spike sorting model all reply -#define cbPKTTYPE_SS_MODELREP 0x51 ///< Spike sorting model reply -#define cbPKTTYPE_SS_DETECTREP 0x52 ///< Spike sorting detect reply -#define cbPKTTYPE_SS_ARTIF_REJECTREP 0x53 ///< Spike sorting artifact reject reply -#define cbPKTTYPE_SS_NOISE_BOUNDARYREP 0x54 ///< Spike sorting noise boundary reply -#define cbPKTTYPE_SS_STATISTICSREP 0x55 ///< Spike sorting statistics reply -#define cbPKTTYPE_SS_RESETREP 0x56 ///< Spike sorting reset reply -#define cbPKTTYPE_SS_STATUSREP 0x57 ///< Spike sorting status reply -#define cbPKTTYPE_SS_RESET_MODEL_REP 0x58 ///< Spike sorting reset model reply -#define cbPKTTYPE_SS_RECALCREP 0x59 ///< Spike sorting recalculate reply -#define cbPKTTYPE_FS_BASISREP 0x5B ///< Feature space basis reply -#define cbPKTTYPE_NPLAYREP 0x5C ///< NPlay reply -#define cbPKTTYPE_SET_DOUTREP 0x5D ///< Set digital output reply -#define cbPKTTYPE_TRIGGERREP 0x5E ///< Trigger reply -#define cbPKTTYPE_VIDEOTRACKREP 0x5F ///< Video track reply +constexpr uint32_t cbPKTTYPE_SS_MODELALLREP = 0x50; ///< Spike sorting model all reply +constexpr uint32_t cbPKTTYPE_SS_MODELREP = 0x51; ///< Spike sorting model reply +constexpr uint32_t cbPKTTYPE_SS_DETECTREP = 0x52; ///< Spike sorting detect reply +constexpr uint32_t cbPKTTYPE_SS_ARTIF_REJECTREP = 0x53; ///< Spike sorting artifact reject reply +constexpr uint32_t cbPKTTYPE_SS_NOISE_BOUNDARYREP = 0x54; ///< Spike sorting noise boundary reply +constexpr uint32_t cbPKTTYPE_SS_STATISTICSREP = 0x55; ///< Spike sorting statistics reply +constexpr uint32_t cbPKTTYPE_SS_RESETREP = 0x56; ///< Spike sorting reset reply +constexpr uint32_t cbPKTTYPE_SS_STATUSREP = 0x57; ///< Spike sorting status reply +constexpr uint32_t cbPKTTYPE_SS_RESET_MODEL_REP = 0x58; ///< Spike sorting reset model reply +constexpr uint32_t cbPKTTYPE_SS_RECALCREP = 0x59; ///< Spike sorting recalculate reply +constexpr uint32_t cbPKTTYPE_FS_BASISREP = 0x5B; ///< Feature space basis reply +constexpr uint32_t cbPKTTYPE_NPLAYREP = 0x5C; ///< NPlay reply +constexpr uint32_t cbPKTTYPE_SET_DOUTREP = 0x5D; ///< Set digital output reply +constexpr uint32_t cbPKTTYPE_TRIGGERREP = 0x5E; ///< Trigger reply +constexpr uint32_t cbPKTTYPE_VIDEOTRACKREP = 0x5F; ///< Video track reply // File and configuration packets - Reply (0x60-0x6F) -#define cbPKTTYPE_REPFILECFG 0x61 ///< File configuration reply -#define cbPKTTYPE_REPUNITSELECTION 0x62 ///< Unit selection reply -#define cbPKTTYPE_LOGREP 0x63 ///< Log reply -#define cbPKTTYPE_REPPATIENTINFO 0x64 ///< Patient info reply -#define cbPKTTYPE_REPIMPEDANCE 0x65 ///< Impedance reply -#define cbPKTTYPE_REPINITIMPEDANCE 0x66 ///< Initial impedance reply -#define cbPKTTYPE_REPPOLL 0x67 ///< Poll reply -#define cbPKTTYPE_REPMAPFILE 0x68 ///< Map file reply +constexpr uint32_t cbPKTTYPE_REPFILECFG = 0x61; ///< File configuration reply +constexpr uint32_t cbPKTTYPE_REPUNITSELECTION = 0x62; ///< Unit selection reply +constexpr uint32_t cbPKTTYPE_LOGREP = 0x63; ///< Log reply +constexpr uint32_t cbPKTTYPE_REPPATIENTINFO = 0x64; ///< Patient info reply +constexpr uint32_t cbPKTTYPE_REPIMPEDANCE = 0x65; ///< Impedance reply +constexpr uint32_t cbPKTTYPE_REPINITIMPEDANCE = 0x66; ///< Initial impedance reply +constexpr uint32_t cbPKTTYPE_REPPOLL = 0x67; ///< Poll reply +constexpr uint32_t cbPKTTYPE_REPMAPFILE = 0x68; ///< Map file reply // Update packets -#define cbPKTTYPE_UPDATEREP 0x71 ///< Update reply +constexpr uint32_t cbPKTTYPE_UPDATEREP = 0x71; ///< Update reply // Preview packets - Set -#define cbPKTTYPE_PREVSETSTREAM 0x82 ///< Preview set stream -#define cbPKTTYPE_PREVSET 0x83 ///< Preview set -#define cbPKTTYPE_PREVSETLNC 0x84 ///< Preview set LNC +constexpr uint32_t cbPKTTYPE_PREVSETSTREAM = 0x82; ///< Preview set stream +constexpr uint32_t cbPKTTYPE_PREVSET = 0x83; ///< Preview set +constexpr uint32_t cbPKTTYPE_PREVSETLNC = 0x84; ///< Preview set LNC // System packets - Request (0x88-0x9F) -#define cbPKTTYPE_REQCONFIGALL 0x88 ///< Request for ALL configuration information -#define cbPKTTYPE_SYSSET 0x90 ///< System set -#define cbPKTTYPE_SYSSETSPKLEN 0x91 ///< System set spike length -#define cbPKTTYPE_SYSSETRUNLEV 0x92 ///< System set runlevel +constexpr uint32_t cbPKTTYPE_REQCONFIGALL = 0x88; ///< Request for ALL configuration information +constexpr uint32_t cbPKTTYPE_SYSSET = 0x90; ///< System set +constexpr uint32_t cbPKTTYPE_SYSSETSPKLEN = 0x91; ///< System set spike length +constexpr uint32_t cbPKTTYPE_SYSSETRUNLEV = 0x92; ///< System set runlevel // Filter and configuration packets - Set (0xA0-0xAF) -#define cbPKTTYPE_FILTSET 0xA3 ///< Filter set -#define cbPKTTYPE_CHANRESET 0xA4 ///< Channel reset -#define cbPKTTYPE_ADAPTFILTSET 0xA5 ///< Adaptive filter set -#define cbPKTTYPE_REFELECFILTSET 0xA6 ///< Reference electrode filter set -#define cbPKTTYPE_SETNTRODEINFO 0xA7 ///< N-Trode information set -#define cbPKTTYPE_LNCSET 0xA8 ///< LNC set -#define cbPKTTYPE_VIDEOSYNCHSET 0xA9 ///< Video sync set +constexpr uint32_t cbPKTTYPE_FILTSET = 0xA3; ///< Filter set +constexpr uint32_t cbPKTTYPE_CHANRESET = 0xA4; ///< Channel reset +constexpr uint32_t cbPKTTYPE_ADAPTFILTSET = 0xA5; ///< Adaptive filter set +constexpr uint32_t cbPKTTYPE_REFELECFILTSET = 0xA6; ///< Reference electrode filter set +constexpr uint32_t cbPKTTYPE_SETNTRODEINFO = 0xA7; ///< N-Trode information set +constexpr uint32_t cbPKTTYPE_LNCSET = 0xA8; ///< LNC set +constexpr uint32_t cbPKTTYPE_VIDEOSYNCHSET = 0xA9; ///< Video sync set // Sample group and waveform packets - Set (0xB0-0xBF) -#define cbPKTTYPE_GROUPSET 0xB0 ///< Sample group set -#define cbPKTTYPE_COMMENTSET 0xB1 ///< Comment set -#define cbPKTTYPE_NMSET 0xB2 ///< NeuroMotive set -#define cbPKTTYPE_WAVEFORMSET 0xB3 ///< Waveform set -#define cbPKTTYPE_STIMULATIONSET 0xB4 ///< Stimulation set +constexpr uint32_t cbPKTTYPE_GROUPSET = 0xB0; ///< Sample group set +constexpr uint32_t cbPKTTYPE_COMMENTSET = 0xB1; ///< Comment set +constexpr uint32_t cbPKTTYPE_NMSET = 0xB2; ///< NeuroMotive set +constexpr uint32_t cbPKTTYPE_WAVEFORMSET = 0xB3; ///< Waveform set +constexpr uint32_t cbPKTTYPE_STIMULATIONSET = 0xB4; ///< Stimulation set // Channel information packets - Set (0xC0-0xCF) -#define cbPKTTYPE_CHANSET 0xC0 ///< Channel information set -#define cbPKTTYPE_CHANSETLABEL 0xC1 ///< Channel label set -#define cbPKTTYPE_CHANSETSCALE 0xC2 ///< Channel scale set -#define cbPKTTYPE_CHANSETDOUT 0xC3 ///< Channel digital output set -#define cbPKTTYPE_CHANSETDINP 0xC4 ///< Channel digital input set -#define cbPKTTYPE_CHANSETAOUT 0xC5 ///< Channel analog output set -#define cbPKTTYPE_CHANSETDISP 0xC6 ///< Channel display set -#define cbPKTTYPE_CHANSETAINP 0xC7 ///< Channel analog input set -#define cbPKTTYPE_CHANSETSMP 0xC8 ///< Channel sampling set -#define cbPKTTYPE_CHANSETSPK 0xC9 ///< Channel spike set -#define cbPKTTYPE_CHANSETSPKTHR 0xCA ///< Channel spike threshold set -#define cbPKTTYPE_CHANSETSPKHPS 0xCB ///< Channel spike hoops set -#define cbPKTTYPE_CHANSETUNITOVERRIDES 0xCC ///< Channel unit overrides set -#define cbPKTTYPE_CHANSETNTRODEGROUP 0xCD ///< Channel n-trode group set -#define cbPKTTYPE_CHANSETREJECTAMPLITUDE 0xCE ///< Channel reject amplitude set -#define cbPKTTYPE_CHANSETAUTOTHRESHOLD 0xCF ///< Channel auto threshold set +constexpr uint32_t cbPKTTYPE_CHANSET = 0xC0; ///< Channel information set +constexpr uint32_t cbPKTTYPE_CHANSETLABEL = 0xC1; ///< Channel label set +constexpr uint32_t cbPKTTYPE_CHANSETSCALE = 0xC2; ///< Channel scale set +constexpr uint32_t cbPKTTYPE_CHANSETDOUT = 0xC3; ///< Channel digital output set +constexpr uint32_t cbPKTTYPE_CHANSETDINP = 0xC4; ///< Channel digital input set +constexpr uint32_t cbPKTTYPE_CHANSETAOUT = 0xC5; ///< Channel analog output set +constexpr uint32_t cbPKTTYPE_CHANSETDISP = 0xC6; ///< Channel display set +constexpr uint32_t cbPKTTYPE_CHANSETAINP = 0xC7; ///< Channel analog input set +constexpr uint32_t cbPKTTYPE_CHANSETSMP = 0xC8; ///< Channel sampling set +constexpr uint32_t cbPKTTYPE_CHANSETSPK = 0xC9; ///< Channel spike set +constexpr uint32_t cbPKTTYPE_CHANSETSPKTHR = 0xCA; ///< Channel spike threshold set +constexpr uint32_t cbPKTTYPE_CHANSETSPKHPS = 0xCB; ///< Channel spike hoops set +constexpr uint32_t cbPKTTYPE_CHANSETUNITOVERRIDES = 0xCC; ///< Channel unit overrides set +constexpr uint32_t cbPKTTYPE_CHANSETNTRODEGROUP = 0xCD; ///< Channel n-trode group set +constexpr uint32_t cbPKTTYPE_CHANSETREJECTAMPLITUDE = 0xCE; ///< Channel reject amplitude set +constexpr uint32_t cbPKTTYPE_CHANSETAUTOTHRESHOLD = 0xCF; ///< Channel auto threshold set // Spike sorting packets - Set (0xD0-0xDF) -#define cbPKTTYPE_SS_MODELALLSET 0xD0 ///< Spike sorting model all set -#define cbPKTTYPE_SS_MODELSET 0xD1 ///< Spike sorting model set -#define cbPKTTYPE_SS_DETECTSET 0xD2 ///< Spike sorting detect set -#define cbPKTTYPE_SS_ARTIF_REJECTSET 0xD3 ///< Spike sorting artifact reject set -#define cbPKTTYPE_SS_NOISE_BOUNDARYSET 0xD4 ///< Spike sorting noise boundary set -#define cbPKTTYPE_SS_STATISTICSSET 0xD5 ///< Spike sorting statistics set -#define cbPKTTYPE_SS_RESETSET 0xD6 ///< Spike sorting reset set -#define cbPKTTYPE_SS_STATUSSET 0xD7 ///< Spike sorting status set -#define cbPKTTYPE_SS_RESET_MODEL_SET 0xD8 ///< Spike sorting reset model set -#define cbPKTTYPE_SS_RECALCSET 0xD9 ///< Spike sorting recalculate set -#define cbPKTTYPE_FS_BASISSET 0xDB ///< Feature space basis set -#define cbPKTTYPE_NPLAYSET 0xDC ///< NPlay set -#define cbPKTTYPE_SET_DOUTSET 0xDD ///< Set digital output set -#define cbPKTTYPE_TRIGGERSET 0xDE ///< Trigger set -#define cbPKTTYPE_VIDEOTRACKSET 0xDF ///< Video track set +constexpr uint32_t cbPKTTYPE_SS_MODELALLSET = 0xD0; ///< Spike sorting model all set +constexpr uint32_t cbPKTTYPE_SS_MODELSET = 0xD1; ///< Spike sorting model set +constexpr uint32_t cbPKTTYPE_SS_DETECTSET = 0xD2; ///< Spike sorting detect set +constexpr uint32_t cbPKTTYPE_SS_ARTIF_REJECTSET = 0xD3; ///< Spike sorting artifact reject set +constexpr uint32_t cbPKTTYPE_SS_NOISE_BOUNDARYSET = 0xD4; ///< Spike sorting noise boundary set +constexpr uint32_t cbPKTTYPE_SS_STATISTICSSET = 0xD5; ///< Spike sorting statistics set +constexpr uint32_t cbPKTTYPE_SS_RESETSET = 0xD6; ///< Spike sorting reset set +constexpr uint32_t cbPKTTYPE_SS_STATUSSET = 0xD7; ///< Spike sorting status set +constexpr uint32_t cbPKTTYPE_SS_RESET_MODEL_SET = 0xD8; ///< Spike sorting reset model set +constexpr uint32_t cbPKTTYPE_SS_RECALCSET = 0xD9; ///< Spike sorting recalculate set +constexpr uint32_t cbPKTTYPE_FS_BASISSET = 0xDB; ///< Feature space basis set +constexpr uint32_t cbPKTTYPE_NPLAYSET = 0xDC; ///< NPlay set +constexpr uint32_t cbPKTTYPE_SET_DOUTSET = 0xDD; ///< Set digital output set +constexpr uint32_t cbPKTTYPE_TRIGGERSET = 0xDE; ///< Trigger set +constexpr uint32_t cbPKTTYPE_VIDEOTRACKSET = 0xDF; ///< Video track set // Packet type masks and conversion constants -#define cbPKTTYPE_MASKED_REFLECTED 0xE0 ///< Masked reflected packet type -#define cbPKTTYPE_COMPARE_MASK_REFLECTED 0xF0 ///< Compare mask for reflected packets -#define cbPKTTYPE_REFLECTED_CONVERSION_MASK 0x7F ///< Reflected conversion mask +constexpr uint32_t cbPKTTYPE_MASKED_REFLECTED = 0xE0; ///< Masked reflected packet type +constexpr uint32_t cbPKTTYPE_COMPARE_MASK_REFLECTED = 0xF0; ///< Compare mask for reflected packets +constexpr uint32_t cbPKTTYPE_REFLECTED_CONVERSION_MASK = 0x7F; ///< Reflected conversion mask // File and configuration packets - Set (0xE0-0xEF) -#define cbPKTTYPE_SETFILECFG 0xE1 ///< File configuration set -#define cbPKTTYPE_SETUNITSELECTION 0xE2 ///< Unit selection set -#define cbPKTTYPE_LOGSET 0xE3 ///< Log set -#define cbPKTTYPE_SETPATIENTINFO 0xE4 ///< Patient info set -#define cbPKTTYPE_SETIMPEDANCE 0xE5 ///< Impedance set -#define cbPKTTYPE_SETINITIMPEDANCE 0xE6 ///< Initial impedance set -#define cbPKTTYPE_SETPOLL 0xE7 ///< Poll set -#define cbPKTTYPE_SETMAPFILE 0xE8 ///< Map file set +constexpr uint32_t cbPKTTYPE_SETFILECFG = 0xE1; ///< File configuration set +constexpr uint32_t cbPKTTYPE_SETUNITSELECTION = 0xE2; ///< Unit selection set +constexpr uint32_t cbPKTTYPE_LOGSET = 0xE3; ///< Log set +constexpr uint32_t cbPKTTYPE_SETPATIENTINFO = 0xE4; ///< Patient info set +constexpr uint32_t cbPKTTYPE_SETIMPEDANCE = 0xE5; ///< Impedance set +constexpr uint32_t cbPKTTYPE_SETINITIMPEDANCE = 0xE6; ///< Initial impedance set +constexpr uint32_t cbPKTTYPE_SETPOLL = 0xE7; ///< Poll set +constexpr uint32_t cbPKTTYPE_SETMAPFILE = 0xE8; ///< Map file set // Update packets - Set -#define cbPKTTYPE_UPDATESET 0xF1 ///< Update set +constexpr uint32_t cbPKTTYPE_UPDATESET = 0xF1; ///< Update set /// @} @@ -580,7 +589,7 @@ typedef struct { /// @name Channel Constants /// @{ -#define cbPKTCHAN_CONFIGURATION 0x8000 ///< Channel # to mean configuration +constexpr uint32_t cbPKTCHAN_CONFIGURATION = 0x8000; ///< Channel # to mean configuration /// @} @@ -591,14 +600,14 @@ typedef struct { /// These flags define the capabilities of each channel /// @{ -#define cbCHAN_EXISTS 0x00000001 ///< Channel id is allocated -#define cbCHAN_CONNECTED 0x00000002 ///< Channel is connected and mapped and ready to use -#define cbCHAN_ISOLATED 0x00000004 ///< Channel is electrically isolated -#define cbCHAN_AINP 0x00000100 ///< Channel has analog input capabilities -#define cbCHAN_AOUT 0x00000200 ///< Channel has analog output capabilities -#define cbCHAN_DINP 0x00000400 ///< Channel has digital input capabilities -#define cbCHAN_DOUT 0x00000800 ///< Channel has digital output capabilities -#define cbCHAN_GYRO 0x00001000 ///< Channel has gyroscope/accelerometer/magnetometer/temperature capabilities +constexpr uint32_t cbCHAN_EXISTS = 0x00000001; ///< Channel id is allocated +constexpr uint32_t cbCHAN_CONNECTED = 0x00000002; ///< Channel is connected and mapped and ready to use +constexpr uint32_t cbCHAN_ISOLATED = 0x00000004; ///< Channel is electrically isolated +constexpr uint32_t cbCHAN_AINP = 0x00000100; ///< Channel has analog input capabilities +constexpr uint32_t cbCHAN_AOUT = 0x00000200; ///< Channel has analog output capabilities +constexpr uint32_t cbCHAN_DINP = 0x00000400; ///< Channel has digital input capabilities +constexpr uint32_t cbCHAN_DOUT = 0x00000800; ///< Channel has digital output capabilities +constexpr uint32_t cbCHAN_GYRO = 0x00001000; ///< Channel has gyroscope/accelerometer/magnetometer/temperature capabilities /// @} @@ -608,28 +617,28 @@ typedef struct { /// Ground truth from upstream/cbproto/cbproto.h lines 569-590 /// @{ -#define cbDINP_SERIALMASK 0x000000FF ///< Bit mask used to detect RS232 Serial Baud Rates -#define cbDINP_BAUD2400 0x00000001 ///< RS232 Serial Port operates at 2400 (n-8-1) -#define cbDINP_BAUD9600 0x00000002 ///< RS232 Serial Port operates at 9600 (n-8-1) -#define cbDINP_BAUD19200 0x00000004 ///< RS232 Serial Port operates at 19200 (n-8-1) -#define cbDINP_BAUD38400 0x00000008 ///< RS232 Serial Port operates at 38400 (n-8-1) -#define cbDINP_BAUD57600 0x00000010 ///< RS232 Serial Port operates at 57600 (n-8-1) -#define cbDINP_BAUD115200 0x00000020 ///< RS232 Serial Port operates at 115200 (n-8-1) -#define cbDINP_1BIT 0x00000100 ///< Port has a single input bit (eg single BNC input) -#define cbDINP_8BIT 0x00000200 ///< Port has 8 input bits -#define cbDINP_16BIT 0x00000400 ///< Port has 16 input bits -#define cbDINP_32BIT 0x00000800 ///< Port has 32 input bits -#define cbDINP_ANYBIT 0x00001000 ///< Capture the port value when any bit changes. -#define cbDINP_WRDSTRB 0x00002000 ///< Capture the port when a word-write line is strobed -#define cbDINP_PKTCHAR 0x00004000 ///< Capture packets using an End of Packet Character -#define cbDINP_PKTSTRB 0x00008000 ///< Capture packets using an End of Packet Logic Input -#define cbDINP_MONITOR 0x00010000 ///< Port controls other ports or system events -#define cbDINP_REDGE 0x00020000 ///< Capture the port value when any bit changes lo-2-hi (rising edge) -#define cbDINP_FEDGE 0x00040000 ///< Capture the port value when any bit changes hi-2-lo (falling edge) -#define cbDINP_STRBANY 0x00080000 ///< Capture packets using 8-bit strobe/8-bit any Input -#define cbDINP_STRBRIS 0x00100000 ///< Capture packets using 8-bit strobe/8-bit rising edge Input -#define cbDINP_STRBFAL 0x00200000 ///< Capture packets using 8-bit strobe/8-bit falling edge Input -#define cbDINP_MASK (cbDINP_ANYBIT | cbDINP_WRDSTRB | cbDINP_PKTCHAR | cbDINP_PKTSTRB | cbDINP_MONITOR | cbDINP_REDGE | cbDINP_FEDGE | cbDINP_STRBANY | cbDINP_STRBRIS | cbDINP_STRBFAL) +constexpr uint32_t cbDINP_SERIALMASK = 0x000000FF; ///< Bit mask used to detect RS232 Serial Baud Rates +constexpr uint32_t cbDINP_BAUD2400 = 0x00000001; ///< RS232 Serial Port operates at 2400 (n-8-1) +constexpr uint32_t cbDINP_BAUD9600 = 0x00000002; ///< RS232 Serial Port operates at 9600 (n-8-1) +constexpr uint32_t cbDINP_BAUD19200 = 0x00000004; ///< RS232 Serial Port operates at 19200 (n-8-1) +constexpr uint32_t cbDINP_BAUD38400 = 0x00000008; ///< RS232 Serial Port operates at 38400 (n-8-1) +constexpr uint32_t cbDINP_BAUD57600 = 0x00000010; ///< RS232 Serial Port operates at 57600 (n-8-1) +constexpr uint32_t cbDINP_BAUD115200 = 0x00000020; ///< RS232 Serial Port operates at 115200 (n-8-1) +constexpr uint32_t cbDINP_1BIT = 0x00000100; ///< Port has a single input bit (eg single BNC input) +constexpr uint32_t cbDINP_8BIT = 0x00000200; ///< Port has 8 input bits +constexpr uint32_t cbDINP_16BIT = 0x00000400; ///< Port has 16 input bits +constexpr uint32_t cbDINP_32BIT = 0x00000800; ///< Port has 32 input bits +constexpr uint32_t cbDINP_ANYBIT = 0x00001000; ///< Capture the port value when any bit changes. +constexpr uint32_t cbDINP_WRDSTRB = 0x00002000; ///< Capture the port when a word-write line is strobed +constexpr uint32_t cbDINP_PKTCHAR = 0x00004000; ///< Capture packets using an End of Packet Character +constexpr uint32_t cbDINP_PKTSTRB = 0x00008000; ///< Capture packets using an End of Packet Logic Input +constexpr uint32_t cbDINP_MONITOR = 0x00010000; ///< Port controls other ports or system events +constexpr uint32_t cbDINP_REDGE = 0x00020000; ///< Capture the port value when any bit changes lo-2-hi (rising edge) +constexpr uint32_t cbDINP_FEDGE = 0x00040000; ///< Capture the port value when any bit changes hi-2-lo (falling edge) +constexpr uint32_t cbDINP_STRBANY = 0x00080000; ///< Capture packets using 8-bit strobe/8-bit any Input +constexpr uint32_t cbDINP_STRBRIS = 0x00100000; ///< Capture packets using 8-bit strobe/8-bit rising edge Input +constexpr uint32_t cbDINP_STRBFAL = 0x00200000; ///< Capture packets using 8-bit strobe/8-bit falling edge Input +constexpr uint32_t cbDINP_MASK = (cbDINP_ANYBIT | cbDINP_WRDSTRB | cbDINP_PKTCHAR | cbDINP_PKTSTRB | cbDINP_MONITOR | cbDINP_REDGE | cbDINP_FEDGE | cbDINP_STRBANY | cbDINP_STRBRIS | cbDINP_STRBFAL); /// @} @@ -639,38 +648,38 @@ typedef struct { /// Ground truth from upstream/cbproto/cbproto.h lines 599-630 /// @{ -#define cbDOUT_SERIALMASK 0x000000FF ///< Port operates as an RS232 Serial Connection -#define cbDOUT_BAUD2400 0x00000001 ///< Serial Port operates at 2400 (n-8-1) -#define cbDOUT_BAUD9600 0x00000002 ///< Serial Port operates at 9600 (n-8-1) -#define cbDOUT_BAUD19200 0x00000004 ///< Serial Port operates at 19200 (n-8-1) -#define cbDOUT_BAUD38400 0x00000008 ///< Serial Port operates at 38400 (n-8-1) -#define cbDOUT_BAUD57600 0x00000010 ///< Serial Port operates at 57600 (n-8-1) -#define cbDOUT_BAUD115200 0x00000020 ///< Serial Port operates at 115200 (n-8-1) -#define cbDOUT_1BIT 0x00000100 ///< Port has a single output bit (eg single BNC output) -#define cbDOUT_8BIT 0x00000200 ///< Port has 8 output bits -#define cbDOUT_16BIT 0x00000400 ///< Port has 16 output bits -#define cbDOUT_32BIT 0x00000800 ///< Port has 32 output bits -#define cbDOUT_VALUE 0x00010000 ///< Port can be manually configured -#define cbDOUT_TRACK 0x00020000 ///< Port should track the most recently selected channel -#define cbDOUT_FREQUENCY 0x00040000 ///< Port can output a frequency -#define cbDOUT_TRIGGERED 0x00080000 ///< Port can be triggered -#define cbDOUT_MONITOR_UNIT0 0x01000000 ///< Can monitor unit 0 = UNCLASSIFIED -#define cbDOUT_MONITOR_UNIT1 0x02000000 ///< Can monitor unit 1 -#define cbDOUT_MONITOR_UNIT2 0x04000000 ///< Can monitor unit 2 -#define cbDOUT_MONITOR_UNIT3 0x08000000 ///< Can monitor unit 3 -#define cbDOUT_MONITOR_UNIT4 0x10000000 ///< Can monitor unit 4 -#define cbDOUT_MONITOR_UNIT5 0x20000000 ///< Can monitor unit 5 -#define cbDOUT_MONITOR_UNIT_ALL 0x3F000000 ///< Can monitor ALL units -#define cbDOUT_MONITOR_SHIFT_TO_FIRST_UNIT 24 ///< This tells us how many bit places to get to unit 1 +constexpr uint32_t cbDOUT_SERIALMASK = 0x000000FF; ///< Port operates as an RS232 Serial Connection +constexpr uint32_t cbDOUT_BAUD2400 = 0x00000001; ///< Serial Port operates at 2400 (n-8-1) +constexpr uint32_t cbDOUT_BAUD9600 = 0x00000002; ///< Serial Port operates at 9600 (n-8-1) +constexpr uint32_t cbDOUT_BAUD19200 = 0x00000004; ///< Serial Port operates at 19200 (n-8-1) +constexpr uint32_t cbDOUT_BAUD38400 = 0x00000008; ///< Serial Port operates at 38400 (n-8-1) +constexpr uint32_t cbDOUT_BAUD57600 = 0x00000010; ///< Serial Port operates at 57600 (n-8-1) +constexpr uint32_t cbDOUT_BAUD115200 = 0x00000020; ///< Serial Port operates at 115200 (n-8-1) +constexpr uint32_t cbDOUT_1BIT = 0x00000100; ///< Port has a single output bit (eg single BNC output) +constexpr uint32_t cbDOUT_8BIT = 0x00000200; ///< Port has 8 output bits +constexpr uint32_t cbDOUT_16BIT = 0x00000400; ///< Port has 16 output bits +constexpr uint32_t cbDOUT_32BIT = 0x00000800; ///< Port has 32 output bits +constexpr uint32_t cbDOUT_VALUE = 0x00010000; ///< Port can be manually configured +constexpr uint32_t cbDOUT_TRACK = 0x00020000; ///< Port should track the most recently selected channel +constexpr uint32_t cbDOUT_FREQUENCY = 0x00040000; ///< Port can output a frequency +constexpr uint32_t cbDOUT_TRIGGERED = 0x00080000; ///< Port can be triggered +constexpr uint32_t cbDOUT_MONITOR_UNIT0 = 0x01000000; ///< Can monitor unit 0 = UNCLASSIFIED +constexpr uint32_t cbDOUT_MONITOR_UNIT1 = 0x02000000; ///< Can monitor unit 1 +constexpr uint32_t cbDOUT_MONITOR_UNIT2 = 0x04000000; ///< Can monitor unit 2 +constexpr uint32_t cbDOUT_MONITOR_UNIT3 = 0x08000000; ///< Can monitor unit 3 +constexpr uint32_t cbDOUT_MONITOR_UNIT4 = 0x10000000; ///< Can monitor unit 4 +constexpr uint32_t cbDOUT_MONITOR_UNIT5 = 0x20000000; ///< Can monitor unit 5 +constexpr uint32_t cbDOUT_MONITOR_UNIT_ALL = 0x3F000000; ///< Can monitor ALL units +constexpr uint32_t cbDOUT_MONITOR_SHIFT_TO_FIRST_UNIT = 24; ///< This tells us how many bit places to get to unit 1 // Trigger types for Digital Output channels -#define cbDOUT_TRIGGER_NONE 0 ///< instant software trigger -#define cbDOUT_TRIGGER_DINPRISING 1 ///< digital input rising edge trigger -#define cbDOUT_TRIGGER_DINPFALLING 2 ///< digital input falling edge trigger -#define cbDOUT_TRIGGER_SPIKEUNIT 3 ///< spike unit -#define cbDOUT_TRIGGER_NM 4 ///< comment RGBA color (A being big byte) -#define cbDOUT_TRIGGER_RECORDINGSTART 5 ///< recording start trigger -#define cbDOUT_TRIGGER_EXTENSION 6 ///< extension trigger +constexpr uint32_t cbDOUT_TRIGGER_NONE = 0; ///< instant software trigger +constexpr uint32_t cbDOUT_TRIGGER_DINPRISING = 1; ///< digital input rising edge trigger +constexpr uint32_t cbDOUT_TRIGGER_DINPFALLING = 2; ///< digital input falling edge trigger +constexpr uint32_t cbDOUT_TRIGGER_SPIKEUNIT = 3; ///< spike unit +constexpr uint32_t cbDOUT_TRIGGER_NM = 4; ///< comment RGBA color (A being big byte) +constexpr uint32_t cbDOUT_TRIGGER_RECORDINGSTART = 5; ///< recording start trigger +constexpr uint32_t cbDOUT_TRIGGER_EXTENSION = 6; ///< extension trigger /// @} @@ -680,33 +689,33 @@ typedef struct { /// Ground truth from upstream/cbproto/cbproto.h lines 696-723 /// @{ -#define cbAINP_RAWPREVIEW 0x00000001 ///< Generate scrolling preview data for the raw channel -#define cbAINP_LNC 0x00000002 ///< Line Noise Cancellation -#define cbAINP_LNCPREVIEW 0x00000004 ///< Retrieve the LNC correction waveform -#define cbAINP_SMPSTREAM 0x00000010 ///< stream the analog input stream directly to disk -#define cbAINP_SMPFILTER 0x00000020 ///< Digitally filter the analog input stream -#define cbAINP_RAWSTREAM 0x00000040 ///< Raw data stream available -#define cbAINP_SPKSTREAM 0x00000100 ///< Spike Stream is available -#define cbAINP_SPKFILTER 0x00000200 ///< Selectable Filters -#define cbAINP_SPKPREVIEW 0x00000400 ///< Generate scrolling preview of the spike channel -#define cbAINP_SPKPROC 0x00000800 ///< Channel is able to do online spike processing -#define cbAINP_OFFSET_CORRECT_CAP 0x00001000 ///< Offset correction mode (0-disabled 1-enabled) - -#define cbAINP_LNC_OFF 0x00000000 ///< Line Noise Cancellation disabled -#define cbAINP_LNC_RUN_HARD 0x00000001 ///< Hardware-based LNC running and adapting according to the adaptation const -#define cbAINP_LNC_RUN_SOFT 0x00000002 ///< Software-based LNC running and adapting according to the adaptation const -#define cbAINP_LNC_HOLD 0x00000004 ///< LNC running, but not adapting -#define cbAINP_LNC_MASK 0x00000007 ///< Mask for LNC Flags -#define cbAINP_REFELEC_LFPSPK 0x00000010 ///< Apply reference electrode to LFP & Spike -#define cbAINP_REFELEC_SPK 0x00000020 ///< Apply reference electrode to Spikes only -#define cbAINP_REFELEC_MASK 0x00000030 ///< Mask for Reference Electrode flags -#define cbAINP_RAWSTREAM_ENABLED 0x00000040 ///< Raw data stream enabled -#define cbAINP_OFFSET_CORRECT 0x00000100 ///< Offset correction mode (0-disabled 1-enabled) +constexpr uint32_t cbAINP_RAWPREVIEW = 0x00000001; ///< Generate scrolling preview data for the raw channel +constexpr uint32_t cbAINP_LNC = 0x00000002; ///< Line Noise Cancellation +constexpr uint32_t cbAINP_LNCPREVIEW = 0x00000004; ///< Retrieve the LNC correction waveform +constexpr uint32_t cbAINP_SMPSTREAM = 0x00000010; ///< stream the analog input stream directly to disk +constexpr uint32_t cbAINP_SMPFILTER = 0x00000020; ///< Digitally filter the analog input stream +constexpr uint32_t cbAINP_RAWSTREAM = 0x00000040; ///< Raw data stream available +constexpr uint32_t cbAINP_SPKSTREAM = 0x00000100; ///< Spike Stream is available +constexpr uint32_t cbAINP_SPKFILTER = 0x00000200; ///< Selectable Filters +constexpr uint32_t cbAINP_SPKPREVIEW = 0x00000400; ///< Generate scrolling preview of the spike channel +constexpr uint32_t cbAINP_SPKPROC = 0x00000800; ///< Channel is able to do online spike processing +constexpr uint32_t cbAINP_OFFSET_CORRECT_CAP = 0x00001000; ///< Offset correction mode (0-disabled 1-enabled) + +constexpr uint32_t cbAINP_LNC_OFF = 0x00000000; ///< Line Noise Cancellation disabled +constexpr uint32_t cbAINP_LNC_RUN_HARD = 0x00000001; ///< Hardware-based LNC running and adapting according to the adaptation const +constexpr uint32_t cbAINP_LNC_RUN_SOFT = 0x00000002; ///< Software-based LNC running and adapting according to the adaptation const +constexpr uint32_t cbAINP_LNC_HOLD = 0x00000004; ///< LNC running, but not adapting +constexpr uint32_t cbAINP_LNC_MASK = 0x00000007; ///< Mask for LNC Flags +constexpr uint32_t cbAINP_REFELEC_LFPSPK = 0x00000010; ///< Apply reference electrode to LFP & Spike +constexpr uint32_t cbAINP_REFELEC_SPK = 0x00000020; ///< Apply reference electrode to Spikes only +constexpr uint32_t cbAINP_REFELEC_MASK = 0x00000030; ///< Mask for Reference Electrode flags +constexpr uint32_t cbAINP_RAWSTREAM_ENABLED = 0x00000040; ///< Raw data stream enabled +constexpr uint32_t cbAINP_OFFSET_CORRECT = 0x00000100; ///< Offset correction mode (0-disabled 1-enabled) // Preview request packet identifiers -#define cbAINPPREV_LNC 0x81 -#define cbAINPPREV_STREAM 0x82 -#define cbAINPPREV_ALL 0x83 +constexpr uint32_t cbAINPPREV_LNC = 0x81; +constexpr uint32_t cbAINPPREV_STREAM = 0x82; +constexpr uint32_t cbAINPPREV_ALL = 0x83; /// @} @@ -716,28 +725,28 @@ typedef struct { /// Ground truth from upstream/cbproto/cbproto.h lines 728-749 /// @{ -#define cbAINPSPK_EXTRACT 0x00000001 ///< Time-stamp and packet to first superthreshold peak -#define cbAINPSPK_REJART 0x00000002 ///< Reject around clipped signals on multiple channels -#define cbAINPSPK_REJCLIP 0x00000004 ///< Reject clipped signals on the channel -#define cbAINPSPK_ALIGNPK 0x00000008 ///< -#define cbAINPSPK_REJAMPL 0x00000010 ///< Reject based on amplitude -#define cbAINPSPK_THRLEVEL 0x00000100 ///< Analog level threshold detection -#define cbAINPSPK_THRENERGY 0x00000200 ///< Energy threshold detection -#define cbAINPSPK_THRAUTO 0x00000400 ///< Auto threshold detection -#define cbAINPSPK_SPREADSORT 0x00001000 ///< Enable Auto spread Sorting -#define cbAINPSPK_CORRSORT 0x00002000 ///< Enable Auto Histogram Correlation Sorting -#define cbAINPSPK_PEAKMAJSORT 0x00004000 ///< Enable Auto Histogram Peak Major Sorting -#define cbAINPSPK_PEAKFISHSORT 0x00008000 ///< Enable Auto Histogram Peak Fisher Sorting -#define cbAINPSPK_HOOPSORT 0x00010000 ///< Enable Manual Hoop Sorting -#define cbAINPSPK_PCAMANSORT 0x00020000 ///< Enable Manual PCA Sorting -#define cbAINPSPK_PCAKMEANSORT 0x00040000 ///< Enable K-means PCA Sorting -#define cbAINPSPK_PCAEMSORT 0x00080000 ///< Enable EM-clustering PCA Sorting -#define cbAINPSPK_PCADBSORT 0x00100000 ///< Enable DBSCAN PCA Sorting -#define cbAINPSPK_AUTOSORT (cbAINPSPK_SPREADSORT | cbAINPSPK_CORRSORT | cbAINPSPK_PEAKMAJSORT | cbAINPSPK_PEAKFISHSORT) ///< old auto sorting methods -#define cbAINPSPK_NOSORT 0x00000000 ///< No sorting -#define cbAINPSPK_PCAAUTOSORT (cbAINPSPK_PCAKMEANSORT | cbAINPSPK_PCAEMSORT | cbAINPSPK_PCADBSORT) ///< All PCA sorting auto algorithms -#define cbAINPSPK_PCASORT (cbAINPSPK_PCAMANSORT | cbAINPSPK_PCAAUTOSORT) ///< All PCA sorting algorithms -#define cbAINPSPK_ALLSORT (cbAINPSPK_AUTOSORT | cbAINPSPK_HOOPSORT | cbAINPSPK_PCASORT) ///< All sorting algorithms +constexpr uint32_t cbAINPSPK_EXTRACT = 0x00000001; ///< Time-stamp and packet to first superthreshold peak +constexpr uint32_t cbAINPSPK_REJART = 0x00000002; ///< Reject around clipped signals on multiple channels +constexpr uint32_t cbAINPSPK_REJCLIP = 0x00000004; ///< Reject clipped signals on the channel +constexpr uint32_t cbAINPSPK_ALIGNPK = 0x00000008; ///< +constexpr uint32_t cbAINPSPK_REJAMPL = 0x00000010; ///< Reject based on amplitude +constexpr uint32_t cbAINPSPK_THRLEVEL = 0x00000100; ///< Analog level threshold detection +constexpr uint32_t cbAINPSPK_THRENERGY = 0x00000200; ///< Energy threshold detection +constexpr uint32_t cbAINPSPK_THRAUTO = 0x00000400; ///< Auto threshold detection +constexpr uint32_t cbAINPSPK_SPREADSORT = 0x00001000; ///< Enable Auto spread Sorting +constexpr uint32_t cbAINPSPK_CORRSORT = 0x00002000; ///< Enable Auto Histogram Correlation Sorting +constexpr uint32_t cbAINPSPK_PEAKMAJSORT = 0x00004000; ///< Enable Auto Histogram Peak Major Sorting +constexpr uint32_t cbAINPSPK_PEAKFISHSORT = 0x00008000; ///< Enable Auto Histogram Peak Fisher Sorting +constexpr uint32_t cbAINPSPK_HOOPSORT = 0x00010000; ///< Enable Manual Hoop Sorting +constexpr uint32_t cbAINPSPK_PCAMANSORT = 0x00020000; ///< Enable Manual PCA Sorting +constexpr uint32_t cbAINPSPK_PCAKMEANSORT = 0x00040000; ///< Enable K-means PCA Sorting +constexpr uint32_t cbAINPSPK_PCAEMSORT = 0x00080000; ///< Enable EM-clustering PCA Sorting +constexpr uint32_t cbAINPSPK_PCADBSORT = 0x00100000; ///< Enable DBSCAN PCA Sorting +constexpr uint32_t cbAINPSPK_AUTOSORT = (cbAINPSPK_SPREADSORT | cbAINPSPK_CORRSORT | cbAINPSPK_PEAKMAJSORT | cbAINPSPK_PEAKFISHSORT); ///< old auto sorting methods +constexpr uint32_t cbAINPSPK_NOSORT = 0x00000000; ///< No sorting +constexpr uint32_t cbAINPSPK_PCAAUTOSORT = (cbAINPSPK_PCAKMEANSORT | cbAINPSPK_PCAEMSORT | cbAINPSPK_PCADBSORT); ///< All PCA sorting auto algorithms +constexpr uint32_t cbAINPSPK_PCASORT = (cbAINPSPK_PCAMANSORT | cbAINPSPK_PCAAUTOSORT); ///< All PCA sorting algorithms +constexpr uint32_t cbAINPSPK_ALLSORT = (cbAINPSPK_AUTOSORT | cbAINPSPK_HOOPSORT | cbAINPSPK_PCASORT); ///< All sorting algorithms /// @} @@ -747,17 +756,17 @@ typedef struct { /// Ground truth from upstream/cbproto/cbproto.h lines 768-778 /// @{ -#define cbAOUT_AUDIO 0x00000001 ///< Channel is physically optimized for audio output -#define cbAOUT_SCALE 0x00000002 ///< Output a static value -#define cbAOUT_TRACK 0x00000004 ///< Output a static value -#define cbAOUT_STATIC 0x00000008 ///< Output a static value -#define cbAOUT_MONITORRAW 0x00000010 ///< Monitor an analog signal line - RAW data -#define cbAOUT_MONITORLNC 0x00000020 ///< Monitor an analog signal line - Line Noise Cancelation -#define cbAOUT_MONITORSMP 0x00000040 ///< Monitor an analog signal line - Continuous -#define cbAOUT_MONITORSPK 0x00000080 ///< Monitor an analog signal line - spike -#define cbAOUT_STIMULATE 0x00000100 ///< Stimulation waveform functions are available. -#define cbAOUT_WAVEFORM 0x00000200 ///< Custom Waveform -#define cbAOUT_EXTENSION 0x00000400 ///< Output Waveform from Extension +constexpr uint32_t cbAOUT_AUDIO = 0x00000001; ///< Channel is physically optimized for audio output +constexpr uint32_t cbAOUT_SCALE = 0x00000002; ///< Output a static value +constexpr uint32_t cbAOUT_TRACK = 0x00000004; ///< Output a static value +constexpr uint32_t cbAOUT_STATIC = 0x00000008; ///< Output a static value +constexpr uint32_t cbAOUT_MONITORRAW = 0x00000010; ///< Monitor an analog signal line - RAW data +constexpr uint32_t cbAOUT_MONITORLNC = 0x00000020; ///< Monitor an analog signal line - Line Noise Cancelation +constexpr uint32_t cbAOUT_MONITORSMP = 0x00000040; ///< Monitor an analog signal line - Continuous +constexpr uint32_t cbAOUT_MONITORSPK = 0x00000080; ///< Monitor an analog signal line - spike +constexpr uint32_t cbAOUT_STIMULATE = 0x00000100; ///< Stimulation waveform functions are available. +constexpr uint32_t cbAOUT_WAVEFORM = 0x00000200; ///< Custom Waveform +constexpr uint32_t cbAOUT_EXTENSION = 0x00000400; ///< Output Waveform from Extension /// @} @@ -768,15 +777,15 @@ typedef struct { /// These define the system runlevel states /// @{ -#define cbRUNLEVEL_UPDATE 78 -#define cbRUNLEVEL_STARTUP 10 -#define cbRUNLEVEL_HARDRESET 20 -#define cbRUNLEVEL_STANDBY 30 -#define cbRUNLEVEL_RESET 40 -#define cbRUNLEVEL_RUNNING 50 -#define cbRUNLEVEL_STRESSED 60 -#define cbRUNLEVEL_ERROR 70 -#define cbRUNLEVEL_SHUTDOWN 80 +constexpr uint32_t cbRUNLEVEL_UPDATE = 78; +constexpr uint32_t cbRUNLEVEL_STARTUP = 10; +constexpr uint32_t cbRUNLEVEL_HARDRESET = 20; +constexpr uint32_t cbRUNLEVEL_STANDBY = 30; +constexpr uint32_t cbRUNLEVEL_RESET = 40; +constexpr uint32_t cbRUNLEVEL_RUNNING = 50; +constexpr uint32_t cbRUNLEVEL_STRESSED = 60; +constexpr uint32_t cbRUNLEVEL_ERROR = 70; +constexpr uint32_t cbRUNLEVEL_SHUTDOWN = 80; /// @} @@ -785,8 +794,8 @@ typedef struct { /// /// These define the system runflags /// @{ -#define cbRUNFLAGS_NONE 0 -#define cbRUNFLAGS_LOCK 1 // Lock recording after reset +constexpr uint32_t cbRUNFLAGS_NONE = 0; +constexpr uint32_t cbRUNFLAGS_LOCK = 1; // Lock recording after reset /// @} @@ -796,10 +805,6 @@ typedef struct { /// Ground truth from upstream/cbproto/cbproto.h /// @{ -#define cbPKTTYPE_SYSHEARTBEAT 0x00 -#define cbPKTDLEN_SYSHEARTBEAT ((sizeof(cbPKT_SYSHEARTBEAT)/4) - cbPKT_HEADER_32SIZE) -#define HEARTBEAT_MS 10 - /// @brief PKT Set:N/A Rep:0x00 - System Heartbeat packet /// /// Ground truth from upstream/cbproto/cbproto.h lines 903-914 @@ -808,6 +813,9 @@ typedef struct { cbPKT_HEADER cbpkt_header; ///< packet header } cbPKT_SYSHEARTBEAT; +constexpr uint32_t cbPKTDLEN_SYSHEARTBEAT = ((sizeof(cbPKT_SYSHEARTBEAT)/4) - cbPKT_HEADER_32SIZE); +constexpr uint32_t HEARTBEAT_MS = 10; + /// @brief PKT Set:0x92 Rep:0x12 - System info /// /// Contains system information including the runlevel @@ -822,13 +830,7 @@ typedef struct { uint32_t runflags; ///< Lock recording after reset } cbPKT_SYSINFO; -#define cbPKTDLEN_SYSINFO ((sizeof(cbPKT_SYSINFO)/4) - cbPKT_HEADER_32SIZE) - -/// @brief Old system info packet -/// -/// Ground truth from upstream/cbproto/cbproto.h lines 1086-1099 -/// Used for backward compatibility with old CCF files -#define cbPKTDLEN_OLDSYSINFO ((sizeof(cbPKT_OLDSYSINFO)/4) - 2) +constexpr uint32_t cbPKTDLEN_SYSINFO = ((sizeof(cbPKT_SYSINFO)/4) - cbPKT_HEADER_32SIZE); typedef struct { uint32_t time; ///< system clock timestamp @@ -844,6 +846,12 @@ typedef struct { uint32_t runflags; } cbPKT_OLDSYSINFO; +/// @brief Old system info packet +/// +/// Ground truth from upstream/cbproto/cbproto.h lines 1086-1099 +/// Used for backward compatibility with old CCF files +constexpr uint32_t cbPKTDLEN_OLDSYSINFO = ((sizeof(cbPKT_OLDSYSINFO)/4) - 2); + /// @brief PKT Set:N/A Rep:0x01 - System protocol monitor /// /// Packets are sent via UDP. This packet is sent by the NSP periodically (approximately every 10ms) @@ -857,10 +865,10 @@ typedef struct { uint32_t sentpkts; ///< Packets sent since last cbPKT_SYSPROTOCOLMONITOR (or 0 if timestamp=0) ///< The cbPKT_SYSPROTOCOLMONITOR packets are counted as well so this must be >= 1 - uint32_t counter; ///< Counter of cbPKT_SYSPROTOCOLMONITOR packets sent since beginning of NSP time + uint32_t counter; ///< Counter of cbPKT_SYSPROTOCOLMONITOR packets sent since beginning of NSP time // VER: 4.1+ ONLY } cbPKT_SYSPROTOCOLMONITOR; -#define cbPKTDLEN_SYSPROTOCOLMONITOR ((sizeof(cbPKT_SYSPROTOCOLMONITOR)/4) - cbPKT_HEADER_32SIZE) +constexpr uint32_t cbPKTDLEN_SYSPROTOCOLMONITOR = ((sizeof(cbPKT_SYSPROTOCOLMONITOR)/4) - cbPKT_HEADER_32SIZE); /// @brief PKT Set:0xB1 Rep:0x31 - Comment annotation packet /// @@ -877,8 +885,8 @@ typedef struct { char comment[cbMAX_COMMENT]; //!< Comment } cbPKT_COMMENT; -#define cbPKTDLEN_COMMENT ((sizeof(cbPKT_COMMENT)/4) - cbPKT_HEADER_32SIZE) -#define cbPKTDLEN_COMMENTSHORT (cbPKTDLEN_COMMENT - ((sizeof(uint8_t)*cbMAX_COMMENT)/4)) +constexpr uint32_t cbPKTDLEN_COMMENT = ((sizeof(cbPKT_COMMENT)/4) - cbPKT_HEADER_32SIZE); +constexpr uint32_t cbPKTDLEN_COMMENTSHORT = (cbPKTDLEN_COMMENT - ((sizeof(uint8_t)*cbMAX_COMMENT)/4)); /// @} @@ -889,16 +897,9 @@ typedef struct { /// @{ // PCA collection states -#define cbPCA_START_COLLECTION 0 ///< start collecting samples -#define cbPCA_START_BASIS 1 ///< start basis calculation -#define cbPCA_MANUAL_LAST_SAMPLE 2 ///< the manual-only PCA, samples at zero, calculates PCA basis at 1 and stops at 2 - -// Stream preview flags -#define cbSTREAMPREV_NONE 0x00000000 -#define cbSTREAMPREV_PCABASIS_NONEMPTY 0x00000001 - -#define cbPKTTYPE_PREVREPSTREAM 0x02 -#define cbPKTDLEN_PREVREPSTREAM ((sizeof(cbPKT_STREAMPREV)/4) - cbPKT_HEADER_32SIZE) +constexpr uint32_t cbPCA_START_COLLECTION = 0; ///< start collecting samples +constexpr uint32_t cbPCA_START_BASIS = 1; ///< start basis calculation +constexpr uint32_t cbPCA_MANUAL_LAST_SAMPLE = 2; ///< the manual-only PCA, samples at zero, calculates PCA basis at 1 and stops at 2 /// @brief Preview packet /// @@ -922,8 +923,11 @@ typedef struct { uint32_t nFlags; ///< cbSTREAMPREV_* } cbPKT_STREAMPREV; -#define cbPKTTYPE_PREVREPLNC 0x04 -#define cbPKTDLEN_PREVREPLNC ((sizeof(cbPKT_LNCPREV)/4) - cbPKT_HEADER_32SIZE) +// Stream preview flags +constexpr uint32_t cbSTREAMPREV_NONE = 0x00000000; +constexpr uint32_t cbSTREAMPREV_PCABASIS_NONEMPTY = 0x00000001; + +constexpr uint32_t cbPKTDLEN_PREVREPSTREAM = ((sizeof(cbPKT_STREAMPREV)/4) - cbPKT_HEADER_32SIZE); /// @brief Preview packet - Line Noise preview /// @@ -935,6 +939,8 @@ typedef struct { int16_t wave[300]; ///< lnc cancellation waveform (downsampled by 2) } cbPKT_LNCPREV; +constexpr uint32_t cbPKTDLEN_PREVREPLNC = ((sizeof(cbPKT_LNCPREV)/4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -962,7 +968,7 @@ typedef struct { uint32_t version; ///< current version of libraries } cbPKT_PROCINFO; -#define cbPKTDLEN_PROCINFO ((sizeof(cbPKT_PROCINFO)/4) - cbPKT_HEADER_32SIZE) +constexpr uint32_t cbPKTDLEN_PROCINFO = ((sizeof(cbPKT_PROCINFO)/4) - cbPKT_HEADER_32SIZE); /// @brief PKT Set:N/A Rep:0x22 - Information about the banks in the processor typedef struct { @@ -977,7 +983,7 @@ typedef struct { uint32_t chancount; ///< number of channel identifiers claimed by this bank } cbPKT_BANKINFO; -#define cbPKTDLEN_BANKINFO ((sizeof(cbPKT_BANKINFO)/4) - cbPKT_HEADER_32SIZE) +constexpr uint32_t cbPKTDLEN_BANKINFO = ((sizeof(cbPKT_BANKINFO)/4) - cbPKT_HEADER_32SIZE); /// @brief PKT Set:0xA3 Rep:0x23 - Filter Information Packet /// @@ -1006,7 +1012,7 @@ typedef struct { double sos2b2; ///< filter coefficient } cbPKT_FILTINFO; -#define cbPKTDLEN_FILTINFO ((sizeof(cbPKT_FILTINFO)/4) - cbPKT_HEADER_32SIZE) +constexpr uint32_t cbPKTDLEN_FILTINFO = ((sizeof(cbPKT_FILTINFO)/4) - cbPKT_HEADER_32SIZE); /// @brief PKT Set:0xB0 Rep:0x30 - Sample Group (GROUP) Information Packets /// @@ -1023,8 +1029,8 @@ typedef struct { uint16_t list[cbNUM_ANALOG_CHANS]; ///< variable length list. The max size is the total number of analog channels } cbPKT_GROUPINFO; -#define cbPKTDLEN_GROUPINFO ((sizeof(cbPKT_GROUPINFO)/4) - cbPKT_HEADER_32SIZE) -#define cbPKTDLEN_GROUPINFOSHORT (8) // basic length without list +constexpr uint32_t cbPKTDLEN_GROUPINFO = ((sizeof(cbPKT_GROUPINFO)/4) - cbPKT_HEADER_32SIZE); +constexpr uint32_t cbPKTDLEN_GROUPINFOSHORT = (8); // basic length without list /// @brief PKT Set:0xCx Rep:0x4x - Channel Information /// @@ -1057,6 +1063,7 @@ typedef struct { uint32_t eopchar; ///< digital input capablities (given by cbDINP_* flags) union { struct { // separate system channel to instrument specific channel number + // VER: 4.2+, monsource is split into moninst and monchan uint16_t moninst; ///< instrument of channel to monitor uint16_t monchan; ///< channel to monitor int32_t outvalue; ///< output value @@ -1068,8 +1075,11 @@ typedef struct { }; }; uint8_t trigtype; ///< trigger type (see cbDOUT_TRIGGER_*) + // VER: 4.1+, triginst and padding added + // --------- uint8_t reserved[2]; ///< 2 bytes reserved uint8_t triginst; ///< instrument of the trigger channel + // --------- uint16_t trigchan; ///< trigger channel uint16_t trigval; ///< trigger value uint32_t ainpopts; ///< analog input options (composed of cbAINP* flags) @@ -1092,8 +1102,8 @@ typedef struct { cbHOOP spkhoops[cbMAXUNITS][cbMAXHOOPS]; ///< spike hoop sorting set } cbPKT_CHANINFO; -#define cbPKTDLEN_CHANINFO ((sizeof(cbPKT_CHANINFO)/4) - cbPKT_HEADER_32SIZE) -#define cbPKTDLEN_CHANINFOSHORT (cbPKTDLEN_CHANINFO - ((sizeof(cbHOOP)*cbMAXUNITS*cbMAXHOOPS)/4)) +constexpr uint32_t cbPKTDLEN_CHANINFO = ((sizeof(cbPKT_CHANINFO)/4) - cbPKT_HEADER_32SIZE); +constexpr uint32_t cbPKTDLEN_CHANINFOSHORT = (cbPKTDLEN_CHANINFO - ((sizeof(cbHOOP)*cbMAXUNITS*cbMAXHOOPS)/4)); /// @} @@ -1101,9 +1111,6 @@ typedef struct { /// @name Spike Data Packets /// @{ -#define cbPKTDLEN_SPK ((sizeof(cbPKT_SPK)/4) - cbPKT_HEADER_32SIZE) -#define cbPKTDLEN_SPKSHORT (cbPKTDLEN_SPK - ((sizeof(int16_t)*cbMAX_PNTS)/4)) - /// @brief Data packet - Spike waveform data /// /// Detected spikes are sent through this packet. The spike waveform may or may not be sent depending @@ -1121,6 +1128,9 @@ typedef struct { ///< wave must be the last item in the structure because it can be variable length to a max of cbMAX_PNTS } cbPKT_SPK; +constexpr uint32_t cbPKTDLEN_SPK = ((sizeof(cbPKT_SPK)/4) - cbPKT_HEADER_32SIZE); +constexpr uint32_t cbPKTDLEN_SPKSHORT = (cbPKTDLEN_SPK - ((sizeof(int16_t)*cbMAX_PNTS)/4)); + /// @brief Gyro Data packet - Gyro input data value. /// /// Ground truth from upstream/cbproto/cbproto.h lines 890-901 @@ -1158,8 +1168,8 @@ typedef struct { /// @name Digital Input/Output Data Packets /// @{ -#define DINP_EVENT_ANYBIT 0x00000001 ///< Digital input event: any bit changed -#define DINP_EVENT_STROBE 0x00000002 ///< Digital input event: strobe detected +constexpr uint32_t DINP_EVENT_ANYBIT = 0x00000001; ///< Digital input event: any bit changed; +constexpr uint32_t DINP_EVENT_STROBE = 0x00000002; ///< Digital input event: strobe detected; /// @brief Data packet - Digital input data value /// @@ -1198,8 +1208,6 @@ enum 0xFF80, // this is here to select all digital input bits in raster when expanded }; -#define cbPKTDLEN_UNITSELECTION ((sizeof(cbPKT_UNIT_SELECTION) / 4) - cbPKT_HEADER_32SIZE) - /// @brief Unit Selection /// /// Packet which says that these channels are now selected @@ -1211,6 +1219,8 @@ typedef struct uint16_t abyUnitSelections[(cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - sizeof(int32_t))]; ///< one for each channel, channels are 0 based here, shows units selected } cbPKT_UNIT_SELECTION; +constexpr uint32_t cbPKTDLEN_UNITSELECTION = ((sizeof(cbPKT_UNIT_SELECTION) / 4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1219,10 +1229,6 @@ typedef struct /// Ground truth from upstream/cbproto/cbproto.h lines 1264-1308 /// @{ -#define cbPKTTYPE_CHANRESETREP 0x24 ///< NSP->PC response...ignore all values -#define cbPKTTYPE_CHANRESET 0xA4 ///< PC->NSP request -#define cbPKTDLEN_CHANRESET ((sizeof(cbPKT_CHANRESET) / 4) - cbPKT_HEADER_32SIZE) - /// @brief PKT Set:0xA4 Rep:0x24 - Channel reset packet /// /// This resets various aspects of a channel. For each member, 0 doesn't change the value, any non-zero value resets @@ -1264,6 +1270,8 @@ typedef struct { uint8_t spkhoops; ///< spike hoop sorting set } cbPKT_CHANRESET; +constexpr uint32_t cbPKTDLEN_CHANRESET = ((sizeof(cbPKT_CHANRESET) / 4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1272,14 +1280,10 @@ typedef struct { /// Ground truth from upstream/cbproto/cbproto.h lines 1310-1333 /// @{ -#define cbPKTTYPE_ADAPTFILTREP 0x25 ///< NSP->PC response -#define cbPKTTYPE_ADAPTFILTSET 0xA5 ///< PC->NSP request -#define cbPKTDLEN_ADAPTFILTINFO ((sizeof(cbPKT_ADAPTFILTINFO) / 4) - cbPKT_HEADER_32SIZE) - // Adaptive filter settings -#define ADAPT_FILT_DISABLED 0 -#define ADAPT_FILT_ALL 1 -#define ADAPT_FILT_SPIKES 2 +constexpr uint32_t ADAPT_FILT_DISABLED = 0; +constexpr uint32_t ADAPT_FILT_ALL = 1; +constexpr uint32_t ADAPT_FILT_SPIKES = 2; /// @brief PKT Set:0xA5 Rep:0x25 - Adaptive filtering /// @@ -1296,6 +1300,8 @@ typedef struct { } cbPKT_ADAPTFILTINFO; +constexpr uint32_t cbPKTDLEN_ADAPTFILTINFO = ((sizeof(cbPKT_ADAPTFILTINFO) / 4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1304,14 +1310,10 @@ typedef struct { /// Ground truth from upstream/cbproto/cbproto.h lines 1335-1355 /// @{ -#define cbPKTTYPE_REFELECFILTREP 0x26 ///< NSP->PC response -#define cbPKTTYPE_REFELECFILTSET 0xA6 ///< PC->NSP request -#define cbPKTDLEN_REFELECFILTINFO ((sizeof(cbPKT_REFELECFILTINFO) / 4) - cbPKT_HEADER_32SIZE) - // Reference electrode filter settings -#define REFELEC_FILT_DISABLED 0 -#define REFELEC_FILT_ALL 1 -#define REFELEC_FILT_SPIKES 2 +constexpr uint32_t REFELEC_FILT_DISABLED = 0; +constexpr uint32_t REFELEC_FILT_ALL = 1; +constexpr uint32_t REFELEC_FILT_SPIKES = 2; /// @brief PKT Set:0xA6 Rep:0x26 - Reference Electrode Information. /// @@ -1325,6 +1327,8 @@ typedef struct { uint32_t nRefChan; ///< The reference channel (1 based). } cbPKT_REFELECFILTINFO; +constexpr uint32_t cbPKTDLEN_REFELECFILTINFO = ((sizeof(cbPKT_REFELECFILTINFO) / 4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1333,10 +1337,6 @@ typedef struct { /// Ground truth from upstream/cbproto/cbproto.h lines 1910-1926 /// @{ -#define cbPKTTYPE_LNCREP 0x28 ///< NSP->PC response -#define cbPKTTYPE_LNCSET 0xA8 ///< PC->NSP request -#define cbPKTDLEN_LNC ((sizeof(cbPKT_LNC) / 4) - cbPKT_HEADER_32SIZE) - /// @brief PKT Set:0xA8 Rep:0x28 - Line Noise Cancellation /// /// This packet holds the Line Noise Cancellation parameters @@ -1349,6 +1349,8 @@ typedef struct uint32_t lncGlobalMode; ///< reserved } cbPKT_LNC; +constexpr uint32_t cbPKTDLEN_LNC = ((sizeof(cbPKT_LNC) / 4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1357,10 +1359,6 @@ typedef struct /// Ground truth from upstream/cbproto/cbproto.h lines 1113-1128 /// @{ -#define cbPKTTYPE_VIDEOSYNCHREP 0x29 ///< NSP->PC response -#define cbPKTTYPE_VIDEOSYNCHSET 0xA9 ///< PC->NSP request -#define cbPKTDLEN_VIDEOSYNCH ((sizeof(cbPKT_VIDEOSYNCH)/4) - cbPKT_HEADER_32SIZE) - /// @brief PKT Set:0xA9 Rep:0x29 - Video/external synchronization packet. /// /// This packet comes from NeuroMotive through network or RS232 @@ -1374,6 +1372,8 @@ typedef struct { uint16_t id; ///< video source id } cbPKT_VIDEOSYNCH; +constexpr uint32_t cbPKTDLEN_VIDEOSYNCH = ((sizeof(cbPKT_VIDEOSYNCH)/4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1383,22 +1383,16 @@ typedef struct { /// @{ // file config options -#define cbFILECFG_OPT_NONE 0x00000000 ///< Launch File dialog, set file info, start or stop recording -#define cbFILECFG_OPT_KEEPALIVE 0x00000001 ///< Keep-alive message -#define cbFILECFG_OPT_REC 0x00000002 ///< Recording is in progress -#define cbFILECFG_OPT_STOP 0x00000003 ///< Recording stopped -#define cbFILECFG_OPT_NMREC 0x00000004 ///< NeuroMotive recording status -#define cbFILECFG_OPT_CLOSE 0x00000005 ///< Close file application -#define cbFILECFG_OPT_SYNCH 0x00000006 ///< Recording datetime -#define cbFILECFG_OPT_OPEN 0x00000007 ///< Launch File dialog, do not set or do anything -#define cbFILECFG_OPT_TIMEOUT 0x00000008 ///< Keep alive not received so it timed out -#define cbFILECFG_OPT_PAUSE 0x00000009 ///< Recording paused - -// file save configuration packet -#define cbPKTTYPE_REPFILECFG 0x61 -#define cbPKTTYPE_SETFILECFG 0xE1 -#define cbPKTDLEN_FILECFG ((sizeof(cbPKT_FILECFG)/4) - cbPKT_HEADER_32SIZE) -#define cbPKTDLEN_FILECFGSHORT (cbPKTDLEN_FILECFG - ((sizeof(char)*3*cbLEN_STR_COMMENT)/4)) ///< used for keep-alive messages +constexpr uint32_t cbFILECFG_OPT_NONE = 0x00000000; ///< Launch File dialog, set file info, start or stop recording +constexpr uint32_t cbFILECFG_OPT_KEEPALIVE = 0x00000001; ///< Keep-alive message +constexpr uint32_t cbFILECFG_OPT_REC = 0x00000002; ///< Recording is in progress +constexpr uint32_t cbFILECFG_OPT_STOP = 0x00000003; ///< Recording stopped +constexpr uint32_t cbFILECFG_OPT_NMREC = 0x00000004; ///< NeuroMotive recording status +constexpr uint32_t cbFILECFG_OPT_CLOSE = 0x00000005; ///< Close file application +constexpr uint32_t cbFILECFG_OPT_SYNCH = 0x00000006; ///< Recording datetime +constexpr uint32_t cbFILECFG_OPT_OPEN = 0x00000007; ///< Launch File dialog, do not set or do anything +constexpr uint32_t cbFILECFG_OPT_TIMEOUT = 0x00000008; ///< Keep alive not received so it timed out +constexpr uint32_t cbFILECFG_OPT_PAUSE = 0x00000009; ///< Recording paused /// @brief PKT Set:0xE1 Rep:0x61 - File configuration packet /// @@ -1421,6 +1415,10 @@ typedef struct { char comment[cbLEN_STR_COMMENT]; ///< comment to include in the file } cbPKT_FILECFG; +// file save configuration packet +constexpr uint32_t cbPKTDLEN_FILECFG = ((sizeof(cbPKT_FILECFG)/4) - cbPKT_HEADER_32SIZE); +constexpr uint32_t cbPKTDLEN_FILECFGSHORT = (cbPKTDLEN_FILECFG - ((sizeof(char)*3*cbLEN_STR_COMMENT)/4)); ///< used for keep-alive messages + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1430,24 +1428,20 @@ typedef struct { /// @{ // Log modes -#define cbLOG_MODE_NONE 0 ///< Normal log -#define cbLOG_MODE_CRITICAL 1 ///< Critical log -#define cbLOG_MODE_RPC 2 ///< PC->NSP: Remote Procedure Call (RPC) -#define cbLOG_MODE_PLUGINFO 3 ///< NSP->PC: Plugin information -#define cbLOG_MODE_RPC_RES 4 ///< NSP->PC: Remote Procedure Call Results -#define cbLOG_MODE_PLUGINERR 5 ///< NSP->PC: Plugin error information -#define cbLOG_MODE_RPC_END 6 ///< NSP->PC: Last RPC packet -#define cbLOG_MODE_RPC_KILL 7 ///< PC->NSP: terminate last RPC -#define cbLOG_MODE_RPC_INPUT 8 ///< PC->NSP: RPC command input -#define cbLOG_MODE_UPLOAD_RES 9 ///< NSP->PC: Upload result -#define cbLOG_MODE_ENDPLUGIN 10 ///< PC->NSP: Signal the plugin to end -#define cbLOG_MODE_NSP_REBOOT 11 ///< PC->NSP: Reboot the NSP - -#define cbMAX_LOG 130 ///< Maximum log description -#define cbPKTTYPE_LOGREP 0x63 ///< NPLAY->PC response -#define cbPKTTYPE_LOGSET 0xE3 ///< PC->NPLAY request -#define cbPKTDLEN_LOG ((sizeof(cbPKT_LOG)/4) - cbPKT_HEADER_32SIZE) -#define cbPKTDLEN_LOGSHORT (cbPKTDLEN_LOG - ((sizeof(char)*cbMAX_LOG)/4)) ///< All but description +constexpr uint32_t cbLOG_MODE_NONE = 0; ///< Normal log +constexpr uint32_t cbLOG_MODE_CRITICAL = 1; ///< Critical log +constexpr uint32_t cbLOG_MODE_RPC = 2; ///< PC->NSP: Remote Procedure Call (RPC) +constexpr uint32_t cbLOG_MODE_PLUGINFO = 3; ///< NSP->PC: Plugin information +constexpr uint32_t cbLOG_MODE_RPC_RES = 4; ///< NSP->PC: Remote Procedure Call Results +constexpr uint32_t cbLOG_MODE_PLUGINERR = 5; ///< NSP->PC: Plugin error information +constexpr uint32_t cbLOG_MODE_RPC_END = 6; ///< NSP->PC: Last RPC packet +constexpr uint32_t cbLOG_MODE_RPC_KILL = 7; ///< PC->NSP: terminate last RPC +constexpr uint32_t cbLOG_MODE_RPC_INPUT = 8; ///< PC->NSP: RPC command input +constexpr uint32_t cbLOG_MODE_UPLOAD_RES = 9; ///< NSP->PC: Upload result +constexpr uint32_t cbLOG_MODE_ENDPLUGIN = 10; ///< PC->NSP: Signal the plugin to end +constexpr uint32_t cbLOG_MODE_NSP_REBOOT = 11; ///< PC->NSP: Reboot the NSP + +constexpr uint32_t cbMAX_LOG = 130; ///< Maximum log description /// @brief PKT Set:0xE3 Rep:0x63 - Log packet /// @@ -1460,6 +1454,9 @@ typedef struct { char desc[cbMAX_LOG]; ///< description of the change (will fill the rest of the packet) } cbPKT_LOG; +constexpr uint32_t cbPKTDLEN_LOG = ((sizeof(cbPKT_LOG)/4) - cbPKT_HEADER_32SIZE); +constexpr uint32_t cbPKTDLEN_LOGSHORT = (cbPKTDLEN_LOG - ((sizeof(char)*cbMAX_LOG)/4)); ///< All but description + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1468,11 +1465,7 @@ typedef struct { /// Ground truth from upstream/cbproto/cbproto.h lines 1586-1605 /// @{ -#define cbMAX_PATIENTSTRING 128 ///< Maximum patient string length - -#define cbPKTTYPE_REPPATIENTINFO 0x64 -#define cbPKTTYPE_SETPATIENTINFO 0xE4 -#define cbPKTDLEN_PATIENTINFO ((sizeof(cbPKT_PATIENTINFO)/4) - cbPKT_HEADER_32SIZE) +constexpr uint32_t cbMAX_PATIENTSTRING = 128; ///< Maximum patient string length /// @brief PKT Set:0xE4 Rep:0x64 - Patient information packet. /// @@ -1488,6 +1481,8 @@ typedef struct { uint32_t DOBYear; ///< Patient birth year } cbPKT_PATIENTINFO; +constexpr uint32_t cbPKTDLEN_PATIENTINFO = ((sizeof(cbPKT_PATIENTINFO)/4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1496,10 +1491,6 @@ typedef struct { /// Ground truth from upstream/cbproto/cbproto.h lines 1607-1659 /// @{ -#define cbPKTTYPE_REPIMPEDANCE 0x65 -#define cbPKTTYPE_SETIMPEDANCE 0xE5 -#define cbPKTDLEN_IMPEDANCE ((sizeof(cbPKT_IMPEDANCE)/4) - cbPKT_HEADER_32SIZE) - /// @brief *Deprecated* Send impedance data typedef struct { cbPKT_HEADER cbpkt_header; ///< packet header @@ -1507,9 +1498,7 @@ typedef struct { float data[(cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE) / sizeof(float)]; ///< variable length address list } cbPKT_IMPEDANCE; -#define cbPKTTYPE_REPINITIMPEDANCE 0x66 -#define cbPKTTYPE_SETINITIMPEDANCE 0xE6 -#define cbPKTDLEN_INITIMPEDANCE ((sizeof(cbPKT_INITIMPEDANCE)/4) - cbPKT_HEADER_32SIZE) +constexpr uint32_t cbPKTDLEN_IMPEDANCE = ((sizeof(cbPKT_IMPEDANCE)/4) - cbPKT_HEADER_32SIZE); /// @brief *Deprecated* Initiate impedance calculations typedef struct { @@ -1519,6 +1508,8 @@ typedef struct { ///< on response -> 1 initiated } cbPKT_INITIMPEDANCE; +constexpr uint32_t cbPKTDLEN_INITIMPEDANCE = ((sizeof(cbPKT_INITIMPEDANCE)/4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1528,21 +1519,17 @@ typedef struct { /// @{ // Poll packet command -#define cbPOLL_MODE_NONE 0 ///< no command (parameters) -#define cbPOLL_MODE_APPSTATUS 1 ///< Poll or response to poll about the status of an application +constexpr uint32_t cbPOLL_MODE_NONE = 0; ///< no command (parameters) +constexpr uint32_t cbPOLL_MODE_APPSTATUS = 1; ///< Poll or response to poll about the status of an application // Poll packet status flags -#define cbPOLL_FLAG_NONE 0 ///< no flag (parameters) -#define cbPOLL_FLAG_RESPONSE 1 ///< Response to the query +constexpr uint32_t cbPOLL_FLAG_NONE = 0; ///< no flag (parameters) +constexpr uint32_t cbPOLL_FLAG_RESPONSE = 1; ///< Response to the query // Extra information -#define cbPOLL_EXT_NONE 0 ///< No extra information -#define cbPOLL_EXT_EXISTS 1 ///< App exists -#define cbPOLL_EXT_RUNNING 2 ///< App is running - -#define cbPKTTYPE_REPPOLL 0x67 -#define cbPKTTYPE_SETPOLL 0xE7 -#define cbPKTDLEN_POLL ((sizeof(cbPKT_POLL)/4) - cbPKT_HEADER_32SIZE) +constexpr uint32_t cbPOLL_EXT_NONE = 0; ///< No extra information +constexpr uint32_t cbPOLL_EXT_EXISTS = 1; ///< App exists +constexpr uint32_t cbPOLL_EXT_RUNNING = 2; ///< App is running /// @brief *Deprecated* Poll for packet mechanism typedef struct { @@ -1556,6 +1543,8 @@ typedef struct { uint32_t res[32]; ///< reserved for the future } cbPKT_POLL; +constexpr uint32_t cbPKTDLEN_POLL = ((sizeof(cbPKT_POLL)/4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1564,10 +1553,6 @@ typedef struct { /// Ground truth from upstream/cbproto/cbproto.h lines 1661-1673 /// @{ -#define cbPKTTYPE_REPMAPFILE 0x68 -#define cbPKTTYPE_SETMAPFILE 0xE8 -#define cbPKTDLEN_MAPFILE ((sizeof(cbPKT_MAPFILE)/4) - cbPKT_HEADER_32SIZE) - /// @brief PKT Set:0xE8 Rep:0x68 - Map file /// /// Sets the mapfile for applications that use a mapfile so they all display similarly. @@ -1577,6 +1562,8 @@ typedef struct { char filename[512]; ///< filename of the mapfile to use } cbPKT_MAPFILE; +constexpr uint32_t cbPKTDLEN_MAPFILE = ((sizeof(cbPKT_MAPFILE)/4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1586,25 +1573,20 @@ typedef struct { /// @{ // Spike sorting algorithm identifiers -#define cbAUTOALG_NONE 0 ///< No sorting -#define cbAUTOALG_SPREAD 1 ///< Auto spread -#define cbAUTOALG_HIST_CORR_MAJ 2 ///< Auto Hist Correlation -#define cbAUTOALG_HIST_PEAK_COUNT_MAJ 3 ///< Auto Hist Peak Maj -#define cbAUTOALG_HIST_PEAK_COUNT_FISH 4 ///< Auto Hist Peak Fish -#define cbAUTOALG_PCA 5 ///< Manual PCA -#define cbAUTOALG_HOOPS 6 ///< Manual Hoops -#define cbAUTOALG_PCA_KMEANS 7 ///< K-means PCA -#define cbAUTOALG_PCA_EM 8 ///< EM-clustering PCA -#define cbAUTOALG_PCA_DBSCAN 9 ///< DBSCAN PCA +constexpr uint32_t cbAUTOALG_NONE = 0; ///< No sorting +constexpr uint32_t cbAUTOALG_SPREAD = 1; ///< Auto spread +constexpr uint32_t cbAUTOALG_HIST_CORR_MAJ = 2; ///< Auto Hist Correlation +constexpr uint32_t cbAUTOALG_HIST_PEAK_COUNT_MAJ = 3; ///< Auto Hist Peak Maj +constexpr uint32_t cbAUTOALG_HIST_PEAK_COUNT_FISH = 4; ///< Auto Hist Peak Fish +constexpr uint32_t cbAUTOALG_PCA = 5; ///< Manual PCA +constexpr uint32_t cbAUTOALG_HOOPS = 6; ///< Manual Hoops +constexpr uint32_t cbAUTOALG_PCA_KMEANS = 7; ///< K-means PCA +constexpr uint32_t cbAUTOALG_PCA_EM = 8; ///< EM-clustering PCA +constexpr uint32_t cbAUTOALG_PCA_DBSCAN = 9; ///< DBSCAN PCA // Spike sorting mode commands -#define cbAUTOALG_MODE_SETTING 0 ///< Change the settings and leave sorting the same (PC->NSP request) -#define cbAUTOALG_MODE_APPLY 1 ///< Change settings and apply this sorting to all channels (PC->NSP request) - -// SS Model All constants -#define cbPKTTYPE_SS_MODELALLREP 0x50 ///< NSP->PC response -#define cbPKTTYPE_SS_MODELALLSET 0xD0 ///< PC->NSP request -#define cbPKTDLEN_SS_MODELALLSET ((sizeof(cbPKT_SS_MODELALLSET) / 4) - cbPKT_HEADER_32SIZE) +constexpr uint32_t cbAUTOALG_MODE_SETTING = 0; ///< Change the settings and leave sorting the same (PC->NSP request) +constexpr uint32_t cbAUTOALG_MODE_APPLY = 1; ///< Change settings and apply this sorting to all channels (PC->NSP request) /// @brief PKT Set:0xD0 Rep:0x50 - Get the spike sorting model for all channels (Histogram Peak Count) /// @@ -1613,11 +1595,8 @@ typedef struct { cbPKT_HEADER cbpkt_header; ///< packet header } cbPKT_SS_MODELALLSET; -// SS Model constants -#define cbPKTTYPE_SS_MODELREP 0x51 ///< NSP->PC response -#define cbPKTTYPE_SS_MODELSET 0xD1 ///< PC->NSP request -#define cbPKTDLEN_SS_MODELSET ((sizeof(cbPKT_SS_MODELSET) / 4) - cbPKT_HEADER_32SIZE) -#define MAX_REPEL_POINTS 3 +// SS Model All constants +constexpr uint32_t cbPKTDLEN_SS_MODELALLSET = ((sizeof(cbPKT_SS_MODELALLSET) / 4) - cbPKT_HEADER_32SIZE); /// @brief PKT Set:0xD1 Rep:0x51 - Get the spike sorting model for a single channel (Histogram Peak Count) /// @@ -1645,10 +1624,9 @@ typedef struct { float sigma_e_squared; } cbPKT_SS_MODELSET; -// SS Detect constants -#define cbPKTTYPE_SS_DETECTREP 0x52 ///< NSP->PC response -#define cbPKTTYPE_SS_DETECTSET 0xD2 ///< PC->NSP request -#define cbPKTDLEN_SS_DETECT ((sizeof(cbPKT_SS_DETECT) / 4) - cbPKT_HEADER_32SIZE) +// SS Model constants +constexpr uint32_t cbPKTDLEN_SS_MODELSET = ((sizeof(cbPKT_SS_MODELSET) / 4) - cbPKT_HEADER_32SIZE); +constexpr uint32_t MAX_REPEL_POINTS = 3; /// @brief PKT Set:0xD2 Rep:0x52 - Auto threshold parameters /// @@ -1660,10 +1638,8 @@ typedef struct { float fMultiplier; ///< multiplier } cbPKT_SS_DETECT; -// SS Artifact Reject constants -#define cbPKTTYPE_SS_ARTIF_REJECTREP 0x53 ///< NSP->PC response -#define cbPKTTYPE_SS_ARTIF_REJECTSET 0xD3 ///< PC->NSP request -#define cbPKTDLEN_SS_ARTIF_REJECT ((sizeof(cbPKT_SS_ARTIF_REJECT) / 4) - cbPKT_HEADER_32SIZE) +// SS Detect constants +constexpr uint32_t cbPKTDLEN_SS_DETECT = ((sizeof(cbPKT_SS_DETECT) / 4) - cbPKT_HEADER_32SIZE); /// @brief PKT Set:0xD3 Rep:0x53 - Artifact reject /// @@ -1675,10 +1651,8 @@ typedef struct { uint32_t nRefractoryCount; ///< for how many samples (30 kHz) is a neuron refractory, so can't re-trigger } cbPKT_SS_ARTIF_REJECT; -// SS Noise Boundary constants -#define cbPKTTYPE_SS_NOISE_BOUNDARYREP 0x54 ///< NSP->PC response -#define cbPKTTYPE_SS_NOISE_BOUNDARYSET 0xD4 ///< PC->NSP request -#define cbPKTDLEN_SS_NOISE_BOUNDARY ((sizeof(cbPKT_SS_NOISE_BOUNDARY) / 4) - cbPKT_HEADER_32SIZE) +// SS Artifact Reject constants +constexpr uint32_t cbPKTDLEN_SS_ARTIF_REJECT = ((sizeof(cbPKT_SS_ARTIF_REJECT) / 4) - cbPKT_HEADER_32SIZE); /// @brief PKT Set:0xD4 Rep:0x54 - Noise boundary /// @@ -1691,10 +1665,8 @@ typedef struct { float afS[3][3]; ///< an array of the axes for the ellipsoid } cbPKT_SS_NOISE_BOUNDARY; -// SS Statistics constants -#define cbPKTTYPE_SS_STATISTICSREP 0x55 ///< NSP->PC response -#define cbPKTTYPE_SS_STATISTICSSET 0xD5 ///< PC->NSP request -#define cbPKTDLEN_SS_STATISTICS ((sizeof(cbPKT_SS_STATISTICS) / 4) - cbPKT_HEADER_32SIZE) +// SS Noise Boundary constants +constexpr uint32_t cbPKTDLEN_SS_NOISE_BOUNDARY = ((sizeof(cbPKT_SS_NOISE_BOUNDARY) / 4) - cbPKT_HEADER_32SIZE); /// @brief PKT Set:0xD5 Rep:0x55 - Spike sourting statistics (Histogram peak count) typedef struct { @@ -1723,10 +1695,8 @@ typedef struct { ///< the same PCA basis before next } cbPKT_SS_STATISTICS; -// SS Status constants -#define cbPKTTYPE_SS_STATUSREP 0x57 ///< NSP->PC response -#define cbPKTTYPE_SS_STATUSSET 0xD7 ///< PC->NSP request -#define cbPKTDLEN_SS_STATUS ((sizeof(cbPKT_SS_STATUS) / 4) - cbPKT_HEADER_32SIZE) +// SS Statistics constants +constexpr uint32_t cbPKTDLEN_SS_STATISTICS = ((sizeof(cbPKT_SS_STATISTICS) / 4) - cbPKT_HEADER_32SIZE); /// @brief PKT Set:0xD7 Rep:0x57 - Spike sorting status (Histogram peak count) /// @@ -1738,10 +1708,8 @@ typedef struct { cbAdaptControl cntlNumUnits; ///< } cbPKT_SS_STATUS; -// SS Reset constants -#define cbPKTTYPE_SS_RESETREP 0x56 ///< NSP->PC response -#define cbPKTTYPE_SS_RESETSET 0xD6 ///< PC->NSP request -#define cbPKTDLEN_SS_RESET ((sizeof(cbPKT_SS_RESET) / 4) - cbPKT_HEADER_32SIZE) +// SS Status constants +constexpr uint32_t cbPKTDLEN_SS_STATUS = ((sizeof(cbPKT_SS_STATUS) / 4) - cbPKT_HEADER_32SIZE); /// @brief PKT Set:0xD6 Rep:0x56 - Spike sorting reset /// @@ -1751,10 +1719,8 @@ typedef struct cbPKT_HEADER cbpkt_header; ///< packet header } cbPKT_SS_RESET; -// SS Reset Model constants -#define cbPKTTYPE_SS_RESET_MODEL_REP 0x58 ///< NSP->PC response -#define cbPKTTYPE_SS_RESET_MODEL_SET 0xD8 ///< PC->NSP request -#define cbPKTDLEN_SS_RESET_MODEL ((sizeof(cbPKT_SS_RESET_MODEL) / 4) - cbPKT_HEADER_32SIZE) +// SS Reset constants +constexpr uint32_t cbPKTDLEN_SS_RESET = ((sizeof(cbPKT_SS_RESET) / 4) - cbPKT_HEADER_32SIZE); /// @brief PKT Set:0xD8 Rep:0x58 - Spike sorting reset model /// @@ -1764,19 +1730,17 @@ typedef struct cbPKT_HEADER cbpkt_header; ///< packet header } cbPKT_SS_RESET_MODEL; -// Feature space commands and status changes -#define cbPCA_RECALC_START 0 ///< PC ->NSP start recalculation -#define cbPCA_RECALC_STOPPED 1 ///< NSP->PC finished recalculation -#define cbPCA_COLLECTION_STARTED 2 ///< NSP->PC waveform collection started -#define cbBASIS_CHANGE 3 ///< Change the basis of feature space -#define cbUNDO_BASIS_CHANGE 4 -#define cbREDO_BASIS_CHANGE 5 -#define cbINVALIDATE_BASIS 6 +// SS Reset Model constants +constexpr uint32_t cbPKTDLEN_SS_RESET_MODEL = ((sizeof(cbPKT_SS_RESET_MODEL) / 4) - cbPKT_HEADER_32SIZE); -// SS Recalc constants -#define cbPKTTYPE_SS_RECALCREP 0x59 ///< NSP->PC response -#define cbPKTTYPE_SS_RECALCSET 0xD9 ///< PC->NSP request -#define cbPKTDLEN_SS_RECALC ((sizeof(cbPKT_SS_RECALC) / 4) - cbPKT_HEADER_32SIZE) +// Feature space commands and status changes +constexpr uint32_t cbPCA_RECALC_START = 0; ///< PC ->NSP start recalculation +constexpr uint32_t cbPCA_RECALC_STOPPED = 1; ///< NSP->PC finished recalculation +constexpr uint32_t cbPCA_COLLECTION_STARTED = 2; ///< NSP->PC waveform collection started +constexpr uint32_t cbBASIS_CHANGE = 3; ///< Change the basis of feature space +constexpr uint32_t cbUNDO_BASIS_CHANGE = 4; +constexpr uint32_t cbREDO_BASIS_CHANGE = 5; +constexpr uint32_t cbINVALIDATE_BASIS = 6; /// @brief PKT Set:0xD9 Rep:0x59 - Spike Sorting recalculate PCA /// @@ -1789,6 +1753,9 @@ typedef struct uint32_t mode; ///< cbPCA_RECALC_START -> Start PCA basis, cbPCA_RECALC_STOPPED-> PCA basis stopped, cbPCA_COLLECTION_STARTED -> PCA waveform collection started } cbPKT_SS_RECALC; +// SS Recalc constants +constexpr uint32_t cbPKTDLEN_SS_RECALC = ((sizeof(cbPKT_SS_RECALC) / 4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1797,11 +1764,6 @@ typedef struct /// Ground truth from upstream/cbproto/cbproto.h lines 1889-1909 /// @{ -#define cbPKTTYPE_FS_BASISREP 0x5B ///< NSP->PC response -#define cbPKTTYPE_FS_BASISSET 0xDB ///< PC->NSP request -#define cbPKTDLEN_FS_BASIS ((sizeof(cbPKT_FS_BASIS) / 4) - cbPKT_HEADER_32SIZE) -#define cbPKTDLEN_FS_BASISSHORT (cbPKTDLEN_FS_BASIS - ((sizeof(float)* cbMAX_PNTS * 3)/4)) - /// @brief PKT Set:0xDB Rep:0x5B - Feature Space Basis /// /// This packet holds the calculated basis of the feature space from NSP to Central @@ -1817,6 +1779,9 @@ typedef struct float basis[cbMAX_PNTS][3]; ///< Room for all possible points collected } cbPKT_FS_BASIS; +constexpr uint32_t cbPKTDLEN_FS_BASIS = ((sizeof(cbPKT_FS_BASIS) / 4) - cbPKT_HEADER_32SIZE); +constexpr uint32_t cbPKTDLEN_FS_BASISSHORT = (cbPKTDLEN_FS_BASIS - ((sizeof(float)* cbMAX_PNTS * 3)/4)); + /// @} @@ -1833,12 +1798,12 @@ typedef struct { } cbVIDEOSOURCE; // Track object types -#define cbTRACKOBJ_TYPE_UNDEFINED 0 ///< Undefined track object type -#define cbTRACKOBJ_TYPE_2DMARKERS 1 ///< 2D marker tracking -#define cbTRACKOBJ_TYPE_2DBLOB 2 ///< 2D blob tracking -#define cbTRACKOBJ_TYPE_3DMARKERS 3 ///< 3D marker tracking -#define cbTRACKOBJ_TYPE_2DBOUNDARY 4 ///< 2D boundary tracking -#define cbTRACKOBJ_TYPE_1DSIZE 5 ///< 1D size tracking +constexpr uint32_t cbTRACKOBJ_TYPE_UNDEFINED = 0; ///< Undefined track object type +constexpr uint32_t cbTRACKOBJ_TYPE_2DMARKERS = 1; ///< 2D marker tracking +constexpr uint32_t cbTRACKOBJ_TYPE_2DBLOB = 2; ///< 2D blob tracking +constexpr uint32_t cbTRACKOBJ_TYPE_3DMARKERS = 3; ///< 3D marker tracking +constexpr uint32_t cbTRACKOBJ_TYPE_2DBOUNDARY = 4; ///< 2D boundary tracking +constexpr uint32_t cbTRACKOBJ_TYPE_1DSIZE = 5; ///< 1D size tracking /// @brief Track object structure for NeuroMotive typedef struct { @@ -1848,30 +1813,26 @@ typedef struct { } cbTRACKOBJ; // NeuroMotive status -#define cbNM_STATUS_IDLE 0 ///< NeuroMotive is idle -#define cbNM_STATUS_EXIT 1 ///< NeuroMotive is exiting -#define cbNM_STATUS_REC 2 ///< NeuroMotive is recording -#define cbNM_STATUS_PLAY 3 ///< NeuroMotive is playing video file -#define cbNM_STATUS_CAP 4 ///< NeuroMotive is capturing from camera -#define cbNM_STATUS_STOP 5 ///< NeuroMotive is stopping -#define cbNM_STATUS_PAUSED 6 ///< NeuroMotive is paused -#define cbNM_STATUS_COUNT 7 ///< This is the count of status options +constexpr uint32_t cbNM_STATUS_IDLE = 0; ///< NeuroMotive is idle +constexpr uint32_t cbNM_STATUS_EXIT = 1; ///< NeuroMotive is exiting +constexpr uint32_t cbNM_STATUS_REC = 2; ///< NeuroMotive is recording +constexpr uint32_t cbNM_STATUS_PLAY = 3; ///< NeuroMotive is playing video file +constexpr uint32_t cbNM_STATUS_CAP = 4; ///< NeuroMotive is capturing from camera +constexpr uint32_t cbNM_STATUS_STOP = 5; ///< NeuroMotive is stopping +constexpr uint32_t cbNM_STATUS_PAUSED = 6; ///< NeuroMotive is paused +constexpr uint32_t cbNM_STATUS_COUNT = 7; ///< This is the count of status options // NeuroMotive commands and status changes (cbPKT_NM.mode) -#define cbNM_MODE_NONE 0 ///< No command -#define cbNM_MODE_CONFIG 1 ///< Ask NeuroMotive for configuration -#define cbNM_MODE_SETVIDEOSOURCE 2 ///< Configure video source -#define cbNM_MODE_SETTRACKABLE 3 ///< Configure trackable -#define cbNM_MODE_STATUS 4 ///< NeuroMotive status reporting (cbNM_STATUS_*) -#define cbNM_MODE_TSCOUNT 5 ///< Timestamp count (value is the period with 0 to disable this mode) -#define cbNM_MODE_SYNCHCLOCK 6 ///< Start (or stop) synchronization clock (fps*1000 specified by value, zero fps to stop capture) -#define cbNM_MODE_ASYNCHCLOCK 7 ///< Asynchronous clock +constexpr uint32_t cbNM_MODE_NONE = 0; ///< No command +constexpr uint32_t cbNM_MODE_CONFIG = 1; ///< Ask NeuroMotive for configuration +constexpr uint32_t cbNM_MODE_SETVIDEOSOURCE = 2; ///< Configure video source +constexpr uint32_t cbNM_MODE_SETTRACKABLE = 3; ///< Configure trackable +constexpr uint32_t cbNM_MODE_STATUS = 4; ///< NeuroMotive status reporting (cbNM_STATUS_*) +constexpr uint32_t cbNM_MODE_TSCOUNT = 5; ///< Timestamp count (value is the period with 0 to disable this mode) +constexpr uint32_t cbNM_MODE_SYNCHCLOCK = 6; ///< Start (or stop) synchronization clock (fps*1000 specified by value, zero fps to stop capture) +constexpr uint32_t cbNM_MODE_ASYNCHCLOCK = 7; ///< Asynchronous clock -#define cbNM_FLAG_NONE 0 ///< No flags - -#define cbPKTTYPE_NMREP 0x32 ///< NSP->PC response -#define cbPKTTYPE_NMSET 0xB2 ///< PC->NSP request -#define cbPKTDLEN_NM ((sizeof(cbPKT_NM)/4) - cbPKT_HEADER_32SIZE) +constexpr uint32_t cbNM_FLAG_NONE = 0; ///< No flags /// @brief PKT Set:0xB2 Rep:0x32 - NeuroMotive packet structure /// @@ -1888,6 +1849,8 @@ typedef struct { }; } cbPKT_NM; +constexpr uint32_t cbPKTDLEN_NM = ((sizeof(cbPKT_NM)/4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1904,10 +1867,6 @@ enum cbNTRODEINFO_FS_MODE { cbNTRODEINFO_FS_COUNT ///< Number of feature space modes }; -#define cbPKTTYPE_REPNTRODEINFO 0x27 ///< NSP->PC response -#define cbPKTTYPE_SETNTRODEINFO 0xA7 ///< PC->NSP request -#define cbPKTDLEN_NTRODEINFO ((sizeof(cbPKT_NTRODEINFO) / 4) - cbPKT_HEADER_32SIZE) - /// @brief PKT Set:0xA7 Rep:0x27 - N-Trode information packets /// /// Sets information about an N-Trode. The user can change the name, number of sites, sites (channels) @@ -1922,6 +1881,8 @@ typedef struct { uint16_t nChan[cbMAXSITES]; ///< group of channels in this NTrode } cbPKT_NTRODEINFO; +constexpr uint32_t cbPKTDLEN_NTRODEINFO = ((sizeof(cbPKT_NTRODEINFO) / 4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1930,7 +1891,7 @@ typedef struct { /// Ground truth from upstream/cbproto/cbproto.h lines 1943-2008 /// @{ -#define cbMAX_WAVEFORM_PHASES ((cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - 24) / 4) ///< Maximum number of phases in a waveform +constexpr uint32_t cbMAX_WAVEFORM_PHASES = ((cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - 24) / 4); ///< Maximum number of phases in a waveform /// @brief Analog output waveform data /// @@ -1954,23 +1915,18 @@ typedef struct } cbWaveformData; // Signal generator waveform type -#define cbWAVEFORM_MODE_NONE 0 ///< waveform is disabled -#define cbWAVEFORM_MODE_PARAMETERS 1 ///< waveform is a repeated sequence -#define cbWAVEFORM_MODE_SINE 2 ///< waveform is a sinusoids +constexpr uint32_t cbWAVEFORM_MODE_NONE = 0; ///< waveform is disabled +constexpr uint32_t cbWAVEFORM_MODE_PARAMETERS = 1; ///< waveform is a repeated sequence +constexpr uint32_t cbWAVEFORM_MODE_SINE = 2; ///< waveform is a sinusoids // Signal generator waveform trigger type -#define cbWAVEFORM_TRIGGER_NONE 0 ///< instant software trigger -#define cbWAVEFORM_TRIGGER_DINPREG 1 ///< digital input rising edge trigger -#define cbWAVEFORM_TRIGGER_DINPFEG 2 ///< digital input falling edge trigger -#define cbWAVEFORM_TRIGGER_SPIKEUNIT 3 ///< spike unit -#define cbWAVEFORM_TRIGGER_COMMENTCOLOR 4 ///< comment RGBA color (A being big byte) -#define cbWAVEFORM_TRIGGER_RECORDINGSTART 5 ///< recording start trigger -#define cbWAVEFORM_TRIGGER_EXTENSION 6 ///< extension trigger - -// AOUT signal generator waveform data -#define cbPKTTYPE_WAVEFORMREP 0x33 ///< NSP->PC response -#define cbPKTTYPE_WAVEFORMSET 0xB3 ///< PC->NSP request -#define cbPKTDLEN_WAVEFORM ((sizeof(cbPKT_AOUT_WAVEFORM)/4) - cbPKT_HEADER_32SIZE) +constexpr uint32_t cbWAVEFORM_TRIGGER_NONE = 0; ///< instant software trigger +constexpr uint32_t cbWAVEFORM_TRIGGER_DINPREG = 1; ///< digital input rising edge trigger +constexpr uint32_t cbWAVEFORM_TRIGGER_DINPFEG = 2; ///< digital input falling edge trigger +constexpr uint32_t cbWAVEFORM_TRIGGER_SPIKEUNIT = 3; ///< spike unit +constexpr uint32_t cbWAVEFORM_TRIGGER_COMMENTCOLOR = 4; ///< comment RGBA color (A being big byte) +constexpr uint32_t cbWAVEFORM_TRIGGER_RECORDINGSTART = 5; ///< recording start trigger +constexpr uint32_t cbWAVEFORM_TRIGGER_EXTENSION = 6; ///< extension trigger /// @brief PKT Set:0xB3 Rep:0x33 - AOUT waveform /// @@ -1999,6 +1955,9 @@ typedef struct { cbWaveformData wave; ///< Actual waveform data } cbPKT_AOUT_WAVEFORM; +// AOUT signal generator waveform data +constexpr uint32_t cbPKTDLEN_WAVEFORM = ((sizeof(cbPKT_AOUT_WAVEFORM)/4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -2007,10 +1966,6 @@ typedef struct { /// Ground truth from upstream/cbproto/cbproto.h lines 2010-2022 /// @{ -#define cbPKTTYPE_STIMULATIONREP 0x34 ///< NSP->PC response -#define cbPKTTYPE_STIMULATIONSET 0xB4 ///< PC->NSP request -#define cbPKTDLEN_STIMULATION ((sizeof(cbPKT_STIMULATION)/4) - cbPKT_HEADER_32SIZE) - /// @brief PKT Set:0xB4 Rep:0x34 - Stimulation command /// /// This sets a user defined stimulation for stim/record headstages @@ -2020,6 +1975,8 @@ typedef struct { uint8_t commandBytes[40]; ///< series of bytes to control stimulation } cbPKT_STIMULATION; +constexpr uint32_t cbPKTDLEN_STIMULATION = ((sizeof(cbPKT_STIMULATION)/4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -2029,41 +1986,36 @@ typedef struct { /// @{ // Audio commands "val" -#define cbAUDIO_CMD_NONE 0 ///< PC->NPLAY query audio status +constexpr uint32_t cbAUDIO_CMD_NONE = 0; ///< PC->NPLAY query audio status // nPlay file version (first byte NSx version, second byte NEV version) -#define cbNPLAY_FILE_NS21 1 ///< NSX 2.1 file -#define cbNPLAY_FILE_NS22 2 ///< NSX 2.2 file -#define cbNPLAY_FILE_NS30 3 ///< NSX 3.0 file -#define cbNPLAY_FILE_NEV21 (1 << 8) ///< Nev 2.1 file -#define cbNPLAY_FILE_NEV22 (2 << 8) ///< Nev 2.2 file -#define cbNPLAY_FILE_NEV23 (3 << 8) ///< Nev 2.3 file -#define cbNPLAY_FILE_NEV30 (4 << 8) ///< Nev 3.0 file +constexpr uint32_t cbNPLAY_FILE_NS21 = 1; ///< NSX 2.1 file +constexpr uint32_t cbNPLAY_FILE_NS22 = 2; ///< NSX 2.2 file +constexpr uint32_t cbNPLAY_FILE_NS30 = 3; ///< NSX 3.0 file +constexpr uint32_t cbNPLAY_FILE_NEV21 = (1 << 8); ///< Nev 2.1 file +constexpr uint32_t cbNPLAY_FILE_NEV22 = (2 << 8); ///< Nev 2.2 file +constexpr uint32_t cbNPLAY_FILE_NEV23 = (3 << 8); ///< Nev 2.3 file +constexpr uint32_t cbNPLAY_FILE_NEV30 = (4 << 8); ///< Nev 3.0 file // nPlay commands and status changes (cbPKT_NPLAY.mode) -#define cbNPLAY_FNAME_LEN (cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - 40) ///< length of the file name (with terminating null) -#define cbNPLAY_MODE_NONE 0 ///< no command (parameters) -#define cbNPLAY_MODE_PAUSE 1 ///< PC->NPLAY pause if "val" is non-zero, un-pause otherwise -#define cbNPLAY_MODE_SEEK 2 ///< PC->NPLAY seek to time "val" -#define cbNPLAY_MODE_CONFIG 3 ///< PC<->NPLAY request full config -#define cbNPLAY_MODE_OPEN 4 ///< PC->NPLAY open new file in "val" for playback -#define cbNPLAY_MODE_PATH 5 ///< PC->NPLAY use the directory path in fname -#define cbNPLAY_MODE_CONFIGMAIN 6 ///< PC<->NPLAY request main config packet -#define cbNPLAY_MODE_STEP 7 ///< PC<->NPLAY run "val" procTime steps and pause, then send cbNPLAY_FLAG_STEPPED -#define cbNPLAY_MODE_SINGLE 8 ///< PC->NPLAY single mode if "val" is non-zero, wrap otherwise -#define cbNPLAY_MODE_RESET 9 ///< PC->NPLAY reset nPlay -#define cbNPLAY_MODE_NEVRESORT 10 ///< PC->NPLAY resort NEV if "val" is non-zero, do not if otherwise -#define cbNPLAY_MODE_AUDIO_CMD 11 ///< PC->NPLAY perform audio command in "val" (cbAUDIO_CMD_*), with option "opt" - -#define cbNPLAY_FLAG_NONE 0x00 ///< no flag -#define cbNPLAY_FLAG_CONF 0x01 ///< NPLAY->PC config packet ("val" is "fname" file index) -#define cbNPLAY_FLAG_MAIN (0x02 | cbNPLAY_FLAG_CONF) ///< NPLAY->PC main config packet ("val" is file version) -#define cbNPLAY_FLAG_DONE 0x02 ///< NPLAY->PC step command done - -// nPlay configuration packet(sent on restart together with config packet) -#define cbPKTTYPE_NPLAYREP 0x5C ///< NPLAY->PC response -#define cbPKTTYPE_NPLAYSET 0xDC ///< PC->NPLAY request -#define cbPKTDLEN_NPLAY ((sizeof(cbPKT_NPLAY)/4) - cbPKT_HEADER_32SIZE) +constexpr uint32_t cbNPLAY_FNAME_LEN = (cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - 40); ///< length of the file name (with terminating null) +constexpr uint32_t cbNPLAY_MODE_NONE = 0; ///< no command (parameters) +constexpr uint32_t cbNPLAY_MODE_PAUSE = 1; ///< PC->NPLAY pause if "val" is non-zero, un-pause otherwise +constexpr uint32_t cbNPLAY_MODE_SEEK = 2; ///< PC->NPLAY seek to time "val" +constexpr uint32_t cbNPLAY_MODE_CONFIG = 3; ///< PC<->NPLAY request full config +constexpr uint32_t cbNPLAY_MODE_OPEN = 4; ///< PC->NPLAY open new file in "val" for playback +constexpr uint32_t cbNPLAY_MODE_PATH = 5; ///< PC->NPLAY use the directory path in fname +constexpr uint32_t cbNPLAY_MODE_CONFIGMAIN = 6; ///< PC<->NPLAY request main config packet +constexpr uint32_t cbNPLAY_MODE_STEP = 7; ///< PC<->NPLAY run "val" procTime steps and pause, then send cbNPLAY_FLAG_STEPPED +constexpr uint32_t cbNPLAY_MODE_SINGLE = 8; ///< PC->NPLAY single mode if "val" is non-zero, wrap otherwise +constexpr uint32_t cbNPLAY_MODE_RESET = 9; ///< PC->NPLAY reset nPlay +constexpr uint32_t cbNPLAY_MODE_NEVRESORT = 10; ///< PC->NPLAY resort NEV if "val" is non-zero, do not if otherwise +constexpr uint32_t cbNPLAY_MODE_AUDIO_CMD = 11; ///< PC->NPLAY perform audio command in "val" (cbAUDIO_CMD_*), with option "opt" + +constexpr uint32_t cbNPLAY_FLAG_NONE = 0x00; ///< no flag +constexpr uint32_t cbNPLAY_FLAG_CONF = 0x01; ///< NPLAY->PC config packet ("val" is "fname" file index) +constexpr uint32_t cbNPLAY_FLAG_MAIN = (0x02 | cbNPLAY_FLAG_CONF); ///< NPLAY->PC main config packet ("val" is file version) +constexpr uint32_t cbNPLAY_FLAG_DONE = 0x02; ///< NPLAY->PC step command done /// @brief PKT Set:0xDC Rep:0x5C - nPlay configuration packet /// @@ -2084,6 +2036,9 @@ typedef struct { char fname[cbNPLAY_FNAME_LEN]; ///< This is a String with the file name. } cbPKT_NPLAY; +// nPlay configuration packet(sent on restart together with config packet) +constexpr uint32_t cbPKTDLEN_NPLAY = ((sizeof(cbPKT_NPLAY)/4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -2092,10 +2047,6 @@ typedef struct { /// Ground truth from upstream/cbproto/cbproto.h lines 1928-1941 /// @{ -#define cbPKTTYPE_SET_DOUTREP 0x5D ///< NSP->PC response -#define cbPKTTYPE_SET_DOUTSET 0xDD ///< PC->NSP request -#define cbPKTDLEN_SET_DOUT ((sizeof(cbPKT_SET_DOUT) / 4) - cbPKT_HEADER_32SIZE) - /// @brief PKT Set:0xDD Rep:0x5D - Set Digital Output /// /// Allows setting the digital output value if not assigned set to monitor a channel or timed waveform or triggered @@ -2106,6 +2057,8 @@ typedef struct { uint16_t value; ///< Which value to set? zero = 0; non-zero = 1 (output is 1 bit) } cbPKT_SET_DOUT; +constexpr uint32_t cbPKTDLEN_SET_DOUT = ((sizeof(cbPKT_SET_DOUT) / 4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -2114,13 +2067,9 @@ typedef struct { /// Ground truth from upstream/cbproto/cbproto.h lines 967-1005 /// @{ -#define cbTRIGGER_MODE_UNDEFINED 0 -#define cbTRIGGER_MODE_BUTTONPRESS 1 ///< Patient button press event -#define cbTRIGGER_MODE_EVENTRESET 2 ///< event reset - -#define cbPKTTYPE_TRIGGERREP 0x5E ///< NPLAY->PC response -#define cbPKTTYPE_TRIGGERSET 0xDE ///< PC->NPLAY request -#define cbPKTDLEN_TRIGGER ((sizeof(cbPKT_TRIGGER)/4) - cbPKT_HEADER_32SIZE) +constexpr uint32_t cbTRIGGER_MODE_UNDEFINED = 0; +constexpr uint32_t cbTRIGGER_MODE_BUTTONPRESS = 1; ///< Patient button press event +constexpr uint32_t cbTRIGGER_MODE_EVENTRESET = 2; ///< event reset /// @brief PKT Set:0xDE Rep:0x5E - Trigger Packet used for Cervello system typedef struct { @@ -2129,12 +2078,9 @@ typedef struct { uint32_t mode; ///< cbTRIGGER_MODE_* } cbPKT_TRIGGER; -#define cbMAX_TRACKCOORDS (128) ///< Maximum number of coordinates (must be an even number) -#define cbPKTTYPE_VIDEOTRACKREP 0x5F ///< NPLAY->PC response -#define cbPKTTYPE_VIDEOTRACKSET 0xDF ///< PC->NPLAY request -#define cbPKTDLEN_VIDEOTRACK ((sizeof(cbPKT_VIDEOTRACK)/4) - cbPKT_HEADER_32SIZE) -#define cbPKTDLEN_VIDEOTRACKSHORT (cbPKTDLEN_VIDEOTRACK - ((sizeof(uint16_t)*cbMAX_TRACKCOORDS)/4)) +constexpr uint32_t cbPKTDLEN_TRIGGER = ((sizeof(cbPKT_TRIGGER)/4) - cbPKT_HEADER_32SIZE); +constexpr uint32_t cbMAX_TRACKCOORDS = (128); ///< Maximum number of coordinates (must be an even number) /// @brief PKT Set:0xDF Rep:0x5F - Video tracking event packet typedef struct { cbPKT_HEADER cbpkt_header; ///< packet header @@ -2150,6 +2096,9 @@ typedef struct { }; } cbPKT_VIDEOTRACK; +constexpr uint32_t cbPKTDLEN_VIDEOTRACK = ((sizeof(cbPKT_VIDEOTRACK)/4) - cbPKT_HEADER_32SIZE); +constexpr uint32_t cbPKTDLEN_VIDEOTRACKSHORT = (cbPKTDLEN_VIDEOTRACK - ((sizeof(uint16_t)*cbMAX_TRACKCOORDS)/4)); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -2196,11 +2145,6 @@ typedef struct { /// Ground truth from upstream/cbproto/cbproto.h lines 800-838 /// @{ -#define cbRUNLEVEL_UPDATE 78 -#define cbPKTTYPE_UPDATESET 0xF1 -#define cbPKTTYPE_UPDATEREP 0x71 -#define cbPKTDLEN_UPDATE (sizeof(cbPKT_UPDATE)/4)-2 - /// @brief PKT Set:0xF1 Rep:0x71 - Update Packet /// /// Update the firmware of the NSP. This will copy data received into files in a temporary location and if @@ -2215,7 +2159,7 @@ typedef struct { uint8_t block[512]; ///< block data } cbPKT_UPDATE; -#define cbPKTDLEN_UPDATE_OLD (sizeof(cbPKT_UPDATE_OLD)/4)-2 +constexpr uint32_t cbPKTDLEN_UPDATE = (sizeof(cbPKT_UPDATE)/4)-2; /// @brief PKT Set:0xF1 Rep:0x71 - Old Update Packet /// @@ -2235,11 +2179,11 @@ typedef struct { uint8_t block[512]; ///< block data } cbPKT_UPDATE_OLD; +constexpr uint32_t cbPKTDLEN_UPDATE_OLD = (sizeof(cbPKT_UPDATE_OLD)/4)-2; + /// @} -#ifdef __cplusplus -} -#endif +#endif // __cplusplus #pragma pack(pop) From c997d396c46ab7304d014ccf4e8254b2f4311530 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Fri, 22 May 2026 11:03:19 -0600 Subject: [PATCH 09/62] Add version-specific structs for each member variable of CentralLegacyCFGBUFF. These structs ensure that each version of CentralLegacyCFGBUFF maps exactly to the corresponding version of Central's configuration buffer. Structure differences between versions are annotated with VER: --- src/cbproto/include/cbproto/config.h | 2 +- src/cbproto/include/cbproto/types.h | 26 +- src/cbshm/include/cbshm/central_types/v3_11.h | 619 +++++++++++++++++- src/cbshm/include/cbshm/central_types/v4_0.h | 606 ++++++++++++++++- src/cbshm/include/cbshm/central_types/v4_1.h | 610 ++++++++++++++++- src/cbshm/include/cbshm/central_types/v4_2.h | 612 ++++++++++++++++- 6 files changed, 2419 insertions(+), 56 deletions(-) diff --git a/src/cbproto/include/cbproto/config.h b/src/cbproto/include/cbproto/config.h index b1dc59ee..cc67e320 100644 --- a/src/cbproto/include/cbproto/config.h +++ b/src/cbproto/include/cbproto/config.h @@ -35,7 +35,7 @@ struct SpikeSorting { // Spike sorting parameters cbPKT_SS_DETECT detect; ///< Detection parameters cbPKT_SS_ARTIF_REJECT artifact_reject; ///< Artifact rejection parameters - cbPKT_SS_NOISE_BOUNDARY noise_boundary[cbMAXCHANS]; ///< Noise boundaries per channel + cbPKT_SS_NOISE_BOUNDARY noise_boundary[cbMAXCHANS]; ///< Noise boundaries per channel // VER: 4.0+, changed to cbMAXCHANS from cbNUM_ANALOG_CHANS cbPKT_SS_STATISTICS statistics; ///< Spike statistics cbPKT_SS_STATUS status; ///< Spike sorting status }; diff --git a/src/cbproto/include/cbproto/types.h b/src/cbproto/include/cbproto/types.h index c9afdb90..9b39f34a 100644 --- a/src/cbproto/include/cbproto/types.h +++ b/src/cbproto/include/cbproto/types.h @@ -14,6 +14,8 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// +// TODO: Move version annotations to src/cbshm/include/cbshm/central_types/ + #ifndef CBPROTO_TYPES_H #define CBPROTO_TYPES_H @@ -38,6 +40,7 @@ constexpr uint32_t cbVERSION_MINOR = 2; /// @{ /// @brief Processor time type +/// VER: 4.0+ 64-bit processor time /// Protocol 4.0+ uses 64-bit timestamps /// Protocol 3.x uses 32-bit timestamps (compile with CBPROTO_311) #ifdef CBPROTO_311 @@ -237,7 +240,7 @@ constexpr uint32_t cbRESULT_SYSLOCK = 26; ///< Cannot (un)lock the system reso typedef struct { PROCTIME time; ///< System clock timestamp uint16_t chid; ///< Channel identifier - uint16_t type; ///< Packet type // VER: 4.1+, type is uint16_t instead of uint8_t + uint16_t type; ///< Packet type // VER: 4.1+, type changed to uint16_t from uint8_t uint16_t dlen; ///< Length of data field in 32-bit chunks uint8_t instrument; ///< Instrument number (0-based in packet, despite cbNSP1=1!) uint8_t reserved; ///< Reserved for future use @@ -431,7 +434,7 @@ constexpr uint32_t cbPKTTYPE_SYSHEARTBEAT = 0x00; ///< System heartbeat packe constexpr uint32_t cbPKTTYPE_SYSPROTOCOLMONITOR = 0x01; ///< Protocol monitoring packet constexpr uint32_t cbPKTTYPE_PREVREPSTREAM = 0x02; ///< Preview reply stream constexpr uint32_t cbPKTTYPE_PREVREP = 0x03; ///< Preview reply -constexpr uint32_t cbPKTTYPE_PREVREPLNC = 0x04; ///< Preview reply LNC +constexpr uint32_t cbPKTTYPE_PREVREPLNC = 0x04; ///< Preview reply LNC // VER: 4.2+, changed to 0x04 from 0x01 constexpr uint32_t cbPKTTYPE_REPCONFIGALL = 0x08; ///< Response that NSP got your request constexpr uint32_t cbPKTTYPE_SYSREP = 0x10; ///< System reply constexpr uint32_t cbPKTTYPE_SYSREPSPKLEN = 0x11; ///< System reply spike length @@ -506,7 +509,7 @@ constexpr uint32_t cbPKTTYPE_UPDATEREP = 0x71; ///< Update reply // Preview packets - Set constexpr uint32_t cbPKTTYPE_PREVSETSTREAM = 0x82; ///< Preview set stream constexpr uint32_t cbPKTTYPE_PREVSET = 0x83; ///< Preview set -constexpr uint32_t cbPKTTYPE_PREVSETLNC = 0x84; ///< Preview set LNC +constexpr uint32_t cbPKTTYPE_PREVSETLNC = 0x84; ///< Preview set LNC // VER: 4.2+, changed to 0x84 from 0x81 // System packets - Request (0x88-0x9F) constexpr uint32_t cbPKTTYPE_REQCONFIGALL = 0x88; ///< Request for ALL configuration information @@ -964,7 +967,7 @@ typedef struct { uint32_t sortcount; ///< number of channels supported for spike sorting (reserved for future) uint32_t unitcount; ///< number of supported units for spike sorting (reserved for future) uint32_t hoopcount; ///< number of supported units for spike sorting (reserved for future) - uint32_t reserved; ///< reserved for future use, set to 0 + uint32_t reserved; ///< reserved for future use, set to 0 // VER: 4.2+, renamed to reserved from sortmethod uint32_t version; ///< current version of libraries } cbPKT_PROCINFO; @@ -1063,7 +1066,7 @@ typedef struct { uint32_t eopchar; ///< digital input capablities (given by cbDINP_* flags) union { struct { // separate system channel to instrument specific channel number - // VER: 4.2+, monsource is split into moninst and monchan + // VER: 4.1+, monsource is split into moninst and monchan uint16_t moninst; ///< instrument of channel to monitor uint16_t monchan; ///< channel to monitor int32_t outvalue; ///< output value @@ -1216,7 +1219,7 @@ typedef struct cbPKT_HEADER cbpkt_header; ///< packet header int32_t lastchan; ///< Which channel was clicked last. - uint16_t abyUnitSelections[(cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - sizeof(int32_t))]; ///< one for each channel, channels are 0 based here, shows units selected + uint16_t abyUnitSelections[(cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - sizeof(int32_t))]; ///< one for each channel, channels are 0 based here, shows units selected // VER: 4.0+, changed from cbMAXCHANS } cbPKT_UNIT_SELECTION; constexpr uint32_t cbPKTDLEN_UNITSELECTION = ((sizeof(cbPKT_UNIT_SELECTION) / 4) - cbPKT_HEADER_32SIZE); @@ -1251,8 +1254,8 @@ typedef struct { uint8_t dinpopts; ///< digital input options (composed of cbDINP_* flags) uint8_t aoutopts; ///< analog output options uint8_t eopchar; ///< the end of packet character - uint8_t moninst; ///< instrument number of channel to monitor - uint8_t monchan; ///< channel to monitor + uint8_t moninst; ///< instrument number of channel to monitor // VER: 4.2+, renamed from monsource + uint8_t monchan; ///< channel to monitor // VER: 4.2+ ONLY uint8_t outvalue; ///< output value uint8_t ainpopts; ///< analog input options (composed of cbAINP_* flags) uint8_t lncrate; ///< line noise cancellation filter adaptation rate @@ -1441,7 +1444,7 @@ constexpr uint32_t cbLOG_MODE_UPLOAD_RES = 9; ///< NSP->PC: Upload result constexpr uint32_t cbLOG_MODE_ENDPLUGIN = 10; ///< PC->NSP: Signal the plugin to end constexpr uint32_t cbLOG_MODE_NSP_REBOOT = 11; ///< PC->NSP: Reboot the NSP -constexpr uint32_t cbMAX_LOG = 130; ///< Maximum log description +constexpr uint32_t cbMAX_LOG = 130; ///< Maximum log description // VER: 4.2+, changed to 130 from 128 /// @brief PKT Set:0xE3 Rep:0x63 - Log packet /// @@ -1943,8 +1946,11 @@ typedef struct { /// Waveform parameter information uint16_t mode; ///< Can be any of cbWAVEFORM_MODE_* uint32_t repeats; ///< Number of repeats (0 means forever) + // VER: 4.1+, uint16_t trig split into trig and trigInst + // --------- uint8_t trig; ///< Can be any of cbWAVEFORM_TRIGGER_* uint8_t trigInst; ///< Instrument the trigChan belongs + // --------- uint16_t trigChan; ///< Depends on trig: /// for cbWAVEFORM_TRIGGER_DINP* 1-based trigChan (1-16) is digin1, (17-32) is digin2, ... /// for cbWAVEFORM_TRIGGER_SPIKEUNIT 1-based trigChan (1-156) is channel number @@ -2179,7 +2185,7 @@ typedef struct { uint8_t block[512]; ///< block data } cbPKT_UPDATE_OLD; -constexpr uint32_t cbPKTDLEN_UPDATE_OLD = (sizeof(cbPKT_UPDATE_OLD)/4)-2; +constexpr uint32_t cbPKTDLEN_UPDATE_OLD = (sizeof(cbPKT_UPDATE_OLD)/4)-2; // VER: 4.2+ ONLY /// @} diff --git a/src/cbshm/include/cbshm/central_types/v3_11.h b/src/cbshm/include/cbshm/central_types/v3_11.h index 143f33eb..61f92988 100644 --- a/src/cbshm/include/cbshm/central_types/v3_11.h +++ b/src/cbshm/include/cbshm/central_types/v3_11.h @@ -36,10 +36,14 @@ constexpr uint32_t cbMAXPROCS = 1; ///< Central supports up to 1 NSPs constexpr uint32_t cbNUM_FE_CHANS = 256; ///< Central supports 256 FE channels constexpr uint32_t cbMAXGROUPS = 8; ///< Sample rate groups constexpr uint32_t cbMAXFILTS = 32; ///< Digital filters -constexpr uint32_t cbMAXVIDEOSOURCE = 1; -constexpr uint32_t cbMAXTRACKOBJ = 20; -constexpr uint32_t cbMAXHOOPS = 4; -constexpr uint32_t cbMAX_AOUT_TRIGGER = 5; +constexpr uint32_t cbMAXVIDEOSOURCE = 1; ///< Maximum number of video sources +constexpr uint32_t cbMAXTRACKOBJ = 20; ///< Maximum number of trackable objects +constexpr uint32_t cbMAXHOOPS = 4; ///< Maximum number of hoops for spike sorting +constexpr uint32_t cbMAXSITES = 4; ///< Maximum number of electrodes in an n-trode group +constexpr uint32_t cbMAXSITEPLOTS = ((cbMAXSITES - 1) * cbMAXSITES / 2); ///< Combination of 2 out of n +constexpr uint32_t cbMAXUNITS = 5; ///< Maximum number of sorted units per channel +constexpr uint32_t cbMAX_PNTS = 128; ///< Maximum spike waveform points +constexpr uint32_t cbMAX_AOUT_TRIGGER = 5; ///< Maximum number of per-channel (analog output, or digital output) triggers // Channel counts constexpr uint32_t cbNUM_ANAIN_CHANS = 16 * cbMAXPROCS; @@ -100,14 +104,556 @@ constexpr uint32_t cbRECBUFFLEN = cbNUM_FE_CHANS * 32768 * 4; /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Instrument status flags (bit field) +/// @name String Length Constants +/// @{ + +constexpr uint32_t cbLEN_STR_UNIT = 8; ///< Length of unit string +constexpr uint32_t cbLEN_STR_LABEL = 16; ///< Length of label string +constexpr uint32_t cbLEN_STR_FILT_LABEL = 16; ///< Length of filter label string +constexpr uint32_t cbLEN_STR_IDENT = 64; ///< Length of identity string +constexpr uint32_t cbLEN_STR_COMMENT = 256; ///< Length of comment string +constexpr uint32_t cbMAX_COMMENT = 128; ///< Maximum comment length (must be multiple of 4) + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Central config buffer subtypes +/// @{ + +typedef uint32_t PROCTIME; + +/// @brief Cerebus packet header data structure /// -/// Used to track which instruments are active in shared memory +/// Known as 'cbPKT_HEADER_OLD' in 4.0+ +typedef struct { + PROCTIME time; ///< System clock timestamp + uint16_t chid; ///< Channel identifier + uint8_t type; ///< Packet type + uint8_t dlen; ///< Length of data field in 32-bit chunks +} cbPKT_HEADER; + +constexpr uint32_t cbPKT_MAX_SIZE = 1024; ///< Maximum packet size in bytes +constexpr uint32_t cbPKT_HEADER_SIZE = sizeof(cbPKT_HEADER); ///< Packet header size in bytes + +/// @brief Option table for Central application /// -enum class InstrumentStatus : uint32_t { - INACTIVE = 0x00000000, ///< Instrument slot is not in use - ACTIVE = 0x00000001, ///< Instrument is active and has data -}; +/// Used for configuration options in Central +typedef struct { + float fRMSAutoThresholdDistance; ///< multiplier to use for autothresholding when using RMS to guess noise + uint32_t reserved[31]; ///< Reserved for future use +} cbOPTIONTABLE; + +/// @brief Color table for Central application +/// +/// Used for display configuration in Central +typedef struct { + uint32_t winrsvd[48]; ///< Reserved for Windows + uint32_t dispback; ///< Display background color + uint32_t dispgridmaj; ///< Display major grid color + uint32_t dispgridmin; ///< Display minor grid color + uint32_t disptext; ///< Display text color + uint32_t dispwave; ///< Display waveform color + uint32_t dispwavewarn; ///< Display waveform warning color + uint32_t dispwaveclip; ///< Display waveform clipping color + uint32_t dispthresh; ///< Display threshold color + uint32_t dispmultunit; ///< Display multi-unit color + uint32_t dispunit[16]; ///< Display unit colors (0 = unclassified) + uint32_t dispnoise; ///< Display noise color + uint32_t dispchansel[3]; ///< Display channel selection colors + uint32_t disptemp[5]; ///< Display temporary colors + uint32_t disprsvd[14]; ///< Reserved display colors +} cbCOLORTABLE; + +/// @brief PKT Set:0x92 Rep:0x12 - System info +/// +/// Contains system information including the runlevel +typedef struct { + cbPKT_HEADER cbpkt_header; ///< Packet header + + uint32_t sysfreq; ///< System sampling clock frequency in Hz + uint32_t spikelen; ///< The length of the spike events + uint32_t spikepre; ///< Spike pre-trigger samples + uint32_t resetque; ///< The channel for the reset to que on + uint32_t runlevel; ///< System runlevel + uint32_t runflags; ///< Lock recording after reset +} cbPKT_SYSINFO; + +/// @brief PKT Set:N/A Rep:0x21 - Info about the processor +/// +/// Includes information about the counts of various features of the processor +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< index of the bank + uint32_t idcode; ///< manufacturer part and rom ID code of the Signal Processor + char ident[cbLEN_STR_IDENT]; ///< ID string with the equipment name of the Signal Processor + uint32_t chanbase; ///< lowest channel number of channel id range claimed by this processor + uint32_t chancount; ///< number of channel identifiers claimed by this processor + uint32_t bankcount; ///< number of signal banks supported by the processor + uint32_t groupcount; ///< number of sample groups supported by the processor + uint32_t filtcount; ///< number of digital filters supported by the processor + uint32_t sortcount; ///< number of channels supported for spike sorting (reserved for future) + uint32_t unitcount; ///< number of supported units for spike sorting (reserved for future) + uint32_t hoopcount; ///< number of supported units for spike sorting (reserved for future) + uint32_t sortmethod; ///< sort method (0=manual, 1=automatic spike sorting) + uint32_t version; ///< current version of libraries +} cbPKT_PROCINFO; + +/// @brief PKT Set:N/A Rep:0x22 - Information about the banks in the processor +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< the address of the processor on which the bank resides + uint32_t bank; ///< the address of the bank reported by the packet + uint32_t idcode; ///< manufacturer part and rom ID code of the module addressed to this bank + char ident[cbLEN_STR_IDENT]; ///< ID string with the equipment name of the Signal Bank hardware module + char label[cbLEN_STR_LABEL]; ///< Label on the instrument for the signal bank, eg "Analog In" + uint32_t chanbase; ///< lowest channel number of channel id range claimed by this bank + uint32_t chancount; ///< number of channel identifiers claimed by this bank +} cbPKT_BANKINFO; + +/// @brief PKT Set:0xB0 Rep:0x30 - Sample Group (GROUP) Information Packets +/// +/// Contains information including the name and list of channels for each sample group. The cbPKT_GROUP packet transmits +/// the data for each group based on the list contained here. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< processor number + uint32_t group; ///< group number + char label[cbLEN_STR_LABEL]; ///< sampling group label + uint32_t period; ///< sampling period for the group + uint32_t length; ///< number of channels in the list + uint16_t list[cbNUM_ANALOG_CHANS]; ///< variable length list. The max size is the total number of analog channels +} cbPKT_GROUPINFO; + +/// @brief PKT Set:0xA3 Rep:0x23 - Filter Information Packet +/// +/// Describes the filters contained in the NSP including the filter coefficients +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< + uint32_t filt; ///< + char label[cbLEN_STR_FILT_LABEL]; // name of the filter + uint32_t hpfreq; ///< high-pass corner frequency in milliHertz + uint32_t hporder; ///< high-pass filter order + uint32_t hptype; ///< high-pass filter type + uint32_t lpfreq; ///< low-pass frequency in milliHertz + uint32_t lporder; ///< low-pass filter order + uint32_t lptype; ///< low-pass filter type + ///< These are for sending the NSP filter info, otherwise the NSP has this stuff in NSPDefaults.c + double gain; ///< filter gain + double sos1a1; ///< filter coefficient + double sos1a2; ///< filter coefficient + double sos1b1; ///< filter coefficient + double sos1b2; ///< filter coefficient + double sos2a1; ///< filter coefficient + double sos2a2; ///< filter coefficient + double sos2b1; ///< filter coefficient + double sos2b2; ///< filter coefficient +} cbPKT_FILTINFO; + +/// @brief PKT Set:0xA5 Rep:0x25 - Adaptive filtering +/// +/// This sets the parameters for the adaptive filtering. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< Ignored + + uint32_t nMode; ///< 0=disabled, 1=filter continuous & spikes, 2=filter spikes + float dLearningRate; ///< speed at which adaptation happens. Very small. e.g. 5e-12 + uint32_t nRefChan1; ///< The first reference channel (1 based). + uint32_t nRefChan2; ///< The second reference channel (1 based). + +} cbPKT_ADAPTFILTINFO; + +/// @brief PKT Set:0xA6 Rep:0x26 - Reference Electrode Information. +/// +/// This configures a channel to be referenced by another channel. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< Ignored + + uint32_t nMode; ///< 0=disabled, 1=filter continuous & spikes, 2=filter spikes + uint32_t nRefChan; ///< The reference channel (1 based). +} cbPKT_REFELECFILTINFO; + +/// @brief Filter description structure +/// +/// Filter description used in cbPKT_CHANINFO +typedef struct { + char label[cbLEN_STR_FILT_LABEL]; + uint32_t hpfreq; ///< high-pass corner frequency in milliHertz + uint32_t hporder; ///< high-pass filter order + uint32_t hptype; ///< high-pass filter type + uint32_t lpfreq; ///< low-pass frequency in milliHertz + uint32_t lporder; ///< low-pass filter order + uint32_t lptype; ///< low-pass filter type +} cbFILTDESC; + +/// @brief Scaling structure +/// +/// Structure used in cbPKT_CHANINFO +typedef struct { + int16_t digmin; ///< digital value that cooresponds with the anamin value + int16_t digmax; ///< digital value that cooresponds with the anamax value + int32_t anamin; ///< the minimum analog value present in the signal + int32_t anamax; ///< the maximum analog value present in the signal + int32_t anagain; ///< the gain applied to the default analog values to get the analog values + char anaunit[cbLEN_STR_UNIT]; ///< the unit for the analog signal (eg, "uV" or "MPa") +} cbSCALING; + +/// @brief Manual Unit Mapping structure +/// +/// Defines an ellipsoid for sorting. Used in cbPKT_CHANINFO and cbPKT_NTRODEINFO +typedef struct { + int16_t nOverride; ///< override to unit if in ellipsoid + int16_t afOrigin[3]; ///< ellipsoid origin + int16_t afShape[3][3]; ///< ellipsoid shape + int16_t aPhi; ///< + uint32_t bValid; ///< is this unit in use at this time? + ///< BOOL implemented as uint32_t - for structure alignment at paragraph boundary +} cbMANUALUNITMAPPING; + +/// @brief Hoop definition structure +/// +/// Defines the hoop used for sorting. There can be up to 5 hoops per unit. Used in cbPKT_CHANINFO +typedef struct { + uint16_t valid; ///< 0=undefined, 1 for valid + int16_t time; ///< time offset into spike window + int16_t min; ///< minimum value for the hoop window + int16_t max; ///< maximum value for the hoop window +} cbHOOP; + +/// @brief PKT Set:0xCx Rep:0x4x - Channel Information +/// +/// This contains the details for each channel within the system. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< actual channel id of the channel being configured + uint32_t proc; ///< the address of the processor on which the channel resides + uint32_t bank; ///< the address of the bank on which the channel resides + uint32_t term; ///< the terminal number of the channel within it's bank + uint32_t chancaps; ///< general channel capablities (given by cbCHAN_* flags) + uint32_t doutcaps; ///< digital output capablities (composed of cbDOUT_* flags) + uint32_t dinpcaps; ///< digital input capablities (composed of cbDINP_* flags) + uint32_t aoutcaps; ///< analog output capablities (composed of cbAOUT_* flags) + uint32_t ainpcaps; ///< analog input capablities (composed of cbAINP_* flags) + uint32_t spkcaps; ///< spike processing capabilities + cbSCALING physcalin; ///< physical channel scaling information + cbFILTDESC phyfiltin; ///< physical channel filter definition + cbSCALING physcalout; ///< physical channel scaling information + cbFILTDESC phyfiltout; ///< physical channel filter definition + char label[cbLEN_STR_LABEL]; ///< Label of the channel (null terminated if <16 characters) + uint32_t userflags; ///< User flags for the channel state + int32_t position[4]; ///< reserved for future position information + cbSCALING scalin; ///< user-defined scaling information for AINP + cbSCALING scalout; ///< user-defined scaling information for AOUT + uint32_t doutopts; ///< digital output options (composed of cbDOUT_* flags) + uint32_t dinpopts; ///< digital input options (composed of cbDINP_* flags) + uint32_t aoutopts; ///< analog output options + uint32_t eopchar; ///< digital input capablities (given by cbDINP_* flags) + union { + struct { // separate system channel to instrument specific channel number + uint32_t monsource; ///< address of channel to monitor + int32_t outvalue; ///< output value + }; + struct { // used for digout timed output + uint16_t lowsamples; ///< number of samples to set low for timed output + uint16_t highsamples; ///< number of samples to set high for timed output + int32_t offset; ///< number of samples to offset the transitions for timed output + }; + }; + uint8_t trigtype; ///< trigger type (see cbDOUT_TRIGGER_*) + uint16_t trigchan; ///< trigger channel + uint16_t trigval; ///< trigger value + uint32_t ainpopts; ///< analog input options (composed of cbAINP* flags) + uint32_t lncrate; ///< line noise cancellation filter adaptation rate + uint32_t smpfilter; ///< continuous-time pathway filter id + uint32_t smpgroup; ///< continuous-time pathway sample group + int32_t smpdispmin; ///< continuous-time pathway display factor + int32_t smpdispmax; ///< continuous-time pathway display factor + uint32_t spkfilter; ///< spike pathway filter id + int32_t spkdispmax; ///< spike pathway display factor + int32_t lncdispmax; ///< Line Noise pathway display factor + uint32_t spkopts; ///< spike processing options + int32_t spkthrlevel; ///< spike threshold level + int32_t spkthrlimit; ///< + uint32_t spkgroup; ///< NTrodeGroup this electrode belongs to - 0 is single unit, non-0 indicates a multi-trode grouping + int16_t amplrejpos; ///< Amplitude rejection positive value + int16_t amplrejneg; ///< Amplitude rejection negative value + uint32_t refelecchan; ///< Software reference electrode channel + cbMANUALUNITMAPPING unitmapping[cbMAXUNITS]; ///< manual unit mapping + cbHOOP spkhoops[cbMAXUNITS][cbMAXHOOPS]; ///< spike hoop sorting set +} cbPKT_CHANINFO; + +/// @brief PKT Set:0xDB Rep:0x5B - Feature Space Basis +/// +/// This packet holds the calculated basis of the feature space from NSP to Central +/// Or it has the previous basis retrieved and transmitted by central to NSP +typedef struct +{ + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< 1-based channel number + uint32_t mode; ///< cbBASIS_CHANGE, cbUNDO_BASIS_CHANGE, cbREDO_BASIS_CHANGE, cbINVALIDATE_BASIS ... + uint32_t fs; ///< Feature space: cbAUTOALG_PCA + /// basis must be the last item in the structure because it can be variable length to a max of cbMAX_PNTS + float basis[cbMAX_PNTS][3]; ///< Room for all possible points collected +} cbPKT_FS_BASIS; + +/// @brief PKT Set:0xD1 Rep:0x51 - Get the spike sorting model for a single channel (Histogram Peak Count) +/// +/// The system replys with the model of a specific channel. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< actual channel id of the channel being configured (0 based) + uint32_t unit_number; ///< unit label (0 based, 0 is noise cluster) + uint32_t valid; ///< 1 = valid unit, 0 = not a unit, in other words just deleted when NSP -> PC + uint32_t inverted; ///< 0 = not inverted, 1 = inverted + + // Block statistics (change from block to block) + int32_t num_samples; ///< non-zero value means that the block stats are valid + float mu_x[2]; + float Sigma_x[2][2]; + float determinant_Sigma_x; + ///// Only needed if we are using a Bayesian classification model + float Sigma_x_inv[2][2]; + float log_determinant_Sigma_x; + ///// + float subcluster_spread_factor_numerator; + float subcluster_spread_factor_denominator; + float mu_e; + float sigma_e_squared; +} cbPKT_SS_MODELSET; + +/// @brief PKT Set:0xD2 Rep:0x52 - Auto threshold parameters +/// +/// Set the auto threshold parameters +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + float fThreshold; ///< current detection threshold + float fMultiplier; ///< multiplier +} cbPKT_SS_DETECT; + +/// @brief PKT Set:0xD3 Rep:0x53 - Artifact reject +/// +/// Sets the artifact rejection parameters. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t nMaxSimulChans; ///< how many channels can fire exactly at the same time??? + uint32_t nRefractoryCount; ///< for how many samples (30 kHz) is a neuron refractory, so can't re-trigger +} cbPKT_SS_ARTIF_REJECT; + +/// @brief PKT Set:0xD4 Rep:0x54 - Noise boundary +/// +/// Sets the noise boundary parameters +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< which channel we belong to + float afc[3]; ///< the center of the ellipsoid + float afS[3][3]; ///< an array of the axes for the ellipsoid +} cbPKT_SS_NOISE_BOUNDARY; + +/// @brief PKT Set:0xD5 Rep:0x55 - Spike sourting statistics (Histogram peak count) +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t nUpdateSpikes; ///< update rate in spike counts + + uint32_t nAutoalg; ///< sorting algorithm (0=none 1=spread, 2=hist_corr_maj, 3=hist_peak_count_maj, 4=hist_peak_count_maj_fisher, 5=pca, 6=hoops) + uint32_t nMode; ///< cbAUTOALG_MODE_SETTING, + + float fMinClusterPairSpreadFactor; ///< larger number = more apt to combine 2 clusters into 1 + float fMaxSubclusterSpreadFactor; ///< larger number = less apt to split because of 2 clusers + + float fMinClusterHistCorrMajMeasure; ///< larger number = more apt to split 1 cluster into 2 + float fMaxClusterPairHistCorrMajMeasure; ///< larger number = less apt to combine 2 clusters into 1 + + float fClusterHistValleyPercentage; ///< larger number = less apt to split nearby clusters + float fClusterHistClosePeakPercentage; ///< larger number = less apt to split nearby clusters + float fClusterHistMinPeakPercentage; ///< larger number = less apt to split separated clusters + + uint32_t nWaveBasisSize; ///< number of wave to collect to calculate the basis, + ///< must be greater than spike length + uint32_t nWaveSampleSize; ///< number of samples sorted with the same basis before re-calculating the basis + ///< 0=manual re-calculation + ///< nWaveBasisSize * nWaveSampleSize is the number of waves/spikes to run against + ///< the same PCA basis before next +} cbPKT_SS_STATISTICS; + +/// @brief Adaptive Control structure +typedef struct { + uint32_t nMode; ///< 0-do not adapt at all, 1-always adapt, 2-adapt if timer not timed out + float fTimeOutMinutes; ///< how many minutes until time out + float fElapsedMinutes; ///< the amount of time that has elapsed +} cbAdaptControl; + +/// @brief PKT Set:0xD7 Rep:0x57 - Spike sorting status (Histogram peak count) +/// +/// This packet contains the status of the automatic spike sorting. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + cbAdaptControl cntlUnitStats; ///< + cbAdaptControl cntlNumUnits; ///< +} cbPKT_SS_STATUS; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Spike sorting configuration +/// +/// Groups all spike-sorting related configuration packets together. +typedef struct { + cbPKT_FS_BASIS asBasis[cbMAXCHANS]; ///< PCA basis values per channel + cbPKT_SS_MODELSET asSortModel[cbMAXCHANS][cbMAXUNITS + 2]; ///< Sorting models/rules per channel + + //////// These are spike sorting options + cbPKT_SS_DETECT pktDetect; ///< Detection parameters + cbPKT_SS_ARTIF_REJECT pktArtifReject; ///< Artifact rejection parameters + cbPKT_SS_NOISE_BOUNDARY pktNoiseBoundary[cbNUM_ANALOG_CHANS]; ///< Noise boundaries per channel + cbPKT_SS_STATISTICS pktStatistics; ///< Spike statistics + cbPKT_SS_STATUS pktStatus; ///< Spike sorting status +} cbSPIKE_SORTING; + +/// @brief PKT Set:0xA7 Rep:0x27 - N-Trode information packets +/// +/// Sets information about an N-Trode. The user can change the name, number of sites, sites (channels) +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t ntrode; ///< ntrode with which we are working (1-based) + char label[cbLEN_STR_LABEL]; ///< Label of the Ntrode (null terminated if < 16 characters) + cbMANUALUNITMAPPING ellipses[cbMAXSITEPLOTS][cbMAXUNITS]; ///< unit mapping + uint16_t nSite; ///< number channels in this NTrode ( 0 <= nSite <= cbMAXSITES) + uint16_t fs; ///< NTrode feature space cbNTRODEINFO_FS_* + uint16_t nChan[cbMAXSITES]; ///< group of channels in this NTrode +} cbPKT_NTRODEINFO; + +constexpr uint32_t cbMAX_WAVEFORM_PHASES = ((cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - 24) / 4); ///< Maximum number of phases in a waveform + +/// @brief Analog output waveform data +/// +/// Contains the parameters to define a waveform for Analog Output channels +typedef struct +{ + int16_t offset; ///< DC offset + union { + struct { + uint16_t sineFrequency; ///< sine wave Hz + int16_t sineAmplitude; ///< sine amplitude + }; + struct { + uint16_t seq; ///< Wave sequence number (for file playback) + uint16_t seqTotal; ///< total number of sequences + uint16_t phases; ///< Number of valid phases in this wave (maximum is cbMAX_WAVEFORM_PHASES) + uint16_t duration[cbMAX_WAVEFORM_PHASES]; ///< array of durations for each phase + int16_t amplitude[cbMAX_WAVEFORM_PHASES]; ///< array of amplitude for each phase + }; + }; +} cbWaveformData; + +/// @brief PKT Set:0xB3 Rep:0x33 - AOUT waveform +/// +/// This sets a user defined waveform for one or multiple Analog & Audio Output channels. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint16_t chan; ///< which analog output/audio output channel (1-based, will equal chan from GetDoutCaps) + + /// Each file may contain multiple sequences. + /// Each sequence consists of phases + /// Each phase is defined by amplitude and duration + + /// Waveform parameter information + uint16_t mode; ///< Can be any of cbWAVEFORM_MODE_* + uint32_t repeats; ///< Number of repeats (0 means forever) + uint16_t trig; ///< Can be any of cbWAVEFORM_TRIGGER* + uint16_t trigChan; ///< Depends on trig: + /// for cbWAVEFORM_TRIGGER_DINP* 1-based trigChan (1-16) is digin1, (17-32) is digin2, ... + /// for cbWAVEFORM_TRIGGER_SPIKEUNIT 1-based trigChan (1-156) is channel number + /// for cbWAVEFORM_TRIGGER_COMMENTCOLOR trigChan is A->B in A->B->G->R + uint16_t trigValue; ///< Trigger value (spike unit, G-R comment color, ...) + uint8_t trigNum; ///< trigger number (0-based) (can be up to cbMAX_AOUT_TRIGGER-1) + uint8_t active; ///< status of trigger + cbWaveformData wave; ///< Actual waveform data +} cbPKT_AOUT_WAVEFORM; + +/// @brief PKT Set:0xA8 Rep:0x28 - Line Noise Cancellation +/// +/// This packet holds the Line Noise Cancellation parameters +typedef struct +{ + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t lncFreq; ///< Nominal line noise frequency to be canceled (in Hz) + uint32_t lncRefChan; ///< Reference channel for lnc synch (1-based) + uint32_t lncGlobalMode; ///< reserved +} cbPKT_LNC; + +constexpr uint32_t cbNPLAY_FNAME_LEN = (cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - 40); ///< length of the file name (with terminating null) + +/// @brief PKT Set:0xDC Rep:0x5C - nPlay configuration packet +/// +/// Sent on restart together with config packet +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + union { + PROCTIME ftime; ///< the total time of the file. + PROCTIME opt; ///< optional value + }; + PROCTIME stime; ///< start time + PROCTIME etime; ///< stime < end time < ftime + PROCTIME val; ///< Used for current time to traverse, file index, file version, ... + uint16_t mode; ///< cbNPLAY_MODE_* command to nPlay + uint16_t flags; ///< cbNPLAY_FLAG_* status of nPlay + float speed; ///< positive means fast forward, negative means rewind, 0 means go as fast as you can. + char fname[cbNPLAY_FNAME_LEN]; ///< This is a String with the file name. +} cbPKT_NPLAY; + +/// @brief NeuroMotive video source +typedef struct { + char name[cbLEN_STR_LABEL]; ///< filename of the video file + float fps; ///< nominal record fps +} cbVIDEOSOURCE; + +/// @brief Track object structure for NeuroMotive +typedef struct { + char name[cbLEN_STR_LABEL]; ///< name of the object + uint16_t type; ///< trackable type (cbTRACKOBJ_TYPE_*) + uint16_t pointCount; ///< maximum number of points +} cbTRACKOBJ; + +/// @brief PKT Set:0xE1 Rep:0x61 - File configuration packet +/// +/// File recording can be started or stopped externally using this packet. It also contains a timeout mechanism to notify +/// if file isn't still recording. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t options; ///< cbFILECFG_OPT_* + uint32_t duration; + uint32_t recording; ///< If cbFILECFG_OPT_NONE this option starts/stops recording remotely + uint32_t extctrl; ///< If cbFILECFG_OPT_REC this is split number (0 for non-TOC) + ///< If cbFILECFG_OPT_STOP this is error code (0 means no error) + + char username[cbLEN_STR_COMMENT]; ///< name of computer issuing the packet + union { + char filename[cbLEN_STR_COMMENT]; ///< filename to record to + char datetime[cbLEN_STR_COMMENT]; ///< + }; + char comment[cbLEN_STR_COMMENT]; ///< comment to include in the file +} cbPKT_FILECFG; + +/// @} /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Central's actual binary layout (CentralLegacyCFGBUFF) @@ -156,6 +702,8 @@ struct CentralLegacyCFGBUFF { /// This is stored in a separate shared memory segment (not embedded in config buffer) /// to match Central's architecture. /// +/// TODO: Rename to cbXMTBUFF (?) +/// struct CentralTransmitBuffer { uint32_t transmitted; ///< How many packets have been sent uint32_t headindex; ///< First empty position (write index) @@ -171,6 +719,8 @@ struct CentralTransmitBuffer { /// Smaller than Global buffer, used for cbSendLoopbackPacket() - packets meant only for /// local processes, not sent to device. /// +/// TODO: Rename to cbXMTBUFF (?) +/// struct CentralTransmitBufferLocal { uint32_t transmitted; ///< How many packets have been sent uint32_t headindex; ///< First empty position (write index) @@ -180,12 +730,32 @@ struct CentralTransmitBufferLocal { uint32_t buffer[cbXMT_LOCAL_BUFFLEN]; ///< Ring buffer for packet data }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Data packet - Spike waveform data +/// +/// Detected spikes are sent through this packet. The spike waveform may or may not be sent depending +/// on the dlen contained in the header. The waveform can be anywhere from 30 samples to 128 samples +/// based on user configuration. The default spike length is 48 samples. cbpkt_header.chid is the +/// channel number of the spike. cbpkt_header.type is the sorted unit number (0=unsorted, 255=noise). +typedef struct { + cbPKT_HEADER cbpkt_header; ///< in the header for this packet, the type is used as the unit number + + float fPattern[3]; ///< values of the pattern space (Normal uses only 2, PCA uses third) + int16_t nPeak; ///< highest datapoint of the waveform + int16_t nValley; ///< lowest datapoint of the waveform + + int16_t wave[cbMAX_PNTS]; ///< datapoints of each sample of the waveform. Room for all possible points collected + ///< wave must be the last item in the structure because it can be variable length to a max of cbMAX_PNTS +} cbPKT_SPK; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Spike cache buffer /// /// Caches recent spike packets for each channel to allow quick access without /// scanning the entire receive buffer. /// +/// TODO: rename to cbSPKCACHE (?) +/// struct CentralSpikeCache { uint32_t chid; ///< Channel ID uint32_t pktcnt; ///< Number of packets that can be saved @@ -195,6 +765,9 @@ struct CentralSpikeCache { cbPKT_SPK spkpkt[cbPKT_SPKCACHEPKTCNT]; ///< Circular buffer of cached spikes }; +/// +/// TODO: rename to cbSPKBUFF (?) +/// struct CentralSpikeBuffer { uint32_t flags; ///< Status flags uint32_t chidmax; ///< Maximum channel ID @@ -203,6 +776,16 @@ struct CentralSpikeBuffer { CentralSpikeCache cache[cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Instrument status flags (bit field) +/// +/// Used to track which instruments are active in shared memory +/// +enum class InstrumentStatus : uint32_t { + INACTIVE = 0x00000000, ///< Instrument slot is not in use + ACTIVE = 0x00000001, ///< Instrument is active and has data +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief PC Status buffer (flattened from cbPcStatus class) /// @@ -217,6 +800,18 @@ enum class NSPStatus : uint32_t { NSP_INVALID = 4 }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Unit Selection +/// +/// Packet which says that these channels are now selected +typedef struct +{ + cbPKT_HEADER cbpkt_header; ///< packet header + + int32_t lastchan; ///< Which channel was clicked last. + uint16_t abyUnitSelections[cbMAXCHANS]; ///< one for each channel, channels are 0 based here, shows units selected +} cbPKT_UNIT_SELECTION; + struct CentralPCStatus { // Public data cbPKT_UNIT_SELECTION isSelection[cbMAXPROCS]; ///< Unit selection per instrument @@ -234,9 +829,7 @@ struct CentralPCStatus { uint32_t m_nNumSerialChans; ///< Number of serial channels uint32_t m_nNumDigoutChans; ///< Number of digital output channels uint32_t m_nNumTotalChans; ///< Total channel count - NSPStatus m_nNspStatus[cbMAXPROCS]; ///< NSP status per instrument - uint32_t m_nNumNTrodesPerInstrument[cbMAXPROCS];///< NTrode count per instrument - uint32_t m_nGeminiSystem; ///< Gemini system flag + // VER: Everything below here added at 4.0+ }; /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/cbshm/include/cbshm/central_types/v4_0.h b/src/cbshm/include/cbshm/central_types/v4_0.h index 73cf940c..0953cfbe 100644 --- a/src/cbshm/include/cbshm/central_types/v4_0.h +++ b/src/cbshm/include/cbshm/central_types/v4_0.h @@ -36,10 +36,14 @@ constexpr uint32_t cbMAXPROCS = 2; ///< Central supports up to 2 NSPs constexpr uint32_t cbNUM_FE_CHANS = 512; ///< Central supports 512 FE channels constexpr uint32_t cbMAXGROUPS = 8; ///< Sample rate groups constexpr uint32_t cbMAXFILTS = 32; ///< Digital filters -constexpr uint32_t cbMAXVIDEOSOURCE = 1; -constexpr uint32_t cbMAXTRACKOBJ = 20; -constexpr uint32_t cbMAXHOOPS = 4; -constexpr uint32_t cbMAX_AOUT_TRIGGER = 5; +constexpr uint32_t cbMAXVIDEOSOURCE = 1; ///< Maximum number of video sources +constexpr uint32_t cbMAXTRACKOBJ = 20; ///< Maximum number of trackable objects +constexpr uint32_t cbMAXHOOPS = 4; ///< Maximum number of hoops for spike sorting +constexpr uint32_t cbMAXSITES = 4; ///< Maximum number of electrodes in an n-trode group +constexpr uint32_t cbMAXSITEPLOTS = ((cbMAXSITES - 1) * cbMAXSITES / 2); ///< Combination of 2 out of n +constexpr uint32_t cbMAXUNITS = 5; ///< Maximum number of sorted units per channel +constexpr uint32_t cbMAX_PNTS = 128; ///< Maximum spike waveform points +constexpr uint32_t cbMAX_AOUT_TRIGGER = 5; ///< Maximum number of per-channel (analog output, or digital output) triggers // Channel counts constexpr uint32_t cbNUM_ANAIN_CHANS = 16 * cbMAXPROCS; @@ -100,14 +104,556 @@ constexpr uint32_t cbRECBUFFLEN = cbNUM_FE_CHANS * 32768 * 4; /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Instrument status flags (bit field) +/// @name String Length Constants +/// @{ + +constexpr uint32_t cbLEN_STR_UNIT = 8; ///< Length of unit string +constexpr uint32_t cbLEN_STR_LABEL = 16; ///< Length of label string +constexpr uint32_t cbLEN_STR_FILT_LABEL = 16; ///< Length of filter label string +constexpr uint32_t cbLEN_STR_IDENT = 64; ///< Length of identity string +constexpr uint32_t cbLEN_STR_COMMENT = 256; ///< Length of comment string +constexpr uint32_t cbMAX_COMMENT = 128; ///< Maximum comment length (must be multiple of 4) + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Central config buffer subtypes +/// @{ + +typedef uint64_t PROCTIME; + +/// @brief Cerebus packet header data structure +typedef struct { + PROCTIME time; ///< System clock timestamp + uint16_t chid; ///< Channel identifier + uint8_t type; ///< Packet type + uint16_t dlen; ///< Length of data field in 32-bit chunks + uint8_t instrument; ///< Instrument number (0-based in packet, despite cbNSP1=1!) + uint8_t reserved; ///< Reserved for future use +} cbPKT_HEADER; + +constexpr uint32_t cbPKT_MAX_SIZE = 1024; ///< Maximum packet size in bytes +constexpr uint32_t cbPKT_HEADER_SIZE = sizeof(cbPKT_HEADER); ///< Packet header size in bytes + +/// @brief Option table for Central application /// -/// Used to track which instruments are active in shared memory +/// Used for configuration options in Central +typedef struct { + float fRMSAutoThresholdDistance; ///< multiplier to use for autothresholding when using RMS to guess noise + uint32_t reserved[31]; ///< Reserved for future use +} cbOPTIONTABLE; + +/// @brief Color table for Central application /// -enum class InstrumentStatus : uint32_t { - INACTIVE = 0x00000000, ///< Instrument slot is not in use - ACTIVE = 0x00000001, ///< Instrument is active and has data -}; +/// Used for display configuration in Central +typedef struct { + uint32_t winrsvd[48]; ///< Reserved for Windows + uint32_t dispback; ///< Display background color + uint32_t dispgridmaj; ///< Display major grid color + uint32_t dispgridmin; ///< Display minor grid color + uint32_t disptext; ///< Display text color + uint32_t dispwave; ///< Display waveform color + uint32_t dispwavewarn; ///< Display waveform warning color + uint32_t dispwaveclip; ///< Display waveform clipping color + uint32_t dispthresh; ///< Display threshold color + uint32_t dispmultunit; ///< Display multi-unit color + uint32_t dispunit[16]; ///< Display unit colors (0 = unclassified) + uint32_t dispnoise; ///< Display noise color + uint32_t dispchansel[3]; ///< Display channel selection colors + uint32_t disptemp[5]; ///< Display temporary colors + uint32_t disprsvd[14]; ///< Reserved display colors +} cbCOLORTABLE; + +/// @brief PKT Set:0x92 Rep:0x12 - System info +/// +/// Contains system information including the runlevel +typedef struct { + cbPKT_HEADER cbpkt_header; ///< Packet header + + uint32_t sysfreq; ///< System sampling clock frequency in Hz + uint32_t spikelen; ///< The length of the spike events + uint32_t spikepre; ///< Spike pre-trigger samples + uint32_t resetque; ///< The channel for the reset to que on + uint32_t runlevel; ///< System runlevel + uint32_t runflags; ///< Lock recording after reset +} cbPKT_SYSINFO; + +/// @brief PKT Set:N/A Rep:0x21 - Info about the processor +/// +/// Includes information about the counts of various features of the processor +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< index of the bank + uint32_t idcode; ///< manufacturer part and rom ID code of the Signal Processor + char ident[cbLEN_STR_IDENT]; ///< ID string with the equipment name of the Signal Processor + uint32_t chanbase; ///< lowest channel number of channel id range claimed by this processor + uint32_t chancount; ///< number of channel identifiers claimed by this processor + uint32_t bankcount; ///< number of signal banks supported by the processor + uint32_t groupcount; ///< number of sample groups supported by the processor + uint32_t filtcount; ///< number of digital filters supported by the processor + uint32_t sortcount; ///< number of channels supported for spike sorting (reserved for future) + uint32_t unitcount; ///< number of supported units for spike sorting (reserved for future) + uint32_t hoopcount; ///< number of supported units for spike sorting (reserved for future) + uint32_t reserved; ///< reserved for future use, set to 0 + uint32_t version; ///< current version of libraries +} cbPKT_PROCINFO; + +/// @brief PKT Set:N/A Rep:0x22 - Information about the banks in the processor +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< the address of the processor on which the bank resides + uint32_t bank; ///< the address of the bank reported by the packet + uint32_t idcode; ///< manufacturer part and rom ID code of the module addressed to this bank + char ident[cbLEN_STR_IDENT]; ///< ID string with the equipment name of the Signal Bank hardware module + char label[cbLEN_STR_LABEL]; ///< Label on the instrument for the signal bank, eg "Analog In" + uint32_t chanbase; ///< lowest channel number of channel id range claimed by this bank + uint32_t chancount; ///< number of channel identifiers claimed by this bank +} cbPKT_BANKINFO; + +/// @brief PKT Set:0xB0 Rep:0x30 - Sample Group (GROUP) Information Packets +/// +/// Contains information including the name and list of channels for each sample group. The cbPKT_GROUP packet transmits +/// the data for each group based on the list contained here. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< processor number + uint32_t group; ///< group number + char label[cbLEN_STR_LABEL]; ///< sampling group label + uint32_t period; ///< sampling period for the group + uint32_t length; ///< number of channels in the list + uint16_t list[cbNUM_ANALOG_CHANS]; ///< variable length list. The max size is the total number of analog channels +} cbPKT_GROUPINFO; + +/// @brief PKT Set:0xA3 Rep:0x23 - Filter Information Packet +/// +/// Describes the filters contained in the NSP including the filter coefficients +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< + uint32_t filt; ///< + char label[cbLEN_STR_FILT_LABEL]; // name of the filter + uint32_t hpfreq; ///< high-pass corner frequency in milliHertz + uint32_t hporder; ///< high-pass filter order + uint32_t hptype; ///< high-pass filter type + uint32_t lpfreq; ///< low-pass frequency in milliHertz + uint32_t lporder; ///< low-pass filter order + uint32_t lptype; ///< low-pass filter type + ///< These are for sending the NSP filter info, otherwise the NSP has this stuff in NSPDefaults.c + double gain; ///< filter gain + double sos1a1; ///< filter coefficient + double sos1a2; ///< filter coefficient + double sos1b1; ///< filter coefficient + double sos1b2; ///< filter coefficient + double sos2a1; ///< filter coefficient + double sos2a2; ///< filter coefficient + double sos2b1; ///< filter coefficient + double sos2b2; ///< filter coefficient +} cbPKT_FILTINFO; + +/// @brief PKT Set:0xA5 Rep:0x25 - Adaptive filtering +/// +/// This sets the parameters for the adaptive filtering. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< Ignored + + uint32_t nMode; ///< 0=disabled, 1=filter continuous & spikes, 2=filter spikes + float dLearningRate; ///< speed at which adaptation happens. Very small. e.g. 5e-12 + uint32_t nRefChan1; ///< The first reference channel (1 based). + uint32_t nRefChan2; ///< The second reference channel (1 based). + +} cbPKT_ADAPTFILTINFO; + +/// @brief PKT Set:0xA6 Rep:0x26 - Reference Electrode Information. +/// +/// This configures a channel to be referenced by another channel. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< Ignored + + uint32_t nMode; ///< 0=disabled, 1=filter continuous & spikes, 2=filter spikes + uint32_t nRefChan; ///< The reference channel (1 based). +} cbPKT_REFELECFILTINFO; + +/// @brief Filter description structure +/// +/// Filter description used in cbPKT_CHANINFO +typedef struct { + char label[cbLEN_STR_FILT_LABEL]; + uint32_t hpfreq; ///< high-pass corner frequency in milliHertz + uint32_t hporder; ///< high-pass filter order + uint32_t hptype; ///< high-pass filter type + uint32_t lpfreq; ///< low-pass frequency in milliHertz + uint32_t lporder; ///< low-pass filter order + uint32_t lptype; ///< low-pass filter type +} cbFILTDESC; + +/// @brief Scaling structure +/// +/// Structure used in cbPKT_CHANINFO +typedef struct { + int16_t digmin; ///< digital value that cooresponds with the anamin value + int16_t digmax; ///< digital value that cooresponds with the anamax value + int32_t anamin; ///< the minimum analog value present in the signal + int32_t anamax; ///< the maximum analog value present in the signal + int32_t anagain; ///< the gain applied to the default analog values to get the analog values + char anaunit[cbLEN_STR_UNIT]; ///< the unit for the analog signal (eg, "uV" or "MPa") +} cbSCALING; + +/// @brief Manual Unit Mapping structure +/// +/// Defines an ellipsoid for sorting. Used in cbPKT_CHANINFO and cbPKT_NTRODEINFO +typedef struct { + int16_t nOverride; ///< override to unit if in ellipsoid + int16_t afOrigin[3]; ///< ellipsoid origin + int16_t afShape[3][3]; ///< ellipsoid shape + int16_t aPhi; ///< + uint32_t bValid; ///< is this unit in use at this time? + ///< BOOL implemented as uint32_t - for structure alignment at paragraph boundary +} cbMANUALUNITMAPPING; + +/// @brief Hoop definition structure +/// +/// Defines the hoop used for sorting. There can be up to 5 hoops per unit. Used in cbPKT_CHANINFO +typedef struct { + uint16_t valid; ///< 0=undefined, 1 for valid + int16_t time; ///< time offset into spike window + int16_t min; ///< minimum value for the hoop window + int16_t max; ///< maximum value for the hoop window +} cbHOOP; + +/// @brief PKT Set:0xCx Rep:0x4x - Channel Information +/// +/// This contains the details for each channel within the system. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< actual channel id of the channel being configured + uint32_t proc; ///< the address of the processor on which the channel resides + uint32_t bank; ///< the address of the bank on which the channel resides + uint32_t term; ///< the terminal number of the channel within it's bank + uint32_t chancaps; ///< general channel capablities (given by cbCHAN_* flags) + uint32_t doutcaps; ///< digital output capablities (composed of cbDOUT_* flags) + uint32_t dinpcaps; ///< digital input capablities (composed of cbDINP_* flags) + uint32_t aoutcaps; ///< analog output capablities (composed of cbAOUT_* flags) + uint32_t ainpcaps; ///< analog input capablities (composed of cbAINP_* flags) + uint32_t spkcaps; ///< spike processing capabilities + cbSCALING physcalin; ///< physical channel scaling information + cbFILTDESC phyfiltin; ///< physical channel filter definition + cbSCALING physcalout; ///< physical channel scaling information + cbFILTDESC phyfiltout; ///< physical channel filter definition + char label[cbLEN_STR_LABEL]; ///< Label of the channel (null terminated if <16 characters) + uint32_t userflags; ///< User flags for the channel state + int32_t position[4]; ///< reserved for future position information + cbSCALING scalin; ///< user-defined scaling information for AINP + cbSCALING scalout; ///< user-defined scaling information for AOUT + uint32_t doutopts; ///< digital output options (composed of cbDOUT_* flags) + uint32_t dinpopts; ///< digital input options (composed of cbDINP_* flags) + uint32_t aoutopts; ///< analog output options + uint32_t eopchar; ///< digital input capablities (given by cbDINP_* flags) + union { + struct { // separate system channel to instrument specific channel number + uint32_t monsource; ///< address of channel to monitor + int32_t outvalue; ///< output value + }; + struct { // used for digout timed output + uint16_t lowsamples; ///< number of samples to set low for timed output + uint16_t highsamples; ///< number of samples to set high for timed output + int32_t offset; ///< number of samples to offset the transitions for timed output + }; + }; + uint8_t trigtype; ///< trigger type (see cbDOUT_TRIGGER_*) + uint16_t trigchan; ///< trigger channel + uint16_t trigval; ///< trigger value + uint32_t ainpopts; ///< analog input options (composed of cbAINP* flags) + uint32_t lncrate; ///< line noise cancellation filter adaptation rate + uint32_t smpfilter; ///< continuous-time pathway filter id + uint32_t smpgroup; ///< continuous-time pathway sample group + int32_t smpdispmin; ///< continuous-time pathway display factor + int32_t smpdispmax; ///< continuous-time pathway display factor + uint32_t spkfilter; ///< spike pathway filter id + int32_t spkdispmax; ///< spike pathway display factor + int32_t lncdispmax; ///< Line Noise pathway display factor + uint32_t spkopts; ///< spike processing options + int32_t spkthrlevel; ///< spike threshold level + int32_t spkthrlimit; ///< + uint32_t spkgroup; ///< NTrodeGroup this electrode belongs to - 0 is single unit, non-0 indicates a multi-trode grouping + int16_t amplrejpos; ///< Amplitude rejection positive value + int16_t amplrejneg; ///< Amplitude rejection negative value + uint32_t refelecchan; ///< Software reference electrode channel + cbMANUALUNITMAPPING unitmapping[cbMAXUNITS]; ///< manual unit mapping + cbHOOP spkhoops[cbMAXUNITS][cbMAXHOOPS]; ///< spike hoop sorting set +} cbPKT_CHANINFO; + +/// @brief PKT Set:0xDB Rep:0x5B - Feature Space Basis +/// +/// This packet holds the calculated basis of the feature space from NSP to Central +/// Or it has the previous basis retrieved and transmitted by central to NSP +typedef struct +{ + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< 1-based channel number + uint32_t mode; ///< cbBASIS_CHANGE, cbUNDO_BASIS_CHANGE, cbREDO_BASIS_CHANGE, cbINVALIDATE_BASIS ... + uint32_t fs; ///< Feature space: cbAUTOALG_PCA + /// basis must be the last item in the structure because it can be variable length to a max of cbMAX_PNTS + float basis[cbMAX_PNTS][3]; ///< Room for all possible points collected +} cbPKT_FS_BASIS; + +/// @brief PKT Set:0xD1 Rep:0x51 - Get the spike sorting model for a single channel (Histogram Peak Count) +/// +/// The system replys with the model of a specific channel. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< actual channel id of the channel being configured (0 based) + uint32_t unit_number; ///< unit label (0 based, 0 is noise cluster) + uint32_t valid; ///< 1 = valid unit, 0 = not a unit, in other words just deleted when NSP -> PC + uint32_t inverted; ///< 0 = not inverted, 1 = inverted + + // Block statistics (change from block to block) + int32_t num_samples; ///< non-zero value means that the block stats are valid + float mu_x[2]; + float Sigma_x[2][2]; + float determinant_Sigma_x; + ///// Only needed if we are using a Bayesian classification model + float Sigma_x_inv[2][2]; + float log_determinant_Sigma_x; + ///// + float subcluster_spread_factor_numerator; + float subcluster_spread_factor_denominator; + float mu_e; + float sigma_e_squared; +} cbPKT_SS_MODELSET; + +/// @brief PKT Set:0xD2 Rep:0x52 - Auto threshold parameters +/// +/// Set the auto threshold parameters +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + float fThreshold; ///< current detection threshold + float fMultiplier; ///< multiplier +} cbPKT_SS_DETECT; + +/// @brief PKT Set:0xD3 Rep:0x53 - Artifact reject +/// +/// Sets the artifact rejection parameters. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t nMaxSimulChans; ///< how many channels can fire exactly at the same time??? + uint32_t nRefractoryCount; ///< for how many samples (30 kHz) is a neuron refractory, so can't re-trigger +} cbPKT_SS_ARTIF_REJECT; + +/// @brief PKT Set:0xD4 Rep:0x54 - Noise boundary +/// +/// Sets the noise boundary parameters +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< which channel we belong to + float afc[3]; ///< the center of the ellipsoid + float afS[3][3]; ///< an array of the axes for the ellipsoid +} cbPKT_SS_NOISE_BOUNDARY; + +/// @brief PKT Set:0xD5 Rep:0x55 - Spike sourting statistics (Histogram peak count) +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t nUpdateSpikes; ///< update rate in spike counts + + uint32_t nAutoalg; ///< sorting algorithm (0=none 1=spread, 2=hist_corr_maj, 3=hist_peak_count_maj, 4=hist_peak_count_maj_fisher, 5=pca, 6=hoops) + uint32_t nMode; ///< cbAUTOALG_MODE_SETTING, + + float fMinClusterPairSpreadFactor; ///< larger number = more apt to combine 2 clusters into 1 + float fMaxSubclusterSpreadFactor; ///< larger number = less apt to split because of 2 clusers + + float fMinClusterHistCorrMajMeasure; ///< larger number = more apt to split 1 cluster into 2 + float fMaxClusterPairHistCorrMajMeasure; ///< larger number = less apt to combine 2 clusters into 1 + + float fClusterHistValleyPercentage; ///< larger number = less apt to split nearby clusters + float fClusterHistClosePeakPercentage; ///< larger number = less apt to split nearby clusters + float fClusterHistMinPeakPercentage; ///< larger number = less apt to split separated clusters + + uint32_t nWaveBasisSize; ///< number of wave to collect to calculate the basis, + ///< must be greater than spike length + uint32_t nWaveSampleSize; ///< number of samples sorted with the same basis before re-calculating the basis + ///< 0=manual re-calculation + ///< nWaveBasisSize * nWaveSampleSize is the number of waves/spikes to run against + ///< the same PCA basis before next +} cbPKT_SS_STATISTICS; + +/// @brief Adaptive Control structure +typedef struct { + uint32_t nMode; ///< 0-do not adapt at all, 1-always adapt, 2-adapt if timer not timed out + float fTimeOutMinutes; ///< how many minutes until time out + float fElapsedMinutes; ///< the amount of time that has elapsed +} cbAdaptControl; + +/// @brief PKT Set:0xD7 Rep:0x57 - Spike sorting status (Histogram peak count) +/// +/// This packet contains the status of the automatic spike sorting. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + cbAdaptControl cntlUnitStats; ///< + cbAdaptControl cntlNumUnits; ///< +} cbPKT_SS_STATUS; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Spike sorting configuration +/// +/// Groups all spike-sorting related configuration packets together. +typedef struct { + cbPKT_FS_BASIS asBasis[cbMAXCHANS]; ///< PCA basis values per channel + cbPKT_SS_MODELSET asSortModel[cbMAXCHANS][cbMAXUNITS + 2]; ///< Sorting models/rules per channel + + //////// These are spike sorting options + cbPKT_SS_DETECT pktDetect; ///< Detection parameters + cbPKT_SS_ARTIF_REJECT pktArtifReject; ///< Artifact rejection parameters + cbPKT_SS_NOISE_BOUNDARY pktNoiseBoundary[cbMAXCHANS]; ///< Noise boundaries per channel + cbPKT_SS_STATISTICS pktStatistics; ///< Spike statistics + cbPKT_SS_STATUS pktStatus; ///< Spike sorting status +} cbSPIKE_SORTING; + +/// @brief PKT Set:0xA7 Rep:0x27 - N-Trode information packets +/// +/// Sets information about an N-Trode. The user can change the name, number of sites, sites (channels) +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t ntrode; ///< ntrode with which we are working (1-based) + char label[cbLEN_STR_LABEL]; ///< Label of the Ntrode (null terminated if < 16 characters) + cbMANUALUNITMAPPING ellipses[cbMAXSITEPLOTS][cbMAXUNITS]; ///< unit mapping + uint16_t nSite; ///< number channels in this NTrode ( 0 <= nSite <= cbMAXSITES) + uint16_t fs; ///< NTrode feature space cbNTRODEINFO_FS_* + uint16_t nChan[cbMAXSITES]; ///< group of channels in this NTrode +} cbPKT_NTRODEINFO; + +constexpr uint32_t cbMAX_WAVEFORM_PHASES = ((cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - 24) / 4); ///< Maximum number of phases in a waveform + +/// @brief Analog output waveform data +/// +/// Contains the parameters to define a waveform for Analog Output channels +typedef struct +{ + int16_t offset; ///< DC offset + union { + struct { + uint16_t sineFrequency; ///< sine wave Hz + int16_t sineAmplitude; ///< sine amplitude + }; + struct { + uint16_t seq; ///< Wave sequence number (for file playback) + uint16_t seqTotal; ///< total number of sequences + uint16_t phases; ///< Number of valid phases in this wave (maximum is cbMAX_WAVEFORM_PHASES) + uint16_t duration[cbMAX_WAVEFORM_PHASES]; ///< array of durations for each phase + int16_t amplitude[cbMAX_WAVEFORM_PHASES]; ///< array of amplitude for each phase + }; + }; +} cbWaveformData; + +/// @brief PKT Set:0xB3 Rep:0x33 - AOUT waveform +/// +/// This sets a user defined waveform for one or multiple Analog & Audio Output channels. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint16_t chan; ///< which analog output/audio output channel (1-based, will equal chan from GetDoutCaps) + + /// Each file may contain multiple sequences. + /// Each sequence consists of phases + /// Each phase is defined by amplitude and duration + + /// Waveform parameter information + uint16_t mode; ///< Can be any of cbWAVEFORM_MODE_* + uint32_t repeats; ///< Number of repeats (0 means forever) + uint16_t trig; ///< Can be any of cbWAVEFORM_TRIGGER* + uint16_t trigChan; ///< Depends on trig: + /// for cbWAVEFORM_TRIGGER_DINP* 1-based trigChan (1-16) is digin1, (17-32) is digin2, ... + /// for cbWAVEFORM_TRIGGER_SPIKEUNIT 1-based trigChan (1-156) is channel number + /// for cbWAVEFORM_TRIGGER_COMMENTCOLOR trigChan is A->B in A->B->G->R + uint16_t trigValue; ///< Trigger value (spike unit, G-R comment color, ...) + uint8_t trigNum; ///< trigger number (0-based) (can be up to cbMAX_AOUT_TRIGGER-1) + uint8_t active; ///< status of trigger + cbWaveformData wave; ///< Actual waveform data +} cbPKT_AOUT_WAVEFORM; + +/// @brief PKT Set:0xA8 Rep:0x28 - Line Noise Cancellation +/// +/// This packet holds the Line Noise Cancellation parameters +typedef struct +{ + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t lncFreq; ///< Nominal line noise frequency to be canceled (in Hz) + uint32_t lncRefChan; ///< Reference channel for lnc synch (1-based) + uint32_t lncGlobalMode; ///< reserved +} cbPKT_LNC; + +constexpr uint32_t cbNPLAY_FNAME_LEN = (cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - 40); ///< length of the file name (with terminating null) + +/// @brief PKT Set:0xDC Rep:0x5C - nPlay configuration packet +/// +/// Sent on restart together with config packet +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + union { + PROCTIME ftime; ///< the total time of the file. + PROCTIME opt; ///< optional value + }; + PROCTIME stime; ///< start time + PROCTIME etime; ///< stime < end time < ftime + PROCTIME val; ///< Used for current time to traverse, file index, file version, ... + uint16_t mode; ///< cbNPLAY_MODE_* command to nPlay + uint16_t flags; ///< cbNPLAY_FLAG_* status of nPlay + float speed; ///< positive means fast forward, negative means rewind, 0 means go as fast as you can. + char fname[cbNPLAY_FNAME_LEN]; ///< This is a String with the file name. +} cbPKT_NPLAY; + +/// @brief NeuroMotive video source +typedef struct { + char name[cbLEN_STR_LABEL]; ///< filename of the video file + float fps; ///< nominal record fps +} cbVIDEOSOURCE; + +/// @brief Track object structure for NeuroMotive +typedef struct { + char name[cbLEN_STR_LABEL]; ///< name of the object + uint16_t type; ///< trackable type (cbTRACKOBJ_TYPE_*) + uint16_t pointCount; ///< maximum number of points +} cbTRACKOBJ; + +/// @brief PKT Set:0xE1 Rep:0x61 - File configuration packet +/// +/// File recording can be started or stopped externally using this packet. It also contains a timeout mechanism to notify +/// if file isn't still recording. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t options; ///< cbFILECFG_OPT_* + uint32_t duration; + uint32_t recording; ///< If cbFILECFG_OPT_NONE this option starts/stops recording remotely + uint32_t extctrl; ///< If cbFILECFG_OPT_REC this is split number (0 for non-TOC) + ///< If cbFILECFG_OPT_STOP this is error code (0 means no error) + + char username[cbLEN_STR_COMMENT]; ///< name of computer issuing the packet + union { + char filename[cbLEN_STR_COMMENT]; ///< filename to record to + char datetime[cbLEN_STR_COMMENT]; ///< + }; + char comment[cbLEN_STR_COMMENT]; ///< comment to include in the file +} cbPKT_FILECFG; + +/// @} /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Central's actual binary layout (CentralLegacyCFGBUFF) @@ -180,6 +726,24 @@ struct CentralTransmitBufferLocal { uint32_t buffer[cbXMT_LOCAL_BUFFLEN]; ///< Ring buffer for packet data }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Data packet - Spike waveform data +/// +/// Detected spikes are sent through this packet. The spike waveform may or may not be sent depending +/// on the dlen contained in the header. The waveform can be anywhere from 30 samples to 128 samples +/// based on user configuration. The default spike length is 48 samples. cbpkt_header.chid is the +/// channel number of the spike. cbpkt_header.type is the sorted unit number (0=unsorted, 255=noise). +typedef struct { + cbPKT_HEADER cbpkt_header; ///< in the header for this packet, the type is used as the unit number + + float fPattern[3]; ///< values of the pattern space (Normal uses only 2, PCA uses third) + int16_t nPeak; ///< highest datapoint of the waveform + int16_t nValley; ///< lowest datapoint of the waveform + + int16_t wave[cbMAX_PNTS]; ///< datapoints of each sample of the waveform. Room for all possible points collected + ///< wave must be the last item in the structure because it can be variable length to a max of cbMAX_PNTS +} cbPKT_SPK; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Spike cache buffer /// @@ -203,6 +767,16 @@ struct CentralSpikeBuffer { CentralSpikeCache cache[cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Instrument status flags (bit field) +/// +/// Used to track which instruments are active in shared memory +/// +enum class InstrumentStatus : uint32_t { + INACTIVE = 0x00000000, ///< Instrument slot is not in use + ACTIVE = 0x00000001, ///< Instrument is active and has data +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief PC Status buffer (flattened from cbPcStatus class) /// @@ -217,6 +791,18 @@ enum class NSPStatus : uint32_t { NSP_INVALID = 4 }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Unit Selection +/// +/// Packet which says that these channels are now selected +typedef struct +{ + cbPKT_HEADER cbpkt_header; ///< packet header + + int32_t lastchan; ///< Which channel was clicked last. + uint16_t abyUnitSelections[(cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - sizeof(int32_t))]; ///< one for each channel, channels are 0 based here, shows units selected +} cbPKT_UNIT_SELECTION; + struct CentralPCStatus { // Public data cbPKT_UNIT_SELECTION isSelection[cbMAXPROCS]; ///< Unit selection per instrument diff --git a/src/cbshm/include/cbshm/central_types/v4_1.h b/src/cbshm/include/cbshm/central_types/v4_1.h index a8cbe25b..14d5d321 100644 --- a/src/cbshm/include/cbshm/central_types/v4_1.h +++ b/src/cbshm/include/cbshm/central_types/v4_1.h @@ -36,10 +36,14 @@ constexpr uint32_t cbMAXPROCS = 3; ///< Central supports up to 3 NSPs constexpr uint32_t cbNUM_FE_CHANS = 512; ///< Central supports 512 FE channels constexpr uint32_t cbMAXGROUPS = 8; ///< Sample rate groups constexpr uint32_t cbMAXFILTS = 32; ///< Digital filters -constexpr uint32_t cbMAXVIDEOSOURCE = 1; -constexpr uint32_t cbMAXTRACKOBJ = 20; -constexpr uint32_t cbMAXHOOPS = 4; -constexpr uint32_t cbMAX_AOUT_TRIGGER = 5; +constexpr uint32_t cbMAXVIDEOSOURCE = 1; ///< Maximum number of video sources +constexpr uint32_t cbMAXTRACKOBJ = 20; ///< Maximum number of trackable objects +constexpr uint32_t cbMAXHOOPS = 4; ///< Maximum number of hoops for spike sorting +constexpr uint32_t cbMAXSITES = 4; ///< Maximum number of electrodes in an n-trode group +constexpr uint32_t cbMAXSITEPLOTS = ((cbMAXSITES - 1) * cbMAXSITES / 2); ///< Combination of 2 out of n +constexpr uint32_t cbMAXUNITS = 5; ///< Maximum number of sorted units per channel +constexpr uint32_t cbMAX_PNTS = 128; ///< Maximum spike waveform points +constexpr uint32_t cbMAX_AOUT_TRIGGER = 5; ///< Maximum number of per-channel (analog output, or digital output) triggers // Channel counts constexpr uint32_t cbNUM_ANAIN_CHANS = 16 * cbMAXPROCS; @@ -100,14 +104,560 @@ constexpr uint32_t cbRECBUFFLEN = cbNUM_FE_CHANS * 32768 * 4; /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Instrument status flags (bit field) +/// @name String Length Constants +/// @{ + +constexpr uint32_t cbLEN_STR_UNIT = 8; ///< Length of unit string +constexpr uint32_t cbLEN_STR_LABEL = 16; ///< Length of label string +constexpr uint32_t cbLEN_STR_FILT_LABEL = 16; ///< Length of filter label string +constexpr uint32_t cbLEN_STR_IDENT = 64; ///< Length of identity string +constexpr uint32_t cbLEN_STR_COMMENT = 256; ///< Length of comment string +constexpr uint32_t cbMAX_COMMENT = 128; ///< Maximum comment length (must be multiple of 4) + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Central config buffer subtypes +/// @{ + +typedef uint64_t PROCTIME; + +/// @brief Cerebus packet header data structure +typedef struct { + PROCTIME time; ///< System clock timestamp + uint16_t chid; ///< Channel identifier + uint16_t type; ///< Packet type + uint16_t dlen; ///< Length of data field in 32-bit chunks + uint8_t instrument; ///< Instrument number (0-based in packet, despite cbNSP1=1!) + uint8_t reserved; ///< Reserved for future use +} cbPKT_HEADER; + +constexpr uint32_t cbPKT_MAX_SIZE = 1024; ///< Maximum packet size in bytes +constexpr uint32_t cbPKT_HEADER_SIZE = sizeof(cbPKT_HEADER); ///< Packet header size in bytes + +/// @brief Option table for Central application /// -/// Used to track which instruments are active in shared memory +/// Used for configuration options in Central +typedef struct { + float fRMSAutoThresholdDistance; ///< multiplier to use for autothresholding when using RMS to guess noise + uint32_t reserved[31]; ///< Reserved for future use +} cbOPTIONTABLE; + +/// @brief Color table for Central application /// -enum class InstrumentStatus : uint32_t { - INACTIVE = 0x00000000, ///< Instrument slot is not in use - ACTIVE = 0x00000001, ///< Instrument is active and has data -}; +/// Used for display configuration in Central +typedef struct { + uint32_t winrsvd[48]; ///< Reserved for Windows + uint32_t dispback; ///< Display background color + uint32_t dispgridmaj; ///< Display major grid color + uint32_t dispgridmin; ///< Display minor grid color + uint32_t disptext; ///< Display text color + uint32_t dispwave; ///< Display waveform color + uint32_t dispwavewarn; ///< Display waveform warning color + uint32_t dispwaveclip; ///< Display waveform clipping color + uint32_t dispthresh; ///< Display threshold color + uint32_t dispmultunit; ///< Display multi-unit color + uint32_t dispunit[16]; ///< Display unit colors (0 = unclassified) + uint32_t dispnoise; ///< Display noise color + uint32_t dispchansel[3]; ///< Display channel selection colors + uint32_t disptemp[5]; ///< Display temporary colors + uint32_t disprsvd[14]; ///< Reserved display colors +} cbCOLORTABLE; + +/// @brief PKT Set:0x92 Rep:0x12 - System info +/// +/// Contains system information including the runlevel +typedef struct { + cbPKT_HEADER cbpkt_header; ///< Packet header + + uint32_t sysfreq; ///< System sampling clock frequency in Hz + uint32_t spikelen; ///< The length of the spike events + uint32_t spikepre; ///< Spike pre-trigger samples + uint32_t resetque; ///< The channel for the reset to que on + uint32_t runlevel; ///< System runlevel + uint32_t runflags; ///< Lock recording after reset +} cbPKT_SYSINFO; + +/// @brief PKT Set:N/A Rep:0x21 - Info about the processor +/// +/// Includes information about the counts of various features of the processor +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< index of the bank + uint32_t idcode; ///< manufacturer part and rom ID code of the Signal Processor + char ident[cbLEN_STR_IDENT]; ///< ID string with the equipment name of the Signal Processor + uint32_t chanbase; ///< lowest channel number of channel id range claimed by this processor + uint32_t chancount; ///< number of channel identifiers claimed by this processor + uint32_t bankcount; ///< number of signal banks supported by the processor + uint32_t groupcount; ///< number of sample groups supported by the processor + uint32_t filtcount; ///< number of digital filters supported by the processor + uint32_t sortcount; ///< number of channels supported for spike sorting (reserved for future) + uint32_t unitcount; ///< number of supported units for spike sorting (reserved for future) + uint32_t hoopcount; ///< number of supported units for spike sorting (reserved for future) + uint32_t reserved; ///< reserved for future use, set to 0 + uint32_t version; ///< current version of libraries +} cbPKT_PROCINFO; + +/// @brief PKT Set:N/A Rep:0x22 - Information about the banks in the processor +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< the address of the processor on which the bank resides + uint32_t bank; ///< the address of the bank reported by the packet + uint32_t idcode; ///< manufacturer part and rom ID code of the module addressed to this bank + char ident[cbLEN_STR_IDENT]; ///< ID string with the equipment name of the Signal Bank hardware module + char label[cbLEN_STR_LABEL]; ///< Label on the instrument for the signal bank, eg "Analog In" + uint32_t chanbase; ///< lowest channel number of channel id range claimed by this bank + uint32_t chancount; ///< number of channel identifiers claimed by this bank +} cbPKT_BANKINFO; + +/// @brief PKT Set:0xB0 Rep:0x30 - Sample Group (GROUP) Information Packets +/// +/// Contains information including the name and list of channels for each sample group. The cbPKT_GROUP packet transmits +/// the data for each group based on the list contained here. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< processor number + uint32_t group; ///< group number + char label[cbLEN_STR_LABEL]; ///< sampling group label + uint32_t period; ///< sampling period for the group + uint32_t length; ///< number of channels in the list + uint16_t list[cbNUM_ANALOG_CHANS]; ///< variable length list. The max size is the total number of analog channels +} cbPKT_GROUPINFO; + +/// @brief PKT Set:0xA3 Rep:0x23 - Filter Information Packet +/// +/// Describes the filters contained in the NSP including the filter coefficients +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< + uint32_t filt; ///< + char label[cbLEN_STR_FILT_LABEL]; // name of the filter + uint32_t hpfreq; ///< high-pass corner frequency in milliHertz + uint32_t hporder; ///< high-pass filter order + uint32_t hptype; ///< high-pass filter type + uint32_t lpfreq; ///< low-pass frequency in milliHertz + uint32_t lporder; ///< low-pass filter order + uint32_t lptype; ///< low-pass filter type + ///< These are for sending the NSP filter info, otherwise the NSP has this stuff in NSPDefaults.c + double gain; ///< filter gain + double sos1a1; ///< filter coefficient + double sos1a2; ///< filter coefficient + double sos1b1; ///< filter coefficient + double sos1b2; ///< filter coefficient + double sos2a1; ///< filter coefficient + double sos2a2; ///< filter coefficient + double sos2b1; ///< filter coefficient + double sos2b2; ///< filter coefficient +} cbPKT_FILTINFO; + +/// @brief PKT Set:0xA5 Rep:0x25 - Adaptive filtering +/// +/// This sets the parameters for the adaptive filtering. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< Ignored + + uint32_t nMode; ///< 0=disabled, 1=filter continuous & spikes, 2=filter spikes + float dLearningRate; ///< speed at which adaptation happens. Very small. e.g. 5e-12 + uint32_t nRefChan1; ///< The first reference channel (1 based). + uint32_t nRefChan2; ///< The second reference channel (1 based). + +} cbPKT_ADAPTFILTINFO; + +/// @brief PKT Set:0xA6 Rep:0x26 - Reference Electrode Information. +/// +/// This configures a channel to be referenced by another channel. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< Ignored + + uint32_t nMode; ///< 0=disabled, 1=filter continuous & spikes, 2=filter spikes + uint32_t nRefChan; ///< The reference channel (1 based). +} cbPKT_REFELECFILTINFO; + +/// @brief Filter description structure +/// +/// Filter description used in cbPKT_CHANINFO +typedef struct { + char label[cbLEN_STR_FILT_LABEL]; + uint32_t hpfreq; ///< high-pass corner frequency in milliHertz + uint32_t hporder; ///< high-pass filter order + uint32_t hptype; ///< high-pass filter type + uint32_t lpfreq; ///< low-pass frequency in milliHertz + uint32_t lporder; ///< low-pass filter order + uint32_t lptype; ///< low-pass filter type +} cbFILTDESC; + +/// @brief Scaling structure +/// +/// Structure used in cbPKT_CHANINFO +typedef struct { + int16_t digmin; ///< digital value that cooresponds with the anamin value + int16_t digmax; ///< digital value that cooresponds with the anamax value + int32_t anamin; ///< the minimum analog value present in the signal + int32_t anamax; ///< the maximum analog value present in the signal + int32_t anagain; ///< the gain applied to the default analog values to get the analog values + char anaunit[cbLEN_STR_UNIT]; ///< the unit for the analog signal (eg, "uV" or "MPa") +} cbSCALING; + +/// @brief Manual Unit Mapping structure +/// +/// Defines an ellipsoid for sorting. Used in cbPKT_CHANINFO and cbPKT_NTRODEINFO +typedef struct { + int16_t nOverride; ///< override to unit if in ellipsoid + int16_t afOrigin[3]; ///< ellipsoid origin + int16_t afShape[3][3]; ///< ellipsoid shape + int16_t aPhi; ///< + uint32_t bValid; ///< is this unit in use at this time? + ///< BOOL implemented as uint32_t - for structure alignment at paragraph boundary +} cbMANUALUNITMAPPING; + +/// @brief Hoop definition structure +/// +/// Defines the hoop used for sorting. There can be up to 5 hoops per unit. Used in cbPKT_CHANINFO +typedef struct { + uint16_t valid; ///< 0=undefined, 1 for valid + int16_t time; ///< time offset into spike window + int16_t min; ///< minimum value for the hoop window + int16_t max; ///< maximum value for the hoop window +} cbHOOP; + +/// @brief PKT Set:0xCx Rep:0x4x - Channel Information +/// +/// This contains the details for each channel within the system. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< actual channel id of the channel being configured + uint32_t proc; ///< the address of the processor on which the channel resides + uint32_t bank; ///< the address of the bank on which the channel resides + uint32_t term; ///< the terminal number of the channel within it's bank + uint32_t chancaps; ///< general channel capablities (given by cbCHAN_* flags) + uint32_t doutcaps; ///< digital output capablities (composed of cbDOUT_* flags) + uint32_t dinpcaps; ///< digital input capablities (composed of cbDINP_* flags) + uint32_t aoutcaps; ///< analog output capablities (composed of cbAOUT_* flags) + uint32_t ainpcaps; ///< analog input capablities (composed of cbAINP_* flags) + uint32_t spkcaps; ///< spike processing capabilities + cbSCALING physcalin; ///< physical channel scaling information + cbFILTDESC phyfiltin; ///< physical channel filter definition + cbSCALING physcalout; ///< physical channel scaling information + cbFILTDESC phyfiltout; ///< physical channel filter definition + char label[cbLEN_STR_LABEL]; ///< Label of the channel (null terminated if <16 characters) + uint32_t userflags; ///< User flags for the channel state + int32_t position[4]; ///< reserved for future position information + cbSCALING scalin; ///< user-defined scaling information for AINP + cbSCALING scalout; ///< user-defined scaling information for AOUT + uint32_t doutopts; ///< digital output options (composed of cbDOUT_* flags) + uint32_t dinpopts; ///< digital input options (composed of cbDINP_* flags) + uint32_t aoutopts; ///< analog output options + uint32_t eopchar; ///< digital input capablities (given by cbDINP_* flags) + union { + struct { // separate system channel to instrument specific channel number + uint16_t moninst; ///< instrument of channel to monitor + uint16_t monchan; ///< channel to monitor + int32_t outvalue; ///< output value + }; + struct { // used for digout timed output + uint16_t lowsamples; ///< number of samples to set low for timed output + uint16_t highsamples; ///< number of samples to set high for timed output + int32_t offset; ///< number of samples to offset the transitions for timed output + }; + }; + uint8_t trigtype; ///< trigger type (see cbDOUT_TRIGGER_*) + uint8_t reserved[2]; ///< 2 bytes reserved + uint8_t triginst; ///< instrument of the trigger channel + uint16_t trigchan; ///< trigger channel + uint16_t trigval; ///< trigger value + uint32_t ainpopts; ///< analog input options (composed of cbAINP* flags) + uint32_t lncrate; ///< line noise cancellation filter adaptation rate + uint32_t smpfilter; ///< continuous-time pathway filter id + uint32_t smpgroup; ///< continuous-time pathway sample group + int32_t smpdispmin; ///< continuous-time pathway display factor + int32_t smpdispmax; ///< continuous-time pathway display factor + uint32_t spkfilter; ///< spike pathway filter id + int32_t spkdispmax; ///< spike pathway display factor + int32_t lncdispmax; ///< Line Noise pathway display factor + uint32_t spkopts; ///< spike processing options + int32_t spkthrlevel; ///< spike threshold level + int32_t spkthrlimit; ///< + uint32_t spkgroup; ///< NTrodeGroup this electrode belongs to - 0 is single unit, non-0 indicates a multi-trode grouping + int16_t amplrejpos; ///< Amplitude rejection positive value + int16_t amplrejneg; ///< Amplitude rejection negative value + uint32_t refelecchan; ///< Software reference electrode channel + cbMANUALUNITMAPPING unitmapping[cbMAXUNITS]; ///< manual unit mapping + cbHOOP spkhoops[cbMAXUNITS][cbMAXHOOPS]; ///< spike hoop sorting set +} cbPKT_CHANINFO; + +/// @brief PKT Set:0xDB Rep:0x5B - Feature Space Basis +/// +/// This packet holds the calculated basis of the feature space from NSP to Central +/// Or it has the previous basis retrieved and transmitted by central to NSP +typedef struct +{ + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< 1-based channel number + uint32_t mode; ///< cbBASIS_CHANGE, cbUNDO_BASIS_CHANGE, cbREDO_BASIS_CHANGE, cbINVALIDATE_BASIS ... + uint32_t fs; ///< Feature space: cbAUTOALG_PCA + /// basis must be the last item in the structure because it can be variable length to a max of cbMAX_PNTS + float basis[cbMAX_PNTS][3]; ///< Room for all possible points collected +} cbPKT_FS_BASIS; + +/// @brief PKT Set:0xD1 Rep:0x51 - Get the spike sorting model for a single channel (Histogram Peak Count) +/// +/// The system replys with the model of a specific channel. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< actual channel id of the channel being configured (0 based) + uint32_t unit_number; ///< unit label (0 based, 0 is noise cluster) + uint32_t valid; ///< 1 = valid unit, 0 = not a unit, in other words just deleted when NSP -> PC + uint32_t inverted; ///< 0 = not inverted, 1 = inverted + + // Block statistics (change from block to block) + int32_t num_samples; ///< non-zero value means that the block stats are valid + float mu_x[2]; + float Sigma_x[2][2]; + float determinant_Sigma_x; + ///// Only needed if we are using a Bayesian classification model + float Sigma_x_inv[2][2]; + float log_determinant_Sigma_x; + ///// + float subcluster_spread_factor_numerator; + float subcluster_spread_factor_denominator; + float mu_e; + float sigma_e_squared; +} cbPKT_SS_MODELSET; + +/// @brief PKT Set:0xD2 Rep:0x52 - Auto threshold parameters +/// +/// Set the auto threshold parameters +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + float fThreshold; ///< current detection threshold + float fMultiplier; ///< multiplier +} cbPKT_SS_DETECT; + +/// @brief PKT Set:0xD3 Rep:0x53 - Artifact reject +/// +/// Sets the artifact rejection parameters. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t nMaxSimulChans; ///< how many channels can fire exactly at the same time??? + uint32_t nRefractoryCount; ///< for how many samples (30 kHz) is a neuron refractory, so can't re-trigger +} cbPKT_SS_ARTIF_REJECT; + +/// @brief PKT Set:0xD4 Rep:0x54 - Noise boundary +/// +/// Sets the noise boundary parameters +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< which channel we belong to + float afc[3]; ///< the center of the ellipsoid + float afS[3][3]; ///< an array of the axes for the ellipsoid +} cbPKT_SS_NOISE_BOUNDARY; + +/// @brief PKT Set:0xD5 Rep:0x55 - Spike sourting statistics (Histogram peak count) +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t nUpdateSpikes; ///< update rate in spike counts + + uint32_t nAutoalg; ///< sorting algorithm (0=none 1=spread, 2=hist_corr_maj, 3=hist_peak_count_maj, 4=hist_peak_count_maj_fisher, 5=pca, 6=hoops) + uint32_t nMode; ///< cbAUTOALG_MODE_SETTING, + + float fMinClusterPairSpreadFactor; ///< larger number = more apt to combine 2 clusters into 1 + float fMaxSubclusterSpreadFactor; ///< larger number = less apt to split because of 2 clusers + + float fMinClusterHistCorrMajMeasure; ///< larger number = more apt to split 1 cluster into 2 + float fMaxClusterPairHistCorrMajMeasure; ///< larger number = less apt to combine 2 clusters into 1 + + float fClusterHistValleyPercentage; ///< larger number = less apt to split nearby clusters + float fClusterHistClosePeakPercentage; ///< larger number = less apt to split nearby clusters + float fClusterHistMinPeakPercentage; ///< larger number = less apt to split separated clusters + + uint32_t nWaveBasisSize; ///< number of wave to collect to calculate the basis, + ///< must be greater than spike length + uint32_t nWaveSampleSize; ///< number of samples sorted with the same basis before re-calculating the basis + ///< 0=manual re-calculation + ///< nWaveBasisSize * nWaveSampleSize is the number of waves/spikes to run against + ///< the same PCA basis before next +} cbPKT_SS_STATISTICS; + +/// @brief Adaptive Control structure +typedef struct { + uint32_t nMode; ///< 0-do not adapt at all, 1-always adapt, 2-adapt if timer not timed out + float fTimeOutMinutes; ///< how many minutes until time out + float fElapsedMinutes; ///< the amount of time that has elapsed +} cbAdaptControl; + +/// @brief PKT Set:0xD7 Rep:0x57 - Spike sorting status (Histogram peak count) +/// +/// This packet contains the status of the automatic spike sorting. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + cbAdaptControl cntlUnitStats; ///< + cbAdaptControl cntlNumUnits; ///< +} cbPKT_SS_STATUS; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Spike sorting configuration +/// +/// Groups all spike-sorting related configuration packets together. +typedef struct { + cbPKT_FS_BASIS asBasis[cbMAXCHANS]; ///< PCA basis values per channel + cbPKT_SS_MODELSET asSortModel[cbMAXCHANS][cbMAXUNITS + 2]; ///< Sorting models/rules per channel + + //////// These are spike sorting options + cbPKT_SS_DETECT pktDetect; ///< Detection parameters + cbPKT_SS_ARTIF_REJECT pktArtifReject; ///< Artifact rejection parameters + cbPKT_SS_NOISE_BOUNDARY pktNoiseBoundary[cbMAXCHANS]; ///< Noise boundaries per channel + cbPKT_SS_STATISTICS pktStatistics; ///< Spike statistics + cbPKT_SS_STATUS pktStatus; ///< Spike sorting status +} cbSPIKE_SORTING; + +/// @brief PKT Set:0xA7 Rep:0x27 - N-Trode information packets +/// +/// Sets information about an N-Trode. The user can change the name, number of sites, sites (channels) +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t ntrode; ///< ntrode with which we are working (1-based) + char label[cbLEN_STR_LABEL]; ///< Label of the Ntrode (null terminated if < 16 characters) + cbMANUALUNITMAPPING ellipses[cbMAXSITEPLOTS][cbMAXUNITS]; ///< unit mapping + uint16_t nSite; ///< number channels in this NTrode ( 0 <= nSite <= cbMAXSITES) + uint16_t fs; ///< NTrode feature space cbNTRODEINFO_FS_* + uint16_t nChan[cbMAXSITES]; ///< group of channels in this NTrode +} cbPKT_NTRODEINFO; + +constexpr uint32_t cbMAX_WAVEFORM_PHASES = ((cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - 24) / 4); ///< Maximum number of phases in a waveform + +/// @brief Analog output waveform data +/// +/// Contains the parameters to define a waveform for Analog Output channels +typedef struct +{ + int16_t offset; ///< DC offset + union { + struct { + uint16_t sineFrequency; ///< sine wave Hz + int16_t sineAmplitude; ///< sine amplitude + }; + struct { + uint16_t seq; ///< Wave sequence number (for file playback) + uint16_t seqTotal; ///< total number of sequences + uint16_t phases; ///< Number of valid phases in this wave (maximum is cbMAX_WAVEFORM_PHASES) + uint16_t duration[cbMAX_WAVEFORM_PHASES]; ///< array of durations for each phase + int16_t amplitude[cbMAX_WAVEFORM_PHASES]; ///< array of amplitude for each phase + }; + }; +} cbWaveformData; + +/// @brief PKT Set:0xB3 Rep:0x33 - AOUT waveform +/// +/// This sets a user defined waveform for one or multiple Analog & Audio Output channels. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint16_t chan; ///< which analog output/audio output channel (1-based, will equal chan from GetDoutCaps) + + /// Each file may contain multiple sequences. + /// Each sequence consists of phases + /// Each phase is defined by amplitude and duration + + /// Waveform parameter information + uint16_t mode; ///< Can be any of cbWAVEFORM_MODE_* + uint32_t repeats; ///< Number of repeats (0 means forever) + uint8_t trig; ///< Can be any of cbWAVEFORM_TRIGGER_* + uint8_t trigInst; ///< Instrument the trigChan belongs + uint16_t trigChan; ///< Depends on trig: + /// for cbWAVEFORM_TRIGGER_DINP* 1-based trigChan (1-16) is digin1, (17-32) is digin2, ... + /// for cbWAVEFORM_TRIGGER_SPIKEUNIT 1-based trigChan (1-156) is channel number + /// for cbWAVEFORM_TRIGGER_COMMENTCOLOR trigChan is A->B in A->B->G->R + uint16_t trigValue; ///< Trigger value (spike unit, G-R comment color, ...) + uint8_t trigNum; ///< trigger number (0-based) (can be up to cbMAX_AOUT_TRIGGER-1) + uint8_t active; ///< status of trigger + cbWaveformData wave; ///< Actual waveform data +} cbPKT_AOUT_WAVEFORM; + +/// @brief PKT Set:0xA8 Rep:0x28 - Line Noise Cancellation +/// +/// This packet holds the Line Noise Cancellation parameters +typedef struct +{ + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t lncFreq; ///< Nominal line noise frequency to be canceled (in Hz) + uint32_t lncRefChan; ///< Reference channel for lnc synch (1-based) + uint32_t lncGlobalMode; ///< reserved +} cbPKT_LNC; + +constexpr uint32_t cbNPLAY_FNAME_LEN = (cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - 40); ///< length of the file name (with terminating null) + +/// @brief PKT Set:0xDC Rep:0x5C - nPlay configuration packet +/// +/// Sent on restart together with config packet +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + union { + PROCTIME ftime; ///< the total time of the file. + PROCTIME opt; ///< optional value + }; + PROCTIME stime; ///< start time + PROCTIME etime; ///< stime < end time < ftime + PROCTIME val; ///< Used for current time to traverse, file index, file version, ... + uint16_t mode; ///< cbNPLAY_MODE_* command to nPlay + uint16_t flags; ///< cbNPLAY_FLAG_* status of nPlay + float speed; ///< positive means fast forward, negative means rewind, 0 means go as fast as you can. + char fname[cbNPLAY_FNAME_LEN]; ///< This is a String with the file name. +} cbPKT_NPLAY; + +/// @brief NeuroMotive video source +typedef struct { + char name[cbLEN_STR_LABEL]; ///< filename of the video file + float fps; ///< nominal record fps +} cbVIDEOSOURCE; + +/// @brief Track object structure for NeuroMotive +typedef struct { + char name[cbLEN_STR_LABEL]; ///< name of the object + uint16_t type; ///< trackable type (cbTRACKOBJ_TYPE_*) + uint16_t pointCount; ///< maximum number of points +} cbTRACKOBJ; + +/// @brief PKT Set:0xE1 Rep:0x61 - File configuration packet +/// +/// File recording can be started or stopped externally using this packet. It also contains a timeout mechanism to notify +/// if file isn't still recording. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t options; ///< cbFILECFG_OPT_* + uint32_t duration; + uint32_t recording; ///< If cbFILECFG_OPT_NONE this option starts/stops recording remotely + uint32_t extctrl; ///< If cbFILECFG_OPT_REC this is split number (0 for non-TOC) + ///< If cbFILECFG_OPT_STOP this is error code (0 means no error) + + char username[cbLEN_STR_COMMENT]; ///< name of computer issuing the packet + union { + char filename[cbLEN_STR_COMMENT]; ///< filename to record to + char datetime[cbLEN_STR_COMMENT]; ///< + }; + char comment[cbLEN_STR_COMMENT]; ///< comment to include in the file +} cbPKT_FILECFG; + +/// @} /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Central's actual binary layout (CentralLegacyCFGBUFF) @@ -180,6 +730,24 @@ struct CentralTransmitBufferLocal { uint32_t buffer[cbXMT_LOCAL_BUFFLEN]; ///< Ring buffer for packet data }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Data packet - Spike waveform data +/// +/// Detected spikes are sent through this packet. The spike waveform may or may not be sent depending +/// on the dlen contained in the header. The waveform can be anywhere from 30 samples to 128 samples +/// based on user configuration. The default spike length is 48 samples. cbpkt_header.chid is the +/// channel number of the spike. cbpkt_header.type is the sorted unit number (0=unsorted, 255=noise). +typedef struct { + cbPKT_HEADER cbpkt_header; ///< in the header for this packet, the type is used as the unit number + + float fPattern[3]; ///< values of the pattern space (Normal uses only 2, PCA uses third) + int16_t nPeak; ///< highest datapoint of the waveform + int16_t nValley; ///< lowest datapoint of the waveform + + int16_t wave[cbMAX_PNTS]; ///< datapoints of each sample of the waveform. Room for all possible points collected + ///< wave must be the last item in the structure because it can be variable length to a max of cbMAX_PNTS +} cbPKT_SPK; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Spike cache buffer /// @@ -203,6 +771,16 @@ struct CentralSpikeBuffer { CentralSpikeCache cache[cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Instrument status flags (bit field) +/// +/// Used to track which instruments are active in shared memory +/// +enum class InstrumentStatus : uint32_t { + INACTIVE = 0x00000000, ///< Instrument slot is not in use + ACTIVE = 0x00000001, ///< Instrument is active and has data +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief PC Status buffer (flattened from cbPcStatus class) /// @@ -217,6 +795,18 @@ enum class NSPStatus : uint32_t { NSP_INVALID = 4 }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Unit Selection +/// +/// Packet which says that these channels are now selected +typedef struct +{ + cbPKT_HEADER cbpkt_header; ///< packet header + + int32_t lastchan; ///< Which channel was clicked last. + uint16_t abyUnitSelections[(cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - sizeof(int32_t))]; ///< one for each channel, channels are 0 based here, shows units selected +} cbPKT_UNIT_SELECTION; + struct CentralPCStatus { // Public data cbPKT_UNIT_SELECTION isSelection[cbMAXPROCS]; ///< Unit selection per instrument diff --git a/src/cbshm/include/cbshm/central_types/v4_2.h b/src/cbshm/include/cbshm/central_types/v4_2.h index 3912e46c..8b314c92 100644 --- a/src/cbshm/include/cbshm/central_types/v4_2.h +++ b/src/cbshm/include/cbshm/central_types/v4_2.h @@ -36,10 +36,14 @@ constexpr uint32_t cbMAXPROCS = 4; ///< Central supports up to 4 NSPs constexpr uint32_t cbNUM_FE_CHANS = 768; ///< Central supports 768 FE channels constexpr uint32_t cbMAXGROUPS = 8; ///< Sample rate groups constexpr uint32_t cbMAXFILTS = 32; ///< Digital filters -constexpr uint32_t cbMAXVIDEOSOURCE = 1; -constexpr uint32_t cbMAXTRACKOBJ = 20; -constexpr uint32_t cbMAXHOOPS = 4; -constexpr uint32_t cbMAX_AOUT_TRIGGER = 5; +constexpr uint32_t cbMAXVIDEOSOURCE = 1; ///< Maximum number of video sources +constexpr uint32_t cbMAXTRACKOBJ = 20; ///< Maximum number of trackable objects +constexpr uint32_t cbMAXHOOPS = 4; ///< Maximum number of hoops for spike sorting +constexpr uint32_t cbMAXSITES = 4; ///< Maximum number of electrodes in an n-trode group +constexpr uint32_t cbMAXSITEPLOTS = ((cbMAXSITES - 1) * cbMAXSITES / 2); ///< Combination of 2 out of n +constexpr uint32_t cbMAXUNITS = 5; ///< Maximum number of sorted units per channel +constexpr uint32_t cbMAX_PNTS = 128; ///< Maximum spike waveform points +constexpr uint32_t cbMAX_AOUT_TRIGGER = 5; ///< Maximum number of per-channel (analog output, or digital output) triggers // Channel counts constexpr uint32_t cbNUM_ANAIN_CHANS = 16 * cbMAXPROCS; @@ -100,19 +104,563 @@ constexpr uint32_t cbRECBUFFLEN = cbNUM_FE_CHANS * 65536 * 4 - 1; /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Instrument status flags (bit field) +/// @name String Length Constants +/// @{ + +constexpr uint32_t cbLEN_STR_UNIT = 8; ///< Length of unit string +constexpr uint32_t cbLEN_STR_LABEL = 16; ///< Length of label string +constexpr uint32_t cbLEN_STR_FILT_LABEL = 16; ///< Length of filter label string +constexpr uint32_t cbLEN_STR_IDENT = 64; ///< Length of identity string +constexpr uint32_t cbLEN_STR_COMMENT = 256; ///< Length of comment string +constexpr uint32_t cbMAX_COMMENT = 128; ///< Maximum comment length (must be multiple of 4) + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Central config buffer subtypes +/// @{ + +typedef uint64_t PROCTIME; + +/// @brief Cerebus packet header data structure +typedef struct { + PROCTIME time; ///< System clock timestamp + uint16_t chid; ///< Channel identifier + uint16_t type; ///< Packet type + uint16_t dlen; ///< Length of data field in 32-bit chunks + uint8_t instrument; ///< Instrument number (0-based in packet, despite cbNSP1=1!) + uint8_t reserved; ///< Reserved for future use +} cbPKT_HEADER; + +constexpr uint32_t cbPKT_MAX_SIZE = 1024; ///< Maximum packet size in bytes +constexpr uint32_t cbPKT_HEADER_SIZE = sizeof(cbPKT_HEADER); ///< Packet header size in bytes + +/// @brief Option table for Central application /// -/// Used to track which instruments are active in shared memory +/// Used for configuration options in Central +typedef struct { + float fRMSAutoThresholdDistance; ///< multiplier to use for autothresholding when using RMS to guess noise + uint32_t reserved[31]; ///< Reserved for future use +} cbOPTIONTABLE; + +/// @brief Color table for Central application /// -enum class InstrumentStatus : uint32_t { - INACTIVE = 0x00000000, ///< Instrument slot is not in use - ACTIVE = 0x00000001, ///< Instrument is active and has data -}; +/// Used for display configuration in Central +typedef struct { + uint32_t winrsvd[48]; ///< Reserved for Windows + uint32_t dispback; ///< Display background color + uint32_t dispgridmaj; ///< Display major grid color + uint32_t dispgridmin; ///< Display minor grid color + uint32_t disptext; ///< Display text color + uint32_t dispwave; ///< Display waveform color + uint32_t dispwavewarn; ///< Display waveform warning color + uint32_t dispwaveclip; ///< Display waveform clipping color + uint32_t dispthresh; ///< Display threshold color + uint32_t dispmultunit; ///< Display multi-unit color + uint32_t dispunit[16]; ///< Display unit colors (0 = unclassified) + uint32_t dispnoise; ///< Display noise color + uint32_t dispchansel[3]; ///< Display channel selection colors + uint32_t disptemp[5]; ///< Display temporary colors + uint32_t disprsvd[14]; ///< Reserved display colors +} cbCOLORTABLE; + +/// @brief PKT Set:0x92 Rep:0x12 - System info +/// +/// Contains system information including the runlevel +typedef struct { + cbPKT_HEADER cbpkt_header; ///< Packet header + + uint32_t sysfreq; ///< System sampling clock frequency in Hz + uint32_t spikelen; ///< The length of the spike events + uint32_t spikepre; ///< Spike pre-trigger samples + uint32_t resetque; ///< The channel for the reset to que on + uint32_t runlevel; ///< System runlevel + uint32_t runflags; ///< Lock recording after reset +} cbPKT_SYSINFO; + +/// @brief PKT Set:N/A Rep:0x21 - Info about the processor +/// +/// Includes information about the counts of various features of the processor +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< index of the bank + uint32_t idcode; ///< manufacturer part and rom ID code of the Signal Processor + char ident[cbLEN_STR_IDENT]; ///< ID string with the equipment name of the Signal Processor + uint32_t chanbase; ///< lowest channel number of channel id range claimed by this processor + uint32_t chancount; ///< number of channel identifiers claimed by this processor + uint32_t bankcount; ///< number of signal banks supported by the processor + uint32_t groupcount; ///< number of sample groups supported by the processor + uint32_t filtcount; ///< number of digital filters supported by the processor + uint32_t sortcount; ///< number of channels supported for spike sorting (reserved for future) + uint32_t unitcount; ///< number of supported units for spike sorting (reserved for future) + uint32_t hoopcount; ///< number of supported units for spike sorting (reserved for future) + uint32_t reserved; ///< reserved for future use, set to 0 + uint32_t version; ///< current version of libraries +} cbPKT_PROCINFO; + +/// @brief PKT Set:N/A Rep:0x22 - Information about the banks in the processor +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< the address of the processor on which the bank resides + uint32_t bank; ///< the address of the bank reported by the packet + uint32_t idcode; ///< manufacturer part and rom ID code of the module addressed to this bank + char ident[cbLEN_STR_IDENT]; ///< ID string with the equipment name of the Signal Bank hardware module + char label[cbLEN_STR_LABEL]; ///< Label on the instrument for the signal bank, eg "Analog In" + uint32_t chanbase; ///< lowest channel number of channel id range claimed by this bank + uint32_t chancount; ///< number of channel identifiers claimed by this bank +} cbPKT_BANKINFO; + +/// @brief PKT Set:0xB0 Rep:0x30 - Sample Group (GROUP) Information Packets +/// +/// Contains information including the name and list of channels for each sample group. The cbPKT_GROUP packet transmits +/// the data for each group based on the list contained here. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< processor number + uint32_t group; ///< group number + char label[cbLEN_STR_LABEL]; ///< sampling group label + uint32_t period; ///< sampling period for the group + uint32_t length; ///< number of channels in the list + uint16_t list[cbNUM_ANALOG_CHANS]; ///< variable length list. The max size is the total number of analog channels +} cbPKT_GROUPINFO; + +/// @brief PKT Set:0xA3 Rep:0x23 - Filter Information Packet +/// +/// Describes the filters contained in the NSP including the filter coefficients +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< + uint32_t filt; ///< + char label[cbLEN_STR_FILT_LABEL]; // name of the filter + uint32_t hpfreq; ///< high-pass corner frequency in milliHertz + uint32_t hporder; ///< high-pass filter order + uint32_t hptype; ///< high-pass filter type + uint32_t lpfreq; ///< low-pass frequency in milliHertz + uint32_t lporder; ///< low-pass filter order + uint32_t lptype; ///< low-pass filter type + ///< These are for sending the NSP filter info, otherwise the NSP has this stuff in NSPDefaults.c + double gain; ///< filter gain + double sos1a1; ///< filter coefficient + double sos1a2; ///< filter coefficient + double sos1b1; ///< filter coefficient + double sos1b2; ///< filter coefficient + double sos2a1; ///< filter coefficient + double sos2a2; ///< filter coefficient + double sos2b1; ///< filter coefficient + double sos2b2; ///< filter coefficient +} cbPKT_FILTINFO; + +/// @brief PKT Set:0xA5 Rep:0x25 - Adaptive filtering +/// +/// This sets the parameters for the adaptive filtering. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< Ignored + + uint32_t nMode; ///< 0=disabled, 1=filter continuous & spikes, 2=filter spikes + float dLearningRate; ///< speed at which adaptation happens. Very small. e.g. 5e-12 + uint32_t nRefChan1; ///< The first reference channel (1 based). + uint32_t nRefChan2; ///< The second reference channel (1 based). + +} cbPKT_ADAPTFILTINFO; + +/// @brief PKT Set:0xA6 Rep:0x26 - Reference Electrode Information. +/// +/// This configures a channel to be referenced by another channel. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< Ignored + + uint32_t nMode; ///< 0=disabled, 1=filter continuous & spikes, 2=filter spikes + uint32_t nRefChan; ///< The reference channel (1 based). +} cbPKT_REFELECFILTINFO; + +/// @brief Filter description structure +/// +/// Filter description used in cbPKT_CHANINFO +typedef struct { + char label[cbLEN_STR_FILT_LABEL]; + uint32_t hpfreq; ///< high-pass corner frequency in milliHertz + uint32_t hporder; ///< high-pass filter order + uint32_t hptype; ///< high-pass filter type + uint32_t lpfreq; ///< low-pass frequency in milliHertz + uint32_t lporder; ///< low-pass filter order + uint32_t lptype; ///< low-pass filter type +} cbFILTDESC; + +/// @brief Scaling structure +/// +/// Structure used in cbPKT_CHANINFO +typedef struct { + int16_t digmin; ///< digital value that cooresponds with the anamin value + int16_t digmax; ///< digital value that cooresponds with the anamax value + int32_t anamin; ///< the minimum analog value present in the signal + int32_t anamax; ///< the maximum analog value present in the signal + int32_t anagain; ///< the gain applied to the default analog values to get the analog values + char anaunit[cbLEN_STR_UNIT]; ///< the unit for the analog signal (eg, "uV" or "MPa") +} cbSCALING; + +/// @brief Manual Unit Mapping structure +/// +/// Defines an ellipsoid for sorting. Used in cbPKT_CHANINFO and cbPKT_NTRODEINFO +typedef struct { + int16_t nOverride; ///< override to unit if in ellipsoid + int16_t afOrigin[3]; ///< ellipsoid origin + int16_t afShape[3][3]; ///< ellipsoid shape + int16_t aPhi; ///< + uint32_t bValid; ///< is this unit in use at this time? + ///< BOOL implemented as uint32_t - for structure alignment at paragraph boundary +} cbMANUALUNITMAPPING; + +/// @brief Hoop definition structure +/// +/// Defines the hoop used for sorting. There can be up to 5 hoops per unit. Used in cbPKT_CHANINFO +typedef struct { + uint16_t valid; ///< 0=undefined, 1 for valid + int16_t time; ///< time offset into spike window + int16_t min; ///< minimum value for the hoop window + int16_t max; ///< maximum value for the hoop window +} cbHOOP; + +/// @brief PKT Set:0xCx Rep:0x4x - Channel Information +/// +/// This contains the details for each channel within the system. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< actual channel id of the channel being configured + uint32_t proc; ///< the address of the processor on which the channel resides + uint32_t bank; ///< the address of the bank on which the channel resides + uint32_t term; ///< the terminal number of the channel within it's bank + uint32_t chancaps; ///< general channel capablities (given by cbCHAN_* flags) + uint32_t doutcaps; ///< digital output capablities (composed of cbDOUT_* flags) + uint32_t dinpcaps; ///< digital input capablities (composed of cbDINP_* flags) + uint32_t aoutcaps; ///< analog output capablities (composed of cbAOUT_* flags) + uint32_t ainpcaps; ///< analog input capablities (composed of cbAINP_* flags) + uint32_t spkcaps; ///< spike processing capabilities + cbSCALING physcalin; ///< physical channel scaling information + cbFILTDESC phyfiltin; ///< physical channel filter definition + cbSCALING physcalout; ///< physical channel scaling information + cbFILTDESC phyfiltout; ///< physical channel filter definition + char label[cbLEN_STR_LABEL]; ///< Label of the channel (null terminated if <16 characters) + uint32_t userflags; ///< User flags for the channel state + int32_t position[4]; ///< reserved for future position information + cbSCALING scalin; ///< user-defined scaling information for AINP + cbSCALING scalout; ///< user-defined scaling information for AOUT + uint32_t doutopts; ///< digital output options (composed of cbDOUT_* flags) + uint32_t dinpopts; ///< digital input options (composed of cbDINP_* flags) + uint32_t aoutopts; ///< analog output options + uint32_t eopchar; ///< digital input capablities (given by cbDINP_* flags) + union { + struct { // separate system channel to instrument specific channel number + uint16_t moninst; ///< instrument of channel to monitor + uint16_t monchan; ///< channel to monitor + int32_t outvalue; ///< output value + }; + struct { // used for digout timed output + uint16_t lowsamples; ///< number of samples to set low for timed output + uint16_t highsamples; ///< number of samples to set high for timed output + int32_t offset; ///< number of samples to offset the transitions for timed output + }; + }; + uint8_t trigtype; ///< trigger type (see cbDOUT_TRIGGER_*) + uint8_t reserved[2]; ///< 2 bytes reserved + uint8_t triginst; ///< instrument of the trigger channel + uint16_t trigchan; ///< trigger channel + uint16_t trigval; ///< trigger value + uint32_t ainpopts; ///< analog input options (composed of cbAINP* flags) + uint32_t lncrate; ///< line noise cancellation filter adaptation rate + uint32_t smpfilter; ///< continuous-time pathway filter id + uint32_t smpgroup; ///< continuous-time pathway sample group + int32_t smpdispmin; ///< continuous-time pathway display factor + int32_t smpdispmax; ///< continuous-time pathway display factor + uint32_t spkfilter; ///< spike pathway filter id + int32_t spkdispmax; ///< spike pathway display factor + int32_t lncdispmax; ///< Line Noise pathway display factor + uint32_t spkopts; ///< spike processing options + int32_t spkthrlevel; ///< spike threshold level + int32_t spkthrlimit; ///< + uint32_t spkgroup; ///< NTrodeGroup this electrode belongs to - 0 is single unit, non-0 indicates a multi-trode grouping + int16_t amplrejpos; ///< Amplitude rejection positive value + int16_t amplrejneg; ///< Amplitude rejection negative value + uint32_t refelecchan; ///< Software reference electrode channel + cbMANUALUNITMAPPING unitmapping[cbMAXUNITS]; ///< manual unit mapping + cbHOOP spkhoops[cbMAXUNITS][cbMAXHOOPS]; ///< spike hoop sorting set +} cbPKT_CHANINFO; + +/// @brief PKT Set:0xDB Rep:0x5B - Feature Space Basis +/// +/// This packet holds the calculated basis of the feature space from NSP to Central +/// Or it has the previous basis retrieved and transmitted by central to NSP +typedef struct +{ + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< 1-based channel number + uint32_t mode; ///< cbBASIS_CHANGE, cbUNDO_BASIS_CHANGE, cbREDO_BASIS_CHANGE, cbINVALIDATE_BASIS ... + uint32_t fs; ///< Feature space: cbAUTOALG_PCA + /// basis must be the last item in the structure because it can be variable length to a max of cbMAX_PNTS + float basis[cbMAX_PNTS][3]; ///< Room for all possible points collected +} cbPKT_FS_BASIS; + +/// @brief PKT Set:0xD1 Rep:0x51 - Get the spike sorting model for a single channel (Histogram Peak Count) +/// +/// The system replys with the model of a specific channel. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< actual channel id of the channel being configured (0 based) + uint32_t unit_number; ///< unit label (0 based, 0 is noise cluster) + uint32_t valid; ///< 1 = valid unit, 0 = not a unit, in other words just deleted when NSP -> PC + uint32_t inverted; ///< 0 = not inverted, 1 = inverted + + // Block statistics (change from block to block) + int32_t num_samples; ///< non-zero value means that the block stats are valid + float mu_x[2]; + float Sigma_x[2][2]; + float determinant_Sigma_x; + ///// Only needed if we are using a Bayesian classification model + float Sigma_x_inv[2][2]; + float log_determinant_Sigma_x; + ///// + float subcluster_spread_factor_numerator; + float subcluster_spread_factor_denominator; + float mu_e; + float sigma_e_squared; +} cbPKT_SS_MODELSET; + +/// @brief PKT Set:0xD2 Rep:0x52 - Auto threshold parameters +/// +/// Set the auto threshold parameters +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + float fThreshold; ///< current detection threshold + float fMultiplier; ///< multiplier +} cbPKT_SS_DETECT; + +/// @brief PKT Set:0xD3 Rep:0x53 - Artifact reject +/// +/// Sets the artifact rejection parameters. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t nMaxSimulChans; ///< how many channels can fire exactly at the same time??? + uint32_t nRefractoryCount; ///< for how many samples (30 kHz) is a neuron refractory, so can't re-trigger +} cbPKT_SS_ARTIF_REJECT; + +/// @brief PKT Set:0xD4 Rep:0x54 - Noise boundary +/// +/// Sets the noise boundary parameters +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< which channel we belong to + float afc[3]; ///< the center of the ellipsoid + float afS[3][3]; ///< an array of the axes for the ellipsoid +} cbPKT_SS_NOISE_BOUNDARY; + +/// @brief PKT Set:0xD5 Rep:0x55 - Spike sourting statistics (Histogram peak count) +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t nUpdateSpikes; ///< update rate in spike counts + + uint32_t nAutoalg; ///< sorting algorithm (0=none 1=spread, 2=hist_corr_maj, 3=hist_peak_count_maj, 4=hist_peak_count_maj_fisher, 5=pca, 6=hoops) + uint32_t nMode; ///< cbAUTOALG_MODE_SETTING, + + float fMinClusterPairSpreadFactor; ///< larger number = more apt to combine 2 clusters into 1 + float fMaxSubclusterSpreadFactor; ///< larger number = less apt to split because of 2 clusers + + float fMinClusterHistCorrMajMeasure; ///< larger number = more apt to split 1 cluster into 2 + float fMaxClusterPairHistCorrMajMeasure; ///< larger number = less apt to combine 2 clusters into 1 + + float fClusterHistValleyPercentage; ///< larger number = less apt to split nearby clusters + float fClusterHistClosePeakPercentage; ///< larger number = less apt to split nearby clusters + float fClusterHistMinPeakPercentage; ///< larger number = less apt to split separated clusters + + uint32_t nWaveBasisSize; ///< number of wave to collect to calculate the basis, + ///< must be greater than spike length + uint32_t nWaveSampleSize; ///< number of samples sorted with the same basis before re-calculating the basis + ///< 0=manual re-calculation + ///< nWaveBasisSize * nWaveSampleSize is the number of waves/spikes to run against + ///< the same PCA basis before next +} cbPKT_SS_STATISTICS; + +/// @brief Adaptive Control structure +typedef struct { + uint32_t nMode; ///< 0-do not adapt at all, 1-always adapt, 2-adapt if timer not timed out + float fTimeOutMinutes; ///< how many minutes until time out + float fElapsedMinutes; ///< the amount of time that has elapsed +} cbAdaptControl; + +/// @brief PKT Set:0xD7 Rep:0x57 - Spike sorting status (Histogram peak count) +/// +/// This packet contains the status of the automatic spike sorting. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + cbAdaptControl cntlUnitStats; ///< + cbAdaptControl cntlNumUnits; ///< +} cbPKT_SS_STATUS; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Central's actual binary layout (CentralLegacyCFGBUFF) +/// @brief Spike sorting configuration +/// +/// Groups all spike-sorting related configuration packets together. +typedef struct { + cbPKT_FS_BASIS asBasis[cbMAXCHANS]; ///< PCA basis values per channel + cbPKT_SS_MODELSET asSortModel[cbMAXCHANS][cbMAXUNITS + 2]; ///< Sorting models/rules per channel + + //////// These are spike sorting options + cbPKT_SS_DETECT pktDetect; ///< Detection parameters + cbPKT_SS_ARTIF_REJECT pktArtifReject; ///< Artifact rejection parameters + cbPKT_SS_NOISE_BOUNDARY pktNoiseBoundary[cbMAXCHANS]; ///< Noise boundaries per channel + cbPKT_SS_STATISTICS pktStatistics; ///< Spike statistics + cbPKT_SS_STATUS pktStatus; ///< Spike sorting status +} cbSPIKE_SORTING; + +/// @brief PKT Set:0xA7 Rep:0x27 - N-Trode information packets +/// +/// Sets information about an N-Trode. The user can change the name, number of sites, sites (channels) +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t ntrode; ///< ntrode with which we are working (1-based) + char label[cbLEN_STR_LABEL]; ///< Label of the Ntrode (null terminated if < 16 characters) + cbMANUALUNITMAPPING ellipses[cbMAXSITEPLOTS][cbMAXUNITS]; ///< unit mapping + uint16_t nSite; ///< number channels in this NTrode ( 0 <= nSite <= cbMAXSITES) + uint16_t fs; ///< NTrode feature space cbNTRODEINFO_FS_* + uint16_t nChan[cbMAXSITES]; ///< group of channels in this NTrode +} cbPKT_NTRODEINFO; + +constexpr uint32_t cbMAX_WAVEFORM_PHASES = ((cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - 24) / 4); ///< Maximum number of phases in a waveform + +/// @brief Analog output waveform data /// -/// VER: 4.2+ (CURRENT) +/// Contains the parameters to define a waveform for Analog Output channels +typedef struct +{ + int16_t offset; ///< DC offset + union { + struct { + uint16_t sineFrequency; ///< sine wave Hz + int16_t sineAmplitude; ///< sine amplitude + }; + struct { + uint16_t seq; ///< Wave sequence number (for file playback) + uint16_t seqTotal; ///< total number of sequences + uint16_t phases; ///< Number of valid phases in this wave (maximum is cbMAX_WAVEFORM_PHASES) + uint16_t duration[cbMAX_WAVEFORM_PHASES]; ///< array of durations for each phase + int16_t amplitude[cbMAX_WAVEFORM_PHASES]; ///< array of amplitude for each phase + }; + }; +} cbWaveformData; + +/// @brief PKT Set:0xB3 Rep:0x33 - AOUT waveform +/// +/// This sets a user defined waveform for one or multiple Analog & Audio Output channels. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint16_t chan; ///< which analog output/audio output channel (1-based, will equal chan from GetDoutCaps) + + /// Each file may contain multiple sequences. + /// Each sequence consists of phases + /// Each phase is defined by amplitude and duration + + /// Waveform parameter information + uint16_t mode; ///< Can be any of cbWAVEFORM_MODE_* + uint32_t repeats; ///< Number of repeats (0 means forever) + uint8_t trig; ///< Can be any of cbWAVEFORM_TRIGGER_* + uint8_t trigInst; ///< Instrument the trigChan belongs + uint16_t trigChan; ///< Depends on trig: + /// for cbWAVEFORM_TRIGGER_DINP* 1-based trigChan (1-16) is digin1, (17-32) is digin2, ... + /// for cbWAVEFORM_TRIGGER_SPIKEUNIT 1-based trigChan (1-156) is channel number + /// for cbWAVEFORM_TRIGGER_COMMENTCOLOR trigChan is A->B in A->B->G->R + uint16_t trigValue; ///< Trigger value (spike unit, G-R comment color, ...) + uint8_t trigNum; ///< trigger number (0-based) (can be up to cbMAX_AOUT_TRIGGER-1) + uint8_t active; ///< status of trigger + cbWaveformData wave; ///< Actual waveform data +} cbPKT_AOUT_WAVEFORM; + +/// @brief PKT Set:0xA8 Rep:0x28 - Line Noise Cancellation +/// +/// This packet holds the Line Noise Cancellation parameters +typedef struct +{ + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t lncFreq; ///< Nominal line noise frequency to be canceled (in Hz) + uint32_t lncRefChan; ///< Reference channel for lnc synch (1-based) + uint32_t lncGlobalMode; ///< reserved +} cbPKT_LNC; + +constexpr uint32_t cbNPLAY_FNAME_LEN = (cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - 40); ///< length of the file name (with terminating null) + +/// @brief PKT Set:0xDC Rep:0x5C - nPlay configuration packet +/// +/// Sent on restart together with config packet +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + union { + PROCTIME ftime; ///< the total time of the file. + PROCTIME opt; ///< optional value + }; + PROCTIME stime; ///< start time + PROCTIME etime; ///< stime < end time < ftime + PROCTIME val; ///< Used for current time to traverse, file index, file version, ... + uint16_t mode; ///< cbNPLAY_MODE_* command to nPlay + uint16_t flags; ///< cbNPLAY_FLAG_* status of nPlay + float speed; ///< positive means fast forward, negative means rewind, 0 means go as fast as you can. + char fname[cbNPLAY_FNAME_LEN]; ///< This is a String with the file name. +} cbPKT_NPLAY; + +/// @brief NeuroMotive video source +typedef struct { + char name[cbLEN_STR_LABEL]; ///< filename of the video file + float fps; ///< nominal record fps +} cbVIDEOSOURCE; + +/// @brief Track object structure for NeuroMotive +typedef struct { + char name[cbLEN_STR_LABEL]; ///< name of the object + uint16_t type; ///< trackable type (cbTRACKOBJ_TYPE_*) + uint16_t pointCount; ///< maximum number of points +} cbTRACKOBJ; + +/// @brief PKT Set:0xE1 Rep:0x61 - File configuration packet +/// +/// File recording can be started or stopped externally using this packet. It also contains a timeout mechanism to notify +/// if file isn't still recording. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t options; ///< cbFILECFG_OPT_* + uint32_t duration; + uint32_t recording; ///< If cbFILECFG_OPT_NONE this option starts/stops recording remotely + uint32_t extctrl; ///< If cbFILECFG_OPT_REC this is split number (0 for non-TOC) + ///< If cbFILECFG_OPT_STOP this is error code (0 means no error) + + char username[cbLEN_STR_COMMENT]; ///< name of computer issuing the packet + union { + char filename[cbLEN_STR_COMMENT]; ///< filename to record to + char datetime[cbLEN_STR_COMMENT]; ///< + }; + char comment[cbLEN_STR_COMMENT]; ///< comment to include in the file +} cbPKT_FILECFG; + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Central's actual binary layout (CentralLegacyCFGBUFF) /// /// This struct matches Central's cbCFGBUFF field order EXACTLY (from cbhwlib.h). /// It is NOT the same as CereLink's cbConfigBuffer (which reorders fields and adds @@ -182,6 +730,24 @@ struct CentralTransmitBufferLocal { uint32_t buffer[cbXMT_LOCAL_BUFFLEN]; ///< Ring buffer for packet data }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Data packet - Spike waveform data +/// +/// Detected spikes are sent through this packet. The spike waveform may or may not be sent depending +/// on the dlen contained in the header. The waveform can be anywhere from 30 samples to 128 samples +/// based on user configuration. The default spike length is 48 samples. cbpkt_header.chid is the +/// channel number of the spike. cbpkt_header.type is the sorted unit number (0=unsorted, 255=noise). +typedef struct { + cbPKT_HEADER cbpkt_header; ///< in the header for this packet, the type is used as the unit number + + float fPattern[3]; ///< values of the pattern space (Normal uses only 2, PCA uses third) + int16_t nPeak; ///< highest datapoint of the waveform + int16_t nValley; ///< lowest datapoint of the waveform + + int16_t wave[cbMAX_PNTS]; ///< datapoints of each sample of the waveform. Room for all possible points collected + ///< wave must be the last item in the structure because it can be variable length to a max of cbMAX_PNTS +} cbPKT_SPK; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Spike cache buffer /// @@ -205,6 +771,16 @@ struct CentralSpikeBuffer { CentralSpikeCache cache[cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Instrument status flags (bit field) +/// +/// Used to track which instruments are active in shared memory +/// +enum class InstrumentStatus : uint32_t { + INACTIVE = 0x00000000, ///< Instrument slot is not in use + ACTIVE = 0x00000001, ///< Instrument is active and has data +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief PC Status buffer (flattened from cbPcStatus class) /// @@ -236,6 +812,18 @@ struct CentralAppWorkspace { uint32_t m_nBottom; }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Unit Selection +/// +/// Packet which says that these channels are now selected +typedef struct +{ + cbPKT_HEADER cbpkt_header; ///< packet header + + int32_t lastchan; ///< Which channel was clicked last. + uint16_t abyUnitSelections[(cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - sizeof(int32_t))]; ///< one for each channel, channels are 0 based here, shows units selected +} cbPKT_UNIT_SELECTION; + struct CentralPCStatus { // Public data cbPKT_UNIT_SELECTION isSelection[cbMAXPROCS]; ///< Unit selection per instrument From 3771bc0d4b55fdbf071835051ac2a0a741d304de Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Tue, 26 May 2026 13:08:24 -0600 Subject: [PATCH 10/62] Minor stylistic edits to central_types/ --- src/cbshm/include/cbshm/central_types/v3_11.h | 27 +++++++++---------- src/cbshm/include/cbshm/central_types/v4_0.h | 27 +++++++++---------- src/cbshm/include/cbshm/central_types/v4_1.h | 27 +++++++++---------- src/cbshm/include/cbshm/central_types/v4_2.h | 27 +++++++++---------- 4 files changed, 48 insertions(+), 60 deletions(-) diff --git a/src/cbshm/include/cbshm/central_types/v3_11.h b/src/cbshm/include/cbshm/central_types/v3_11.h index 61f92988..9bfb77cd 100644 --- a/src/cbshm/include/cbshm/central_types/v3_11.h +++ b/src/cbshm/include/cbshm/central_types/v3_11.h @@ -17,9 +17,6 @@ #include -// Include InstrumentId from protocol module -#include - // Ensure tight packing for shared memory structures #pragma pack(push, 1) @@ -281,6 +278,18 @@ typedef struct { uint32_t nRefChan; ///< The reference channel (1 based). } cbPKT_REFELECFILTINFO; +/// @brief Scaling structure +/// +/// Structure used in cbPKT_CHANINFO +typedef struct { + int16_t digmin; ///< digital value that cooresponds with the anamin value + int16_t digmax; ///< digital value that cooresponds with the anamax value + int32_t anamin; ///< the minimum analog value present in the signal + int32_t anamax; ///< the maximum analog value present in the signal + int32_t anagain; ///< the gain applied to the default analog values to get the analog values + char anaunit[cbLEN_STR_UNIT]; ///< the unit for the analog signal (eg, "uV" or "MPa") +} cbSCALING; + /// @brief Filter description structure /// /// Filter description used in cbPKT_CHANINFO @@ -294,18 +303,6 @@ typedef struct { uint32_t lptype; ///< low-pass filter type } cbFILTDESC; -/// @brief Scaling structure -/// -/// Structure used in cbPKT_CHANINFO -typedef struct { - int16_t digmin; ///< digital value that cooresponds with the anamin value - int16_t digmax; ///< digital value that cooresponds with the anamax value - int32_t anamin; ///< the minimum analog value present in the signal - int32_t anamax; ///< the maximum analog value present in the signal - int32_t anagain; ///< the gain applied to the default analog values to get the analog values - char anaunit[cbLEN_STR_UNIT]; ///< the unit for the analog signal (eg, "uV" or "MPa") -} cbSCALING; - /// @brief Manual Unit Mapping structure /// /// Defines an ellipsoid for sorting. Used in cbPKT_CHANINFO and cbPKT_NTRODEINFO diff --git a/src/cbshm/include/cbshm/central_types/v4_0.h b/src/cbshm/include/cbshm/central_types/v4_0.h index 0953cfbe..588f492a 100644 --- a/src/cbshm/include/cbshm/central_types/v4_0.h +++ b/src/cbshm/include/cbshm/central_types/v4_0.h @@ -17,9 +17,6 @@ #include -// Include InstrumentId from protocol module -#include - // Ensure tight packing for shared memory structures #pragma pack(push, 1) @@ -281,6 +278,18 @@ typedef struct { uint32_t nRefChan; ///< The reference channel (1 based). } cbPKT_REFELECFILTINFO; +/// @brief Scaling structure +/// +/// Structure used in cbPKT_CHANINFO +typedef struct { + int16_t digmin; ///< digital value that cooresponds with the anamin value + int16_t digmax; ///< digital value that cooresponds with the anamax value + int32_t anamin; ///< the minimum analog value present in the signal + int32_t anamax; ///< the maximum analog value present in the signal + int32_t anagain; ///< the gain applied to the default analog values to get the analog values + char anaunit[cbLEN_STR_UNIT]; ///< the unit for the analog signal (eg, "uV" or "MPa") +} cbSCALING; + /// @brief Filter description structure /// /// Filter description used in cbPKT_CHANINFO @@ -294,18 +303,6 @@ typedef struct { uint32_t lptype; ///< low-pass filter type } cbFILTDESC; -/// @brief Scaling structure -/// -/// Structure used in cbPKT_CHANINFO -typedef struct { - int16_t digmin; ///< digital value that cooresponds with the anamin value - int16_t digmax; ///< digital value that cooresponds with the anamax value - int32_t anamin; ///< the minimum analog value present in the signal - int32_t anamax; ///< the maximum analog value present in the signal - int32_t anagain; ///< the gain applied to the default analog values to get the analog values - char anaunit[cbLEN_STR_UNIT]; ///< the unit for the analog signal (eg, "uV" or "MPa") -} cbSCALING; - /// @brief Manual Unit Mapping structure /// /// Defines an ellipsoid for sorting. Used in cbPKT_CHANINFO and cbPKT_NTRODEINFO diff --git a/src/cbshm/include/cbshm/central_types/v4_1.h b/src/cbshm/include/cbshm/central_types/v4_1.h index 14d5d321..3d12436c 100644 --- a/src/cbshm/include/cbshm/central_types/v4_1.h +++ b/src/cbshm/include/cbshm/central_types/v4_1.h @@ -17,9 +17,6 @@ #include -// Include InstrumentId from protocol module -#include - // Ensure tight packing for shared memory structures #pragma pack(push, 1) @@ -281,6 +278,18 @@ typedef struct { uint32_t nRefChan; ///< The reference channel (1 based). } cbPKT_REFELECFILTINFO; +/// @brief Scaling structure +/// +/// Structure used in cbPKT_CHANINFO +typedef struct { + int16_t digmin; ///< digital value that cooresponds with the anamin value + int16_t digmax; ///< digital value that cooresponds with the anamax value + int32_t anamin; ///< the minimum analog value present in the signal + int32_t anamax; ///< the maximum analog value present in the signal + int32_t anagain; ///< the gain applied to the default analog values to get the analog values + char anaunit[cbLEN_STR_UNIT]; ///< the unit for the analog signal (eg, "uV" or "MPa") +} cbSCALING; + /// @brief Filter description structure /// /// Filter description used in cbPKT_CHANINFO @@ -294,18 +303,6 @@ typedef struct { uint32_t lptype; ///< low-pass filter type } cbFILTDESC; -/// @brief Scaling structure -/// -/// Structure used in cbPKT_CHANINFO -typedef struct { - int16_t digmin; ///< digital value that cooresponds with the anamin value - int16_t digmax; ///< digital value that cooresponds with the anamax value - int32_t anamin; ///< the minimum analog value present in the signal - int32_t anamax; ///< the maximum analog value present in the signal - int32_t anagain; ///< the gain applied to the default analog values to get the analog values - char anaunit[cbLEN_STR_UNIT]; ///< the unit for the analog signal (eg, "uV" or "MPa") -} cbSCALING; - /// @brief Manual Unit Mapping structure /// /// Defines an ellipsoid for sorting. Used in cbPKT_CHANINFO and cbPKT_NTRODEINFO diff --git a/src/cbshm/include/cbshm/central_types/v4_2.h b/src/cbshm/include/cbshm/central_types/v4_2.h index 8b314c92..1b1ca059 100644 --- a/src/cbshm/include/cbshm/central_types/v4_2.h +++ b/src/cbshm/include/cbshm/central_types/v4_2.h @@ -17,9 +17,6 @@ #include -// Include InstrumentId from protocol module -#include - // Ensure tight packing for shared memory structures #pragma pack(push, 1) @@ -281,6 +278,18 @@ typedef struct { uint32_t nRefChan; ///< The reference channel (1 based). } cbPKT_REFELECFILTINFO; +/// @brief Scaling structure +/// +/// Structure used in cbPKT_CHANINFO +typedef struct { + int16_t digmin; ///< digital value that cooresponds with the anamin value + int16_t digmax; ///< digital value that cooresponds with the anamax value + int32_t anamin; ///< the minimum analog value present in the signal + int32_t anamax; ///< the maximum analog value present in the signal + int32_t anagain; ///< the gain applied to the default analog values to get the analog values + char anaunit[cbLEN_STR_UNIT]; ///< the unit for the analog signal (eg, "uV" or "MPa") +} cbSCALING; + /// @brief Filter description structure /// /// Filter description used in cbPKT_CHANINFO @@ -294,18 +303,6 @@ typedef struct { uint32_t lptype; ///< low-pass filter type } cbFILTDESC; -/// @brief Scaling structure -/// -/// Structure used in cbPKT_CHANINFO -typedef struct { - int16_t digmin; ///< digital value that cooresponds with the anamin value - int16_t digmax; ///< digital value that cooresponds with the anamax value - int32_t anamin; ///< the minimum analog value present in the signal - int32_t anamax; ///< the maximum analog value present in the signal - int32_t anagain; ///< the gain applied to the default analog values to get the analog values - char anaunit[cbLEN_STR_UNIT]; ///< the unit for the analog signal (eg, "uV" or "MPa") -} cbSCALING; - /// @brief Manual Unit Mapping structure /// /// Defines an ellipsoid for sorting. Used in cbPKT_CHANINFO and cbPKT_NTRODEINFO From 0db8a86a13571a686c69bec123bf919a23de6796 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Tue, 26 May 2026 14:49:07 -0600 Subject: [PATCH 11/62] Add object translators for compatibility with Central Each translator file can be diffed with another to see translation differences between versions. Translations are two-way between legacy versions and the current protocol version. --- .../include/cbshm/central_types/translators.h | 280 ++++++ src/cbshm/src/central_translators/utils.h | 102 +++ src/cbshm/src/central_translators/v3_11.cpp | 812 +++++++++++++++++ src/cbshm/src/central_translators/v4_0.cpp | 814 +++++++++++++++++ src/cbshm/src/central_translators/v4_1.cpp | 818 ++++++++++++++++++ src/cbshm/src/central_translators/v4_2.cpp | 818 ++++++++++++++++++ 6 files changed, 3644 insertions(+) create mode 100644 src/cbshm/include/cbshm/central_types/translators.h create mode 100644 src/cbshm/src/central_translators/utils.h create mode 100644 src/cbshm/src/central_translators/v3_11.cpp create mode 100644 src/cbshm/src/central_translators/v4_0.cpp create mode 100644 src/cbshm/src/central_translators/v4_1.cpp create mode 100644 src/cbshm/src/central_translators/v4_2.cpp diff --git a/src/cbshm/include/cbshm/central_types/translators.h b/src/cbshm/include/cbshm/central_types/translators.h new file mode 100644 index 00000000..44cf3fb2 --- /dev/null +++ b/src/cbshm/include/cbshm/central_types/translators.h @@ -0,0 +1,280 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file translators.h +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Translators for Central-compatible shared memory access +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include + +#ifndef CBSHM_CENTRAL_TYPES_TRANSLATORS_H +#define CBSHM_CENTRAL_TYPES_TRANSLATORS_H + +namespace cbshm { + +namespace central_v4_2 { + +::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg); +::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg); +::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg); +::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg); +::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg); +::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg); +::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg); +::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg); +::cbSCALING fromLegacy(const cbSCALING& leg); +::cbFILTDESC fromLegacy(const cbFILTDESC& leg); +::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg); +::cbHOOP fromLegacy(const cbHOOP& leg); +::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg); +::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg); +::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg); +::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg); +::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg); +::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg); +::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg); +::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg); +::cbproto::SpikeSorting fromLegacy(const cbproto::SpikeSorting& leg); +::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg); +::cbWaveformData fromLegacy(const cbWaveformData& leg); +::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg); +::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg); +::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg); +::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg); +::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg); +::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg); + +cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur); +cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur); +cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur); +cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur); +cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur); +cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur); +cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur); +cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur); +cbSCALING toLegacy(const ::cbSCALING& cur); +cbFILTDESC toLegacy(const ::cbFILTDESC& cur); +cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur); +cbHOOP toLegacy(const ::cbHOOP& cur); +cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur); +cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur); +cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur); +cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur); +cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur); +cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur); +cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur); +cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur); +cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur); +cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur); +cbWaveformData toLegacy(const ::cbWaveformData& cur); +cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur); +cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur); +cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur); +cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur); +cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur); +cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur); + +} // namespace central_v4_2 + +namespace central_v4_1 { + +::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg); +::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg); +::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg); +::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg); +::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg); +::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg); +::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg); +::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg); +::cbSCALING fromLegacy(const cbSCALING& leg); +::cbFILTDESC fromLegacy(const cbFILTDESC& leg); +::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg); +::cbHOOP fromLegacy(const cbHOOP& leg); +::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg); +::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg); +::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg); +::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg); +::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg); +::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg); +::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg); +::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg); +::cbproto::SpikeSorting fromLegacy(const cbproto::SpikeSorting& leg); +::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg); +::cbWaveformData fromLegacy(const cbWaveformData& leg); +::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg); +::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg); +::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg); +::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg); +::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg); +::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg); + +cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur); +cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur); +cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur); +cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur); +cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur); +cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur); +cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur); +cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur); +cbSCALING toLegacy(const ::cbSCALING& cur); +cbFILTDESC toLegacy(const ::cbFILTDESC& cur); +cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur); +cbHOOP toLegacy(const ::cbHOOP& cur); +cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur); +cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur); +cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur); +cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur); +cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur); +cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur); +cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur); +cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur); +cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur); +cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur); +cbWaveformData toLegacy(const ::cbWaveformData& cur); +cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur); +cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur); +cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur); +cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur); +cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur); +cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur); + +} // namespace central_v4_1 + +namespace central_v4_0 { + +::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg); +::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg); +::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg); +::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg); +::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg); +::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg); +::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg); +::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg); +::cbSCALING fromLegacy(const cbSCALING& leg); +::cbFILTDESC fromLegacy(const cbFILTDESC& leg); +::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg); +::cbHOOP fromLegacy(const cbHOOP& leg); +::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg); +::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg); +::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg); +::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg); +::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg); +::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg); +::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg); +::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg); +::cbproto::SpikeSorting fromLegacy(const cbproto::SpikeSorting& leg); +::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg); +::cbWaveformData fromLegacy(const cbWaveformData& leg); +::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg); +::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg); +::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg); +::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg); +::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg); +::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg); + +cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur); +cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur); +cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur); +cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur); +cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur); +cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur); +cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur); +cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur); +cbSCALING toLegacy(const ::cbSCALING& cur); +cbFILTDESC toLegacy(const ::cbFILTDESC& cur); +cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur); +cbHOOP toLegacy(const ::cbHOOP& cur); +cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur); +cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur); +cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur); +cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur); +cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur); +cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur); +cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur); +cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur); +cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur); +cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur); +cbWaveformData toLegacy(const ::cbWaveformData& cur); +cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur); +cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur); +cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur); +cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur); +cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur); +cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur); + +} // namespace central_v4_0 + +namespace central_v3_11 { + +::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg); +::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg); +::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg); +::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg); +::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg); +::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg); +::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg); +::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg); +::cbSCALING fromLegacy(const cbSCALING& leg); +::cbFILTDESC fromLegacy(const cbFILTDESC& leg); +::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg); +::cbHOOP fromLegacy(const cbHOOP& leg); +::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg); +::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg); +::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg); +::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg); +::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg); +::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg); +::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg); +::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg); +::cbproto::SpikeSorting fromLegacy(const cbproto::SpikeSorting& leg); +::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg); +::cbWaveformData fromLegacy(const cbWaveformData& leg); +::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg); +::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg); +::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg); +::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg); +::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg); +::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg); + +cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur); +cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur); +cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur); +cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur); +cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur); +cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur); +cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur); +cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur); +cbSCALING toLegacy(const ::cbSCALING& cur); +cbFILTDESC toLegacy(const ::cbFILTDESC& cur); +cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur); +cbHOOP toLegacy(const ::cbHOOP& cur); +cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur); +cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur); +cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur); +cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur); +cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur); +cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur); +cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur); +cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur); +cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur); +cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur); +cbWaveformData toLegacy(const ::cbWaveformData& cur); +cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur); +cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur); +cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur); +cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur); +cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur); +cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur); + +} // namespace central_v3_11 + +} // namespace cbshm + +#endif // CBSHM_CENTRAL_TYPES_TRANSLATORS_H diff --git a/src/cbshm/src/central_translators/utils.h b/src/cbshm/src/central_translators/utils.h new file mode 100644 index 00000000..e1f8ae55 --- /dev/null +++ b/src/cbshm/src/central_translators/utils.h @@ -0,0 +1,102 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file utils.h +/// @author Caden Shmookler +/// @date 2025-05-22 +/// +/// @brief Common utilities for the Central-compatible object translators +/// +/// leg -> Legacy Version +/// cur -> Current Version +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include + +#ifndef CBSHM_CENTRAL_TRANSLATORS_UTILS_H +#define CBSHM_CENTRAL_TRANSLATORS_UTILS_H + +template +void copyArr(T(&lhs)[lhs_n], const T(&rhs)[rhs_n]) { + if (lhs_n <= rhs_n) { + // Either the current array has fewer elements than the legacy array, + // or they both have the same length. Either way, copy only as much + // as the current array has space for. + std::memcpy(lhs, rhs, lhs_n); + } else { + // Current array has more entries! Copy everything from the legacy + // array to the current array and zero out the remaining space. + std::memcpy(lhs, rhs, rhs_n); + std::memset(lhs + rhs_n, 0, lhs_n - rhs_n); + } +} + +template +void copyArr(LHS_T(&lhs)[lhs_n], const RHS_T(&rhs)[rhs_n], LHS_T(*translation_func)(const RHS_T&)) { + if (lhs_n <= rhs_n) { + // Either the current array has fewer elements than the legacy array, + // or they both have the same length. Either way, copy only as much + // as the current array has space for. + for (size_t i = 0; i < lhs_n; ++i) { + lhs[i] = translation_func(rhs[i]); + } + } else { + // Current array has more entries! Copy everything from the legacy + // array to the current array and zero out the remaining space. + for (size_t i = 0; i < rhs_n; ++i) { + lhs[i] = translation_func(rhs[i]); + } + std::memset(lhs + rhs_n, 0, lhs_n - rhs_n); + } +} + +template +void copyArr2D(T(&lhs)[lhs_ny][lhs_nx], const T(&rhs)[rhs_ny][rhs_nx]) { + if (lhs_ny <= rhs_ny) { + // Either the current array has fewer elements than the legacy array, + // or they both have the same length. Either way, copy only as much + // as the current array has space for. + if (lhs_nx == rhs_nx) { + std::memcpy(lhs, rhs, lhs_ny * lhs_nx); + } else { + for (size_t i = 0; i < lhs_ny; ++i) { + copyArr(lhs[i], rhs[i]); + } + } + } else { + // Current array has more entries! Copy everything from the legacy + // array to the current array and zero out the remaining space. + if (lhs_nx == rhs_nx) { + std::memcpy(lhs, rhs, rhs_ny * rhs_nx); + } else { + for (size_t i = 0; i < rhs_ny; ++i) { + copyArr(lhs[i], rhs[i]); + } + } + std::memset(lhs + (rhs_ny * rhs_nx), 0, (lhs_ny * lhs_nx) - (rhs_ny * rhs_nx)); + } +} + +template +void copyArr2D(LHS_T(&lhs)[lhs_ny][lhs_nx], const RHS_T(&rhs)[rhs_ny][rhs_nx], LHS_T(*translation_func)(const RHS_T&)) { + if (lhs_ny <= rhs_ny) { + // Either the current array has fewer elements than the legacy array, + // or they both have the same length. Either way, copy only as much + // as the current array has space for. + for (size_t i = 0; i < lhs_ny; ++i) { + for (size_t j = 0; j < lhs_nx; ++j) { + lhs[i][j] = translation_func(rhs[i][j]); + } + } + } else { + // Current array has more entries! Copy everything from the legacy + // array to the current array and zero out the remaining space. + for (size_t i = 0; i < rhs_ny; ++i) { + for (size_t j = 0; j < rhs_nx; ++j) { + lhs[i][j] = translation_func(rhs[i][j]); + } + } + std::memset(lhs + (rhs_ny * rhs_nx), 0, (lhs_ny * lhs_nx) - (rhs_ny * rhs_nx)); + } +} + +#endif // CBSHM_CENTRAL_TRANSLATORS_UTILS_H diff --git a/src/cbshm/src/central_translators/v3_11.cpp b/src/cbshm/src/central_translators/v3_11.cpp new file mode 100644 index 00000000..9c0751b8 --- /dev/null +++ b/src/cbshm/src/central_translators/v3_11.cpp @@ -0,0 +1,812 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v3_11.cpp +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Central translator implementations +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "utils.h" +#include +#include + +namespace cbshm { + +namespace central_v3_11 { + +::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) { + ::cbPKT_HEADER cur{}; + cur.time = leg.time; // TODO: explicit or implicit conversion here (?) (and for all PROCTIME) + cur.chid = leg.chid; + cur.type = static_cast(leg.type); + cur.dlen = static_cast(leg.dlen); + cur.instrument = 0; // TODO: VERIFY + cur.reserved = 0; + return cur; +} + +::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) { + ::cbPKT_SYSINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.sysfreq = leg.sysfreq; + cur.spikelen = leg.spikelen; + cur.spikepre = leg.spikepre; + cur.resetque = leg.resetque; + cur.runlevel = leg.runlevel; + cur.runflags = leg.runflags; + return cur; +} + +::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) { + ::cbPKT_PROCINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.idcode = leg.idcode; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; + cur.bankcount = leg.bankcount; + cur.groupcount = leg.groupcount; + cur.filtcount = leg.filtcount; + cur.sortcount = leg.sortcount; + cur.unitcount = leg.unitcount; + cur.hoopcount = leg.hoopcount; + cur.reserved = leg.sortmethod; + cur.version = leg.version; + return cur; +} + +::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) { + ::cbPKT_BANKINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + copyArr(cur.label, leg.label); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; + return cur; +} + +::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) { + ::cbPKT_GROUPINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.group = leg.group; + copyArr(cur.label, leg.label); + cur.period = leg.period; + cur.length = leg.length; + copyArr(cur.list, leg.list); + return cur; +} + +::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) { + ::cbPKT_FILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.filt = leg.filt; + copyArr(cur.label, leg.label); + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; + cur.gain = leg.gain; + cur.sos1a1 = leg.sos1a1; + cur.sos1a2 = leg.sos1a2; + cur.sos1b1 = leg.sos1b1; + cur.sos1b2 = leg.sos1b2; + cur.sos2a1 = leg.sos2a1; + cur.sos2a2 = leg.sos2a2; + cur.sos2b1 = leg.sos2b1; + cur.sos2b2 = leg.sos2b2; + return cur; +} + +::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) { + ::cbPKT_ADAPTFILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.dLearningRate = leg.dLearningRate; + cur.nRefChan1 = leg.nRefChan1; + cur.nRefChan2 = leg.nRefChan2; + return cur; +} + +::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg) { + ::cbPKT_REFELECFILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.nRefChan = leg.nRefChan; + return cur; +} + +::cbSCALING fromLegacy(const cbSCALING& leg) { + ::cbSCALING cur{}; + cur.digmin = leg.digmin; + cur.digmax = leg.digmax; + cur.anamin = leg.anamin; + cur.anamax = leg.anamax; + cur.anagain = leg.anagain; + copyArr(cur.anaunit, leg.anaunit); + return cur; +} + +::cbFILTDESC fromLegacy(const cbFILTDESC& leg) { + ::cbFILTDESC cur{}; + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; + return cur; +} + +::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) { + ::cbMANUALUNITMAPPING cur{}; + cur.nOverride = leg.nOverride; + copyArr(cur.afOrigin, leg.afOrigin); + copyArr2D(cur.afShape, leg.afShape); + cur.aPhi = leg.aPhi; + cur.bValid = leg.bValid; + return cur; +} + +::cbHOOP fromLegacy(const cbHOOP& leg) { + ::cbHOOP cur{}; + cur.valid = leg.valid; + cur.time = leg.time; + cur.min = leg.min; + cur.max = leg.max; + return cur; +} + +::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) { + ::cbPKT_CHANINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.term = leg.term; + cur.chancaps = leg.chancaps; + cur.doutcaps = leg.doutcaps; + cur.dinpcaps = leg.dinpcaps; + cur.aoutcaps = leg.aoutcaps; + cur.ainpcaps = leg.ainpcaps; + cur.spkcaps = leg.spkcaps; + cur.physcalin = fromLegacy(leg.physcalin); + cur.phyfiltin = fromLegacy(leg.phyfiltin); + cur.physcalout = fromLegacy(leg.physcalout); + cur.phyfiltout = fromLegacy(leg.phyfiltout); + copyArr(cur.label, leg.label); + cur.userflags = leg.userflags; + copyArr(cur.position, leg.position); + cur.scalin = fromLegacy(leg.scalin); + cur.scalout = fromLegacy(leg.scalout); + cur.doutopts = leg.doutopts; + cur.dinpopts = leg.dinpopts; + cur.aoutopts = leg.aoutopts; + cur.eopchar = leg.eopchar; + cur.moninst = static_cast((leg.monsource >> 16) & 0xFFFF); // aka lowsamples + cur.monchan = static_cast(leg.monsource & 0xFFFF); // aka highsamples + cur.outvalue = leg.outvalue; // aka offset + cur.trigtype = leg.trigtype; + // skip reserved + cur.triginst = 0; // TODO: VERIFY + cur.trigchan = leg.trigchan; + cur.trigval = leg.trigval; + cur.ainpopts = leg.ainpopts; + cur.lncrate = leg.lncrate; + cur.smpfilter = leg.smpfilter; + cur.smpgroup = leg.smpgroup; + cur.smpdispmin = leg.smpdispmin; + cur.smpdispmax = leg.smpdispmax; + cur.spkfilter = leg.spkfilter; + cur.spkdispmax = leg.spkdispmax; + cur.lncdispmax = leg.lncdispmax; + cur.spkopts = leg.spkopts; + cur.spkthrlevel = leg.spkthrlevel; + cur.spkthrlimit = leg.spkthrlimit; + cur.spkgroup = leg.spkgroup; + cur.amplrejpos = leg.amplrejpos; + cur.amplrejneg = leg.amplrejneg; + cur.refelecchan = leg.refelecchan; + copyArr(cur.unitmapping, leg.unitmapping, fromLegacy); + copyArr2D(cur.spkhoops, leg.spkhoops, fromLegacy); + return cur; +} + +::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) { + ::cbPKT_FS_BASIS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.fs = leg.fs; + copyArr2D(cur.basis, leg.basis); + return cur; +} + +::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) { + ::cbPKT_SS_MODELSET cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.unit_number = leg.unit_number; + cur.valid = leg.valid; + cur.inverted = leg.inverted; + cur.num_samples = leg.num_samples; + copyArr(cur.mu_x, leg.mu_x); + copyArr2D(cur.Sigma_x, leg.Sigma_x); + cur.determinant_Sigma_x = leg.determinant_Sigma_x; + copyArr2D(cur.Sigma_x_inv, leg.Sigma_x_inv); + cur.log_determinant_Sigma_x = leg.log_determinant_Sigma_x; + cur.subcluster_spread_factor_numerator = leg.subcluster_spread_factor_numerator; + cur.subcluster_spread_factor_denominator = leg.subcluster_spread_factor_denominator; + cur.mu_e = leg.mu_e; + cur.sigma_e_squared = leg.sigma_e_squared; + return cur; +} + +::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg) { + ::cbPKT_SS_DETECT cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.fThreshold = leg.fThreshold; + cur.fMultiplier = leg.fMultiplier; + return cur; +} + +::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) { + ::cbPKT_SS_ARTIF_REJECT cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.nMaxSimulChans = leg.nMaxSimulChans; + cur.nRefractoryCount = leg.nRefractoryCount; + return cur; +} + +::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) { + ::cbPKT_SS_NOISE_BOUNDARY cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + copyArr(cur.afc, leg.afc); + copyArr2D(cur.afS, leg.afS); + return cur; +} + +::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) { + ::cbPKT_SS_STATISTICS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.nUpdateSpikes = leg.nUpdateSpikes; + cur.nAutoalg = leg.nAutoalg; + cur.nMode = leg.nMode; + cur.fMinClusterPairSpreadFactor = leg.fMinClusterPairSpreadFactor; + cur.fMaxSubclusterSpreadFactor = leg.fMaxSubclusterSpreadFactor; + cur.fMinClusterHistCorrMajMeasure = leg.fMinClusterHistCorrMajMeasure; + cur.fMaxClusterPairHistCorrMajMeasure = leg.fMaxClusterPairHistCorrMajMeasure; + cur.fClusterHistValleyPercentage = leg.fClusterHistValleyPercentage; + cur.fClusterHistClosePeakPercentage = leg.fClusterHistClosePeakPercentage; + cur.fClusterHistMinPeakPercentage = leg.fClusterHistMinPeakPercentage; + cur.nWaveBasisSize = leg.nWaveBasisSize; + cur.nWaveSampleSize = leg.nWaveSampleSize; + return cur; +} + +::cbAdaptControl fromLegacy(const cbAdaptControl& leg) { + ::cbAdaptControl cur{}; + cur.nMode = leg.nMode; + cur.fTimeOutMinutes = leg.fTimeOutMinutes; + cur.fElapsedMinutes = leg.fElapsedMinutes; + return cur; +} + +::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg) { + ::cbPKT_SS_STATUS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats); + cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits); + return cur; +} + +::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg) { + ::cbproto::SpikeSorting cur{}; + copyArr(cur.basis, leg.asBasis, fromLegacy); + copyArr2D(cur.models, leg.asSortModel, fromLegacy); + cur.detect = fromLegacy(leg.pktDetect); + cur.artifact_reject = fromLegacy(leg.pktArtifReject); + copyArr(cur.noise_boundary, leg.pktNoiseBoundary, fromLegacy); + cur.statistics = fromLegacy(leg.pktStatistics); + cur.status = fromLegacy(leg.pktStatus); + return cur; +} + +::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg) { + ::cbPKT_NTRODEINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.ntrode = leg.ntrode; + copyArr(cur.label, leg.label); + copyArr2D(cur.ellipses, leg.ellipses, fromLegacy); + cur.nSite = leg.nSite; + cur.fs = leg.fs; + copyArr(cur.nChan, leg.nChan); + return cur; +} + +::cbWaveformData fromLegacy(const cbWaveformData& leg) { + ::cbWaveformData cur{}; + cur.offset = leg.offset; // aka sineFrequency + cur.seq = leg.seq; // aka sineAmplitude + cur.seqTotal = leg.seqTotal; + cur.phases = leg.phases; + copyArr(cur.duration, leg.duration); + copyArr(cur.amplitude, leg.amplitude); + return cur; +} + +::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) { + ::cbPKT_AOUT_WAVEFORM cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.repeats = leg.repeats; + cur.trig = static_cast((leg.trig >> 8) & 0xFF); + cur.trigInst = static_cast(leg.trig & 0xFF); + cur.trigChan = leg.trigChan; + cur.trigValue = leg.trigValue; + cur.trigNum = leg.trigNum; + cur.active = leg.active; + cur.wave = fromLegacy(leg.wave); + return cur; +} + +::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg) { + ::cbPKT_LNC cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.lncFreq = leg.lncFreq; + cur.lncRefChan = leg.lncRefChan; + cur.lncGlobalMode = leg.lncGlobalMode; + return cur; +} + +::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) { + ::cbPKT_NPLAY cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.ftime = leg.ftime; // aka opt + cur.stime = leg.stime; + cur.etime = leg.etime; + cur.val = leg.val; + cur.mode = leg.mode; + cur.flags = leg.flags; + cur.speed = leg.speed; + copyArr(cur.fname, leg.fname); + return cur; +} + +::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg) { + ::cbVIDEOSOURCE cur{}; + copyArr(cur.name, leg.name); + cur.fps = leg.fps; + return cur; +} + +::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) { + ::cbTRACKOBJ cur{}; + copyArr(cur.name, leg.name); + cur.type = leg.type; + cur.pointCount = leg.pointCount; + return cur; +} + +::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) { + ::cbPKT_FILECFG cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.options = leg.options; + cur.duration = leg.duration; + cur.recording = leg.recording; + cur.extctrl = leg.extctrl; + copyArr(cur.username, leg.username); + copyArr(cur.filename, leg.filename); // aka datetime + copyArr(cur.comment, leg.comment); + return cur; +} + +cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) { + cbPKT_HEADER leg{}; + leg.time = cur.time; + leg.chid = cur.chid; + leg.type = static_cast(cur.type); + leg.dlen = static_cast(cur.dlen); + return leg; +} + +cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) { + cbPKT_SYSINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.sysfreq = cur.sysfreq; + leg.spikelen = cur.spikelen; + leg.spikepre = cur.spikepre; + leg.resetque = cur.resetque; + leg.runlevel = cur.runlevel; + leg.runflags = cur.runflags; + return leg; +} + +cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) { + cbPKT_PROCINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.idcode = cur.idcode; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; + leg.bankcount = cur.bankcount; + leg.groupcount = cur.groupcount; + leg.filtcount = cur.filtcount; + leg.sortcount = cur.sortcount; + leg.unitcount = cur.unitcount; + leg.hoopcount = cur.hoopcount; + leg.sortmethod = cur.reserved; + leg.version = cur.version; + return leg; +} + +cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) { + cbPKT_BANKINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + copyArr(leg.label, cur.label); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; + return leg; +} + +cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) { + cbPKT_GROUPINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.group = cur.group; + copyArr(leg.label, cur.label); + leg.period = cur.period; + leg.length = cur.length; + copyArr(leg.list, cur.list); + return leg; +} + +cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) { + cbPKT_FILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.filt = cur.filt; + copyArr(leg.label, cur.label); + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; + leg.gain = cur.gain; + leg.sos1a1 = cur.sos1a1; + leg.sos1a2 = cur.sos1a2; + leg.sos1b1 = cur.sos1b1; + leg.sos1b2 = cur.sos1b2; + leg.sos2a1 = cur.sos2a1; + leg.sos2a2 = cur.sos2a2; + leg.sos2b1 = cur.sos2b1; + leg.sos2b2 = cur.sos2b2; + return leg; +} + +cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) { + cbPKT_ADAPTFILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.dLearningRate = cur.dLearningRate; + leg.nRefChan1 = cur.nRefChan1; + leg.nRefChan2 = cur.nRefChan2; + return leg; +} + +cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur) { + cbPKT_REFELECFILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.nRefChan = cur.nRefChan; + return leg; +} + +cbSCALING toLegacy(const ::cbSCALING& cur) { + cbSCALING leg{}; + leg.digmin = cur.digmin; + leg.digmax = cur.digmax; + leg.anamin = cur.anamin; + leg.anamax = cur.anamax; + leg.anagain = cur.anagain; + copyArr(leg.anaunit, cur.anaunit); + return leg; +} + +cbFILTDESC toLegacy(const ::cbFILTDESC& cur) { + cbFILTDESC leg{}; + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; + return leg; +} + +cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) { + cbMANUALUNITMAPPING leg{}; + leg.nOverride = cur.nOverride; + copyArr(leg.afOrigin, cur.afOrigin); + copyArr2D(leg.afShape, cur.afShape); + leg.aPhi = cur.aPhi; + leg.bValid = cur.bValid; + return leg; +} + +cbHOOP toLegacy(const ::cbHOOP& cur) { + cbHOOP leg{}; + leg.valid = cur.valid; + leg.time = cur.time; + leg.min = cur.min; + leg.max = cur.max; + return leg; +} + +cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) { + cbPKT_CHANINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.term = cur.term; + leg.chancaps = cur.chancaps; + leg.doutcaps = cur.doutcaps; + leg.dinpcaps = cur.dinpcaps; + leg.aoutcaps = cur.aoutcaps; + leg.ainpcaps = cur.ainpcaps; + leg.spkcaps = cur.spkcaps; + leg.physcalin = toLegacy(cur.physcalin); + leg.phyfiltin = toLegacy(cur.phyfiltin); + leg.physcalout = toLegacy(cur.physcalout); + leg.phyfiltout = toLegacy(cur.phyfiltout); + copyArr(leg.label, cur.label); + leg.userflags = cur.userflags; + copyArr(leg.position, cur.position); + leg.scalin = toLegacy(cur.scalin); + leg.scalout = toLegacy(cur.scalout); + leg.doutopts = cur.doutopts; + leg.dinpopts = cur.dinpopts; + leg.aoutopts = cur.aoutopts; + leg.eopchar = cur.eopchar; + leg.monsource = (static_cast(cur.moninst) << 16) | static_cast(cur.monchan); // aka highsamples and lowsamples + leg.outvalue = cur.outvalue; // aka offset + leg.trigtype = cur.trigtype; + leg.trigchan = cur.trigchan; + leg.trigval = cur.trigval; + leg.ainpopts = cur.ainpopts; + leg.lncrate = cur.lncrate; + leg.smpfilter = cur.smpfilter; + leg.smpgroup = cur.smpgroup; + leg.smpdispmin = cur.smpdispmin; + leg.smpdispmax = cur.smpdispmax; + leg.spkfilter = cur.spkfilter; + leg.spkdispmax = cur.spkdispmax; + leg.lncdispmax = cur.lncdispmax; + leg.spkopts = cur.spkopts; + leg.spkthrlevel = cur.spkthrlevel; + leg.spkthrlimit = cur.spkthrlimit; + leg.spkgroup = cur.spkgroup; + leg.amplrejpos = cur.amplrejpos; + leg.amplrejneg = cur.amplrejneg; + leg.refelecchan = cur.refelecchan; + copyArr(leg.unitmapping, cur.unitmapping, toLegacy); + copyArr2D(leg.spkhoops, cur.spkhoops, toLegacy); + return leg; +} + +cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) { + cbPKT_FS_BASIS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.fs = cur.fs; + copyArr2D(leg.basis, cur.basis); + return leg; +} + +cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) { + cbPKT_SS_MODELSET leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.unit_number = cur.unit_number; + leg.valid = cur.valid; + leg.inverted = cur.inverted; + leg.num_samples = cur.num_samples; + copyArr(leg.mu_x, cur.mu_x); + copyArr2D(leg.Sigma_x, cur.Sigma_x); + leg.determinant_Sigma_x = cur.determinant_Sigma_x; + copyArr2D(leg.Sigma_x_inv, cur.Sigma_x_inv); + leg.log_determinant_Sigma_x = cur.log_determinant_Sigma_x; + leg.subcluster_spread_factor_numerator = cur.subcluster_spread_factor_numerator; + leg.subcluster_spread_factor_denominator = cur.subcluster_spread_factor_denominator; + leg.mu_e = cur.mu_e; + leg.sigma_e_squared = cur.sigma_e_squared; + return leg; +} + +cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur) { + cbPKT_SS_DETECT leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.fThreshold = cur.fThreshold; + leg.fMultiplier = cur.fMultiplier; + return leg; +} + +cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) { + cbPKT_SS_ARTIF_REJECT leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.nMaxSimulChans = cur.nMaxSimulChans; + leg.nRefractoryCount = cur.nRefractoryCount; + return leg; +} + +cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) { + cbPKT_SS_NOISE_BOUNDARY leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + copyArr(leg.afc, cur.afc); + copyArr2D(leg.afS, cur.afS); + return leg; +} + +cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) { + cbPKT_SS_STATISTICS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.nUpdateSpikes = cur.nUpdateSpikes; + leg.nAutoalg = cur.nAutoalg; + leg.nMode = cur.nMode; + leg.fMinClusterPairSpreadFactor = cur.fMinClusterPairSpreadFactor; + leg.fMaxSubclusterSpreadFactor = cur.fMaxSubclusterSpreadFactor; + leg.fMinClusterHistCorrMajMeasure = cur.fMinClusterHistCorrMajMeasure; + leg.fMaxClusterPairHistCorrMajMeasure = cur.fMaxClusterPairHistCorrMajMeasure; + leg.fClusterHistValleyPercentage = cur.fClusterHistValleyPercentage; + leg.fClusterHistClosePeakPercentage = cur.fClusterHistClosePeakPercentage; + leg.fClusterHistMinPeakPercentage = cur.fClusterHistMinPeakPercentage; + leg.nWaveBasisSize = cur.nWaveBasisSize; + leg.nWaveSampleSize = cur.nWaveSampleSize; + return leg; +} + +cbAdaptControl toLegacy(const ::cbAdaptControl& cur) { + cbAdaptControl leg{}; + leg.nMode = cur.nMode; + leg.fTimeOutMinutes = cur.fTimeOutMinutes; + leg.fElapsedMinutes = cur.fElapsedMinutes; + return leg; +} + +cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur) { + cbPKT_SS_STATUS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cntlUnitStats = toLegacy(cur.cntlUnitStats); + leg.cntlNumUnits = toLegacy(cur.cntlNumUnits); + return leg; +} + +cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur) { + cbSPIKE_SORTING leg{}; + copyArr(leg.asBasis, cur.basis, toLegacy); + copyArr2D(leg.asSortModel, cur.models, toLegacy); + leg.pktDetect = toLegacy(cur.detect); + leg.pktArtifReject = toLegacy(cur.artifact_reject); + copyArr(leg.pktNoiseBoundary, cur.noise_boundary, toLegacy); + leg.pktStatistics = toLegacy(cur.statistics); + leg.pktStatus = toLegacy(cur.status); + return leg; +} + +cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur) { + cbPKT_NTRODEINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.ntrode = cur.ntrode; + copyArr(leg.label, cur.label); + copyArr2D(leg.ellipses, cur.ellipses, toLegacy); + leg.nSite = cur.nSite; + leg.fs = cur.fs; + copyArr(leg.nChan, cur.nChan); + return leg; +} + +cbWaveformData toLegacy(const ::cbWaveformData& cur) { + cbWaveformData leg{}; + leg.offset = cur.offset; // aka sineFrequency + leg.seq = cur.seq; // aka sineAmplitude + leg.seqTotal = cur.seqTotal; + leg.phases = cur.phases; + copyArr(leg.duration, cur.duration); + copyArr(leg.amplitude, cur.amplitude); + return leg; +} + +cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) { + cbPKT_AOUT_WAVEFORM leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.repeats = cur.repeats; + leg.trig = (static_cast(cur.trig) << 8) | static_cast(cur.trigInst); + leg.trigChan = cur.trigChan; + leg.trigValue = cur.trigValue; + leg.trigNum = cur.trigNum; + leg.active = cur.active; + leg.wave = toLegacy(cur.wave); + return leg; +} + +cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur) { + cbPKT_LNC leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.lncFreq = cur.lncFreq; + leg.lncRefChan = cur.lncRefChan; + leg.lncGlobalMode = cur.lncGlobalMode; + return leg; +} + +cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) { + cbPKT_NPLAY leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.ftime = cur.ftime; // aka opt + leg.stime = cur.stime; + leg.etime = cur.etime; + leg.val = cur.val; + leg.mode = cur.mode; + leg.flags = cur.flags; + leg.speed = cur.speed; + copyArr(leg.fname, cur.fname); + return leg; +} + +cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) { + cbVIDEOSOURCE leg{}; + copyArr(leg.name, cur.name); + leg.fps = cur.fps; + return leg; +} + +cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) { + cbTRACKOBJ leg{}; + copyArr(leg.name, cur.name); + leg.type = cur.type; + leg.pointCount = cur.pointCount; + return leg; +} + +cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) { + cbPKT_FILECFG leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.options = cur.options; + leg.duration = cur.duration; + leg.recording = cur.recording; + leg.extctrl = cur.extctrl; + copyArr(leg.username, cur.username); + copyArr(leg.filename, cur.filename); // aka datetime + copyArr(leg.comment, cur.comment); + return leg; +} + +} // namespace central_v3_11 + +} // namespace cbshm diff --git a/src/cbshm/src/central_translators/v4_0.cpp b/src/cbshm/src/central_translators/v4_0.cpp new file mode 100644 index 00000000..82491e3a --- /dev/null +++ b/src/cbshm/src/central_translators/v4_0.cpp @@ -0,0 +1,814 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v4_0.cpp +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Central translator implementations +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "utils.h" +#include +#include + +namespace cbshm { + +namespace central_v4_0 { + +::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) { + ::cbPKT_HEADER cur{}; + cur.time = leg.time; + cur.chid = leg.chid; + cur.type = static_cast(leg.type); + cur.dlen = leg.dlen; + cur.instrument = leg.instrument; + cur.reserved = leg.reserved; + return cur; +} + +::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) { + ::cbPKT_SYSINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.sysfreq = leg.sysfreq; + cur.spikelen = leg.spikelen; + cur.spikepre = leg.spikepre; + cur.resetque = leg.resetque; + cur.runlevel = leg.runlevel; + cur.runflags = leg.runflags; + return cur; +} + +::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) { + ::cbPKT_PROCINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.idcode = leg.idcode; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; + cur.bankcount = leg.bankcount; + cur.groupcount = leg.groupcount; + cur.filtcount = leg.filtcount; + cur.sortcount = leg.sortcount; + cur.unitcount = leg.unitcount; + cur.hoopcount = leg.hoopcount; + cur.reserved = leg.reserved; + cur.version = leg.version; + return cur; +} + +::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) { + ::cbPKT_BANKINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + copyArr(cur.label, leg.label); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; + return cur; +} + +::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) { + ::cbPKT_GROUPINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.group = leg.group; + copyArr(cur.label, leg.label); + cur.period = leg.period; + cur.length = leg.length; + copyArr(cur.list, leg.list); + return cur; +} + +::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) { + ::cbPKT_FILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.filt = leg.filt; + copyArr(cur.label, leg.label); + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; + cur.gain = leg.gain; + cur.sos1a1 = leg.sos1a1; + cur.sos1a2 = leg.sos1a2; + cur.sos1b1 = leg.sos1b1; + cur.sos1b2 = leg.sos1b2; + cur.sos2a1 = leg.sos2a1; + cur.sos2a2 = leg.sos2a2; + cur.sos2b1 = leg.sos2b1; + cur.sos2b2 = leg.sos2b2; + return cur; +} + +::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) { + ::cbPKT_ADAPTFILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.dLearningRate = leg.dLearningRate; + cur.nRefChan1 = leg.nRefChan1; + cur.nRefChan2 = leg.nRefChan2; + return cur; +} + +::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg) { + ::cbPKT_REFELECFILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.nRefChan = leg.nRefChan; + return cur; +} + +::cbSCALING fromLegacy(const cbSCALING& leg) { + ::cbSCALING cur{}; + cur.digmin = leg.digmin; + cur.digmax = leg.digmax; + cur.anamin = leg.anamin; + cur.anamax = leg.anamax; + cur.anagain = leg.anagain; + copyArr(cur.anaunit, leg.anaunit); + return cur; +} + +::cbFILTDESC fromLegacy(const cbFILTDESC& leg) { + ::cbFILTDESC cur{}; + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; + return cur; +} + +::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) { + ::cbMANUALUNITMAPPING cur{}; + cur.nOverride = leg.nOverride; + copyArr(cur.afOrigin, leg.afOrigin); + copyArr2D(cur.afShape, leg.afShape); + cur.aPhi = leg.aPhi; + cur.bValid = leg.bValid; + return cur; +} + +::cbHOOP fromLegacy(const cbHOOP& leg) { + ::cbHOOP cur{}; + cur.valid = leg.valid; + cur.time = leg.time; + cur.min = leg.min; + cur.max = leg.max; + return cur; +} + +::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) { + ::cbPKT_CHANINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.term = leg.term; + cur.chancaps = leg.chancaps; + cur.doutcaps = leg.doutcaps; + cur.dinpcaps = leg.dinpcaps; + cur.aoutcaps = leg.aoutcaps; + cur.ainpcaps = leg.ainpcaps; + cur.spkcaps = leg.spkcaps; + cur.physcalin = fromLegacy(leg.physcalin); + cur.phyfiltin = fromLegacy(leg.phyfiltin); + cur.physcalout = fromLegacy(leg.physcalout); + cur.phyfiltout = fromLegacy(leg.phyfiltout); + copyArr(cur.label, leg.label); + cur.userflags = leg.userflags; + copyArr(cur.position, leg.position); + cur.scalin = fromLegacy(leg.scalin); + cur.scalout = fromLegacy(leg.scalout); + cur.doutopts = leg.doutopts; + cur.dinpopts = leg.dinpopts; + cur.aoutopts = leg.aoutopts; + cur.eopchar = leg.eopchar; + cur.moninst = static_cast((leg.monsource >> 16) & 0xFFFF); // aka lowsamples + cur.monchan = static_cast(leg.monsource & 0xFFFF); // aka highsamples + cur.outvalue = leg.outvalue; // aka offset + cur.trigtype = leg.trigtype; + // skip reserved + cur.triginst = 0; // TODO: VERIFY + cur.trigchan = leg.trigchan; + cur.trigval = leg.trigval; + cur.ainpopts = leg.ainpopts; + cur.lncrate = leg.lncrate; + cur.smpfilter = leg.smpfilter; + cur.smpgroup = leg.smpgroup; + cur.smpdispmin = leg.smpdispmin; + cur.smpdispmax = leg.smpdispmax; + cur.spkfilter = leg.spkfilter; + cur.spkdispmax = leg.spkdispmax; + cur.lncdispmax = leg.lncdispmax; + cur.spkopts = leg.spkopts; + cur.spkthrlevel = leg.spkthrlevel; + cur.spkthrlimit = leg.spkthrlimit; + cur.spkgroup = leg.spkgroup; + cur.amplrejpos = leg.amplrejpos; + cur.amplrejneg = leg.amplrejneg; + cur.refelecchan = leg.refelecchan; + copyArr(cur.unitmapping, leg.unitmapping, fromLegacy); + copyArr2D(cur.spkhoops, leg.spkhoops, fromLegacy); + return cur; +} + +::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) { + ::cbPKT_FS_BASIS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.fs = leg.fs; + copyArr2D(cur.basis, leg.basis); + return cur; +} + +::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) { + ::cbPKT_SS_MODELSET cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.unit_number = leg.unit_number; + cur.valid = leg.valid; + cur.inverted = leg.inverted; + cur.num_samples = leg.num_samples; + copyArr(cur.mu_x, leg.mu_x); + copyArr2D(cur.Sigma_x, leg.Sigma_x); + cur.determinant_Sigma_x = leg.determinant_Sigma_x; + copyArr2D(cur.Sigma_x_inv, leg.Sigma_x_inv); + cur.log_determinant_Sigma_x = leg.log_determinant_Sigma_x; + cur.subcluster_spread_factor_numerator = leg.subcluster_spread_factor_numerator; + cur.subcluster_spread_factor_denominator = leg.subcluster_spread_factor_denominator; + cur.mu_e = leg.mu_e; + cur.sigma_e_squared = leg.sigma_e_squared; + return cur; +} + +::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg) { + ::cbPKT_SS_DETECT cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.fThreshold = leg.fThreshold; + cur.fMultiplier = leg.fMultiplier; + return cur; +} + +::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) { + ::cbPKT_SS_ARTIF_REJECT cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.nMaxSimulChans = leg.nMaxSimulChans; + cur.nRefractoryCount = leg.nRefractoryCount; + return cur; +} + +::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) { + ::cbPKT_SS_NOISE_BOUNDARY cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + copyArr(cur.afc, leg.afc); + copyArr2D(cur.afS, leg.afS); + return cur; +} + +::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) { + ::cbPKT_SS_STATISTICS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.nUpdateSpikes = leg.nUpdateSpikes; + cur.nAutoalg = leg.nAutoalg; + cur.nMode = leg.nMode; + cur.fMinClusterPairSpreadFactor = leg.fMinClusterPairSpreadFactor; + cur.fMaxSubclusterSpreadFactor = leg.fMaxSubclusterSpreadFactor; + cur.fMinClusterHistCorrMajMeasure = leg.fMinClusterHistCorrMajMeasure; + cur.fMaxClusterPairHistCorrMajMeasure = leg.fMaxClusterPairHistCorrMajMeasure; + cur.fClusterHistValleyPercentage = leg.fClusterHistValleyPercentage; + cur.fClusterHistClosePeakPercentage = leg.fClusterHistClosePeakPercentage; + cur.fClusterHistMinPeakPercentage = leg.fClusterHistMinPeakPercentage; + cur.nWaveBasisSize = leg.nWaveBasisSize; + cur.nWaveSampleSize = leg.nWaveSampleSize; + return cur; +} + +::cbAdaptControl fromLegacy(const cbAdaptControl& leg) { + ::cbAdaptControl cur{}; + cur.nMode = leg.nMode; + cur.fTimeOutMinutes = leg.fTimeOutMinutes; + cur.fElapsedMinutes = leg.fElapsedMinutes; + return cur; +} + +::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg) { + ::cbPKT_SS_STATUS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats); + cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits); + return cur; +} + +::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg) { + ::cbproto::SpikeSorting cur{}; + copyArr(cur.basis, leg.asBasis, fromLegacy); + copyArr2D(cur.models, leg.asSortModel, fromLegacy); + cur.detect = fromLegacy(leg.pktDetect); + cur.artifact_reject = fromLegacy(leg.pktArtifReject); + copyArr(cur.noise_boundary, leg.pktNoiseBoundary, fromLegacy); + cur.statistics = fromLegacy(leg.pktStatistics); + cur.status = fromLegacy(leg.pktStatus); + return cur; +} + +::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg) { + ::cbPKT_NTRODEINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.ntrode = leg.ntrode; + copyArr(cur.label, leg.label); + copyArr2D(cur.ellipses, leg.ellipses, fromLegacy); + cur.nSite = leg.nSite; + cur.fs = leg.fs; + copyArr(cur.nChan, leg.nChan); + return cur; +} + +::cbWaveformData fromLegacy(const cbWaveformData& leg) { + ::cbWaveformData cur{}; + cur.offset = leg.offset; // aka sineFrequency + cur.seq = leg.seq; // aka sineAmplitude + cur.seqTotal = leg.seqTotal; + cur.phases = leg.phases; + copyArr(cur.duration, leg.duration); + copyArr(cur.amplitude, leg.amplitude); + return cur; +} + +::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) { + ::cbPKT_AOUT_WAVEFORM cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.repeats = leg.repeats; + cur.trig = static_cast((leg.trig >> 8) & 0xFF); + cur.trigInst = static_cast(leg.trig & 0xFF); + cur.trigChan = leg.trigChan; + cur.trigValue = leg.trigValue; + cur.trigNum = leg.trigNum; + cur.active = leg.active; + cur.wave = fromLegacy(leg.wave); + return cur; +} + +::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg) { + ::cbPKT_LNC cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.lncFreq = leg.lncFreq; + cur.lncRefChan = leg.lncRefChan; + cur.lncGlobalMode = leg.lncGlobalMode; + return cur; +} + +::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) { + ::cbPKT_NPLAY cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.ftime = leg.ftime; // aka opt + cur.stime = leg.stime; + cur.etime = leg.etime; + cur.val = leg.val; + cur.mode = leg.mode; + cur.flags = leg.flags; + cur.speed = leg.speed; + copyArr(cur.fname, leg.fname); + return cur; +} + +::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg) { + ::cbVIDEOSOURCE cur{}; + copyArr(cur.name, leg.name); + cur.fps = leg.fps; + return cur; +} + +::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) { + ::cbTRACKOBJ cur{}; + copyArr(cur.name, leg.name); + cur.type = leg.type; + cur.pointCount = leg.pointCount; + return cur; +} + +::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) { + ::cbPKT_FILECFG cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.options = leg.options; + cur.duration = leg.duration; + cur.recording = leg.recording; + cur.extctrl = leg.extctrl; + copyArr(cur.username, leg.username); + copyArr(cur.filename, leg.filename); // aka datetime + copyArr(cur.comment, leg.comment); + return cur; +} + +cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) { + cbPKT_HEADER leg{}; + leg.time = cur.time; + leg.chid = cur.chid; + leg.type = static_cast(cur.type); + leg.dlen = cur.dlen; + leg.instrument = cur.instrument; + leg.reserved = cur.reserved; + return leg; +} + +cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) { + cbPKT_SYSINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.sysfreq = cur.sysfreq; + leg.spikelen = cur.spikelen; + leg.spikepre = cur.spikepre; + leg.resetque = cur.resetque; + leg.runlevel = cur.runlevel; + leg.runflags = cur.runflags; + return leg; +} + +cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) { + cbPKT_PROCINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.idcode = cur.idcode; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; + leg.bankcount = cur.bankcount; + leg.groupcount = cur.groupcount; + leg.filtcount = cur.filtcount; + leg.sortcount = cur.sortcount; + leg.unitcount = cur.unitcount; + leg.hoopcount = cur.hoopcount; + leg.reserved = cur.reserved; + leg.version = cur.version; + return leg; +} + +cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) { + cbPKT_BANKINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + copyArr(leg.label, cur.label); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; + return leg; +} + +cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) { + cbPKT_GROUPINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.group = cur.group; + copyArr(leg.label, cur.label); + leg.period = cur.period; + leg.length = cur.length; + copyArr(leg.list, cur.list); + return leg; +} + +cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) { + cbPKT_FILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.filt = cur.filt; + copyArr(leg.label, cur.label); + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; + leg.gain = cur.gain; + leg.sos1a1 = cur.sos1a1; + leg.sos1a2 = cur.sos1a2; + leg.sos1b1 = cur.sos1b1; + leg.sos1b2 = cur.sos1b2; + leg.sos2a1 = cur.sos2a1; + leg.sos2a2 = cur.sos2a2; + leg.sos2b1 = cur.sos2b1; + leg.sos2b2 = cur.sos2b2; + return leg; +} + +cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) { + cbPKT_ADAPTFILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.dLearningRate = cur.dLearningRate; + leg.nRefChan1 = cur.nRefChan1; + leg.nRefChan2 = cur.nRefChan2; + return leg; +} + +cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur) { + cbPKT_REFELECFILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.nRefChan = cur.nRefChan; + return leg; +} + +cbSCALING toLegacy(const ::cbSCALING& cur) { + cbSCALING leg{}; + leg.digmin = cur.digmin; + leg.digmax = cur.digmax; + leg.anamin = cur.anamin; + leg.anamax = cur.anamax; + leg.anagain = cur.anagain; + copyArr(leg.anaunit, cur.anaunit); + return leg; +} + +cbFILTDESC toLegacy(const ::cbFILTDESC& cur) { + cbFILTDESC leg{}; + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; + return leg; +} + +cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) { + cbMANUALUNITMAPPING leg{}; + leg.nOverride = cur.nOverride; + copyArr(leg.afOrigin, cur.afOrigin); + copyArr2D(leg.afShape, cur.afShape); + leg.aPhi = cur.aPhi; + leg.bValid = cur.bValid; + return leg; +} + +cbHOOP toLegacy(const ::cbHOOP& cur) { + cbHOOP leg{}; + leg.valid = cur.valid; + leg.time = cur.time; + leg.min = cur.min; + leg.max = cur.max; + return leg; +} + +cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) { + cbPKT_CHANINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.term = cur.term; + leg.chancaps = cur.chancaps; + leg.doutcaps = cur.doutcaps; + leg.dinpcaps = cur.dinpcaps; + leg.aoutcaps = cur.aoutcaps; + leg.ainpcaps = cur.ainpcaps; + leg.spkcaps = cur.spkcaps; + leg.physcalin = toLegacy(cur.physcalin); + leg.phyfiltin = toLegacy(cur.phyfiltin); + leg.physcalout = toLegacy(cur.physcalout); + leg.phyfiltout = toLegacy(cur.phyfiltout); + copyArr(leg.label, cur.label); + leg.userflags = cur.userflags; + copyArr(leg.position, cur.position); + leg.scalin = toLegacy(cur.scalin); + leg.scalout = toLegacy(cur.scalout); + leg.doutopts = cur.doutopts; + leg.dinpopts = cur.dinpopts; + leg.aoutopts = cur.aoutopts; + leg.eopchar = cur.eopchar; + leg.monsource = (static_cast(cur.moninst) << 16) | static_cast(cur.monchan); // aka highsamples and lowsamples + leg.outvalue = cur.outvalue; // aka offset + leg.trigtype = cur.trigtype; + leg.trigchan = cur.trigchan; + leg.trigval = cur.trigval; + leg.ainpopts = cur.ainpopts; + leg.lncrate = cur.lncrate; + leg.smpfilter = cur.smpfilter; + leg.smpgroup = cur.smpgroup; + leg.smpdispmin = cur.smpdispmin; + leg.smpdispmax = cur.smpdispmax; + leg.spkfilter = cur.spkfilter; + leg.spkdispmax = cur.spkdispmax; + leg.lncdispmax = cur.lncdispmax; + leg.spkopts = cur.spkopts; + leg.spkthrlevel = cur.spkthrlevel; + leg.spkthrlimit = cur.spkthrlimit; + leg.spkgroup = cur.spkgroup; + leg.amplrejpos = cur.amplrejpos; + leg.amplrejneg = cur.amplrejneg; + leg.refelecchan = cur.refelecchan; + copyArr(leg.unitmapping, cur.unitmapping, toLegacy); + copyArr2D(leg.spkhoops, cur.spkhoops, toLegacy); + return leg; +} + +cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) { + cbPKT_FS_BASIS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.fs = cur.fs; + copyArr2D(leg.basis, cur.basis); + return leg; +} + +cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) { + cbPKT_SS_MODELSET leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.unit_number = cur.unit_number; + leg.valid = cur.valid; + leg.inverted = cur.inverted; + leg.num_samples = cur.num_samples; + copyArr(leg.mu_x, cur.mu_x); + copyArr2D(leg.Sigma_x, cur.Sigma_x); + leg.determinant_Sigma_x = cur.determinant_Sigma_x; + copyArr2D(leg.Sigma_x_inv, cur.Sigma_x_inv); + leg.log_determinant_Sigma_x = cur.log_determinant_Sigma_x; + leg.subcluster_spread_factor_numerator = cur.subcluster_spread_factor_numerator; + leg.subcluster_spread_factor_denominator = cur.subcluster_spread_factor_denominator; + leg.mu_e = cur.mu_e; + leg.sigma_e_squared = cur.sigma_e_squared; + return leg; +} + +cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur) { + cbPKT_SS_DETECT leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.fThreshold = cur.fThreshold; + leg.fMultiplier = cur.fMultiplier; + return leg; +} + +cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) { + cbPKT_SS_ARTIF_REJECT leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.nMaxSimulChans = cur.nMaxSimulChans; + leg.nRefractoryCount = cur.nRefractoryCount; + return leg; +} + +cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) { + cbPKT_SS_NOISE_BOUNDARY leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + copyArr(leg.afc, cur.afc); + copyArr2D(leg.afS, cur.afS); + return leg; +} + +cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) { + cbPKT_SS_STATISTICS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.nUpdateSpikes = cur.nUpdateSpikes; + leg.nAutoalg = cur.nAutoalg; + leg.nMode = cur.nMode; + leg.fMinClusterPairSpreadFactor = cur.fMinClusterPairSpreadFactor; + leg.fMaxSubclusterSpreadFactor = cur.fMaxSubclusterSpreadFactor; + leg.fMinClusterHistCorrMajMeasure = cur.fMinClusterHistCorrMajMeasure; + leg.fMaxClusterPairHistCorrMajMeasure = cur.fMaxClusterPairHistCorrMajMeasure; + leg.fClusterHistValleyPercentage = cur.fClusterHistValleyPercentage; + leg.fClusterHistClosePeakPercentage = cur.fClusterHistClosePeakPercentage; + leg.fClusterHistMinPeakPercentage = cur.fClusterHistMinPeakPercentage; + leg.nWaveBasisSize = cur.nWaveBasisSize; + leg.nWaveSampleSize = cur.nWaveSampleSize; + return leg; +} + +cbAdaptControl toLegacy(const ::cbAdaptControl& cur) { + cbAdaptControl leg{}; + leg.nMode = cur.nMode; + leg.fTimeOutMinutes = cur.fTimeOutMinutes; + leg.fElapsedMinutes = cur.fElapsedMinutes; + return leg; +} + +cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur) { + cbPKT_SS_STATUS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cntlUnitStats = toLegacy(cur.cntlUnitStats); + leg.cntlNumUnits = toLegacy(cur.cntlNumUnits); + return leg; +} + +cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur) { + cbSPIKE_SORTING leg{}; + copyArr(leg.asBasis, cur.basis, toLegacy); + copyArr2D(leg.asSortModel, cur.models, toLegacy); + leg.pktDetect = toLegacy(cur.detect); + leg.pktArtifReject = toLegacy(cur.artifact_reject); + copyArr(leg.pktNoiseBoundary, cur.noise_boundary, toLegacy); + leg.pktStatistics = toLegacy(cur.statistics); + leg.pktStatus = toLegacy(cur.status); + return leg; +} + +cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur) { + cbPKT_NTRODEINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.ntrode = cur.ntrode; + copyArr(leg.label, cur.label); + copyArr2D(leg.ellipses, cur.ellipses, toLegacy); + leg.nSite = cur.nSite; + leg.fs = cur.fs; + copyArr(leg.nChan, cur.nChan); + return leg; +} + +cbWaveformData toLegacy(const ::cbWaveformData& cur) { + cbWaveformData leg{}; + leg.offset = cur.offset; // aka sineFrequency + leg.seq = cur.seq; // aka sineAmplitude + leg.seqTotal = cur.seqTotal; + leg.phases = cur.phases; + copyArr(leg.duration, cur.duration); + copyArr(leg.amplitude, cur.amplitude); + return leg; +} + +cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) { + cbPKT_AOUT_WAVEFORM leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.repeats = cur.repeats; + leg.trig = (static_cast(cur.trig) << 8) | static_cast(cur.trigInst); + leg.trigChan = cur.trigChan; + leg.trigValue = cur.trigValue; + leg.trigNum = cur.trigNum; + leg.active = cur.active; + leg.wave = toLegacy(cur.wave); + return leg; +} + +cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur) { + cbPKT_LNC leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.lncFreq = cur.lncFreq; + leg.lncRefChan = cur.lncRefChan; + leg.lncGlobalMode = cur.lncGlobalMode; + return leg; +} + +cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) { + cbPKT_NPLAY leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.ftime = cur.ftime; // aka opt + leg.stime = cur.stime; + leg.etime = cur.etime; + leg.val = cur.val; + leg.mode = cur.mode; + leg.flags = cur.flags; + leg.speed = cur.speed; + copyArr(leg.fname, cur.fname); + return leg; +} + +cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) { + cbVIDEOSOURCE leg{}; + copyArr(leg.name, cur.name); + leg.fps = cur.fps; + return leg; +} + +cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) { + cbTRACKOBJ leg{}; + copyArr(leg.name, cur.name); + leg.type = cur.type; + leg.pointCount = cur.pointCount; + return leg; +} + +cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) { + cbPKT_FILECFG leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.options = cur.options; + leg.duration = cur.duration; + leg.recording = cur.recording; + leg.extctrl = cur.extctrl; + copyArr(leg.username, cur.username); + copyArr(leg.filename, cur.filename); // aka datetime + copyArr(leg.comment, cur.comment); + return leg; +} + +} // namespace central_v4_0 + +} // namespace cbshm diff --git a/src/cbshm/src/central_translators/v4_1.cpp b/src/cbshm/src/central_translators/v4_1.cpp new file mode 100644 index 00000000..f65b2077 --- /dev/null +++ b/src/cbshm/src/central_translators/v4_1.cpp @@ -0,0 +1,818 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v4_1.cpp +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Central translator implementations +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "utils.h" +#include +#include + +namespace cbshm { + +namespace central_v4_1 { + +::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) { + ::cbPKT_HEADER cur{}; + cur.time = leg.time; + cur.chid = leg.chid; + cur.type = leg.type; + cur.dlen = leg.dlen; + cur.instrument = leg.instrument; + cur.reserved = leg.reserved; + return cur; +} + +::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) { + ::cbPKT_SYSINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.sysfreq = leg.sysfreq; + cur.spikelen = leg.spikelen; + cur.spikepre = leg.spikepre; + cur.resetque = leg.resetque; + cur.runlevel = leg.runlevel; + cur.runflags = leg.runflags; + return cur; +} + +::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) { + ::cbPKT_PROCINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.idcode = leg.idcode; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; + cur.bankcount = leg.bankcount; + cur.groupcount = leg.groupcount; + cur.filtcount = leg.filtcount; + cur.sortcount = leg.sortcount; + cur.unitcount = leg.unitcount; + cur.hoopcount = leg.hoopcount; + cur.reserved = leg.reserved; + cur.version = leg.version; + return cur; +} + +::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) { + ::cbPKT_BANKINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + copyArr(cur.label, leg.label); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; + return cur; +} + +::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) { + ::cbPKT_GROUPINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.group = leg.group; + copyArr(cur.label, leg.label); + cur.period = leg.period; + cur.length = leg.length; + copyArr(cur.list, leg.list); + return cur; +} + +::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) { + ::cbPKT_FILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.filt = leg.filt; + copyArr(cur.label, leg.label); + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; + cur.gain = leg.gain; + cur.sos1a1 = leg.sos1a1; + cur.sos1a2 = leg.sos1a2; + cur.sos1b1 = leg.sos1b1; + cur.sos1b2 = leg.sos1b2; + cur.sos2a1 = leg.sos2a1; + cur.sos2a2 = leg.sos2a2; + cur.sos2b1 = leg.sos2b1; + cur.sos2b2 = leg.sos2b2; + return cur; +} + +::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) { + ::cbPKT_ADAPTFILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.dLearningRate = leg.dLearningRate; + cur.nRefChan1 = leg.nRefChan1; + cur.nRefChan2 = leg.nRefChan2; + return cur; +} + +::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg) { + ::cbPKT_REFELECFILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.nRefChan = leg.nRefChan; + return cur; +} + +::cbSCALING fromLegacy(const cbSCALING& leg) { + ::cbSCALING cur{}; + cur.digmin = leg.digmin; + cur.digmax = leg.digmax; + cur.anamin = leg.anamin; + cur.anamax = leg.anamax; + cur.anagain = leg.anagain; + copyArr(cur.anaunit, leg.anaunit); + return cur; +} + +::cbFILTDESC fromLegacy(const cbFILTDESC& leg) { + ::cbFILTDESC cur{}; + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; + return cur; +} + +::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) { + ::cbMANUALUNITMAPPING cur{}; + cur.nOverride = leg.nOverride; + copyArr(cur.afOrigin, leg.afOrigin); + copyArr2D(cur.afShape, leg.afShape); + cur.aPhi = leg.aPhi; + cur.bValid = leg.bValid; + return cur; +} + +::cbHOOP fromLegacy(const cbHOOP& leg) { + ::cbHOOP cur{}; + cur.valid = leg.valid; + cur.time = leg.time; + cur.min = leg.min; + cur.max = leg.max; + return cur; +} + +::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) { + ::cbPKT_CHANINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.term = leg.term; + cur.chancaps = leg.chancaps; + cur.doutcaps = leg.doutcaps; + cur.dinpcaps = leg.dinpcaps; + cur.aoutcaps = leg.aoutcaps; + cur.ainpcaps = leg.ainpcaps; + cur.spkcaps = leg.spkcaps; + cur.physcalin = fromLegacy(leg.physcalin); + cur.phyfiltin = fromLegacy(leg.phyfiltin); + cur.physcalout = fromLegacy(leg.physcalout); + cur.phyfiltout = fromLegacy(leg.phyfiltout); + copyArr(cur.label, leg.label); + cur.userflags = leg.userflags; + copyArr(cur.position, leg.position); + cur.scalin = fromLegacy(leg.scalin); + cur.scalout = fromLegacy(leg.scalout); + cur.doutopts = leg.doutopts; + cur.dinpopts = leg.dinpopts; + cur.aoutopts = leg.aoutopts; + cur.eopchar = leg.eopchar; + cur.moninst = leg.moninst; // aka lowsamples + cur.monchan = leg.monchan; // aka highsamples + cur.outvalue = leg.outvalue; // aka offset + cur.trigtype = leg.trigtype; + copyArr(cur.reserved, leg.reserved); + cur.triginst = leg.triginst; + cur.trigchan = leg.trigchan; + cur.trigval = leg.trigval; + cur.ainpopts = leg.ainpopts; + cur.lncrate = leg.lncrate; + cur.smpfilter = leg.smpfilter; + cur.smpgroup = leg.smpgroup; + cur.smpdispmin = leg.smpdispmin; + cur.smpdispmax = leg.smpdispmax; + cur.spkfilter = leg.spkfilter; + cur.spkdispmax = leg.spkdispmax; + cur.lncdispmax = leg.lncdispmax; + cur.spkopts = leg.spkopts; + cur.spkthrlevel = leg.spkthrlevel; + cur.spkthrlimit = leg.spkthrlimit; + cur.spkgroup = leg.spkgroup; + cur.amplrejpos = leg.amplrejpos; + cur.amplrejneg = leg.amplrejneg; + cur.refelecchan = leg.refelecchan; + copyArr(cur.unitmapping, leg.unitmapping, fromLegacy); + copyArr2D(cur.spkhoops, leg.spkhoops, fromLegacy); + return cur; +} + +::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) { + ::cbPKT_FS_BASIS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.fs = leg.fs; + copyArr2D(cur.basis, leg.basis); + return cur; +} + +::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) { + ::cbPKT_SS_MODELSET cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.unit_number = leg.unit_number; + cur.valid = leg.valid; + cur.inverted = leg.inverted; + cur.num_samples = leg.num_samples; + copyArr(cur.mu_x, leg.mu_x); + copyArr2D(cur.Sigma_x, leg.Sigma_x); + cur.determinant_Sigma_x = leg.determinant_Sigma_x; + copyArr2D(cur.Sigma_x_inv, leg.Sigma_x_inv); + cur.log_determinant_Sigma_x = leg.log_determinant_Sigma_x; + cur.subcluster_spread_factor_numerator = leg.subcluster_spread_factor_numerator; + cur.subcluster_spread_factor_denominator = leg.subcluster_spread_factor_denominator; + cur.mu_e = leg.mu_e; + cur.sigma_e_squared = leg.sigma_e_squared; + return cur; +} + +::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg) { + ::cbPKT_SS_DETECT cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.fThreshold = leg.fThreshold; + cur.fMultiplier = leg.fMultiplier; + return cur; +} + +::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) { + ::cbPKT_SS_ARTIF_REJECT cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.nMaxSimulChans = leg.nMaxSimulChans; + cur.nRefractoryCount = leg.nRefractoryCount; + return cur; +} + +::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) { + ::cbPKT_SS_NOISE_BOUNDARY cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + copyArr(cur.afc, leg.afc); + copyArr2D(cur.afS, leg.afS); + return cur; +} + +::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) { + ::cbPKT_SS_STATISTICS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.nUpdateSpikes = leg.nUpdateSpikes; + cur.nAutoalg = leg.nAutoalg; + cur.nMode = leg.nMode; + cur.fMinClusterPairSpreadFactor = leg.fMinClusterPairSpreadFactor; + cur.fMaxSubclusterSpreadFactor = leg.fMaxSubclusterSpreadFactor; + cur.fMinClusterHistCorrMajMeasure = leg.fMinClusterHistCorrMajMeasure; + cur.fMaxClusterPairHistCorrMajMeasure = leg.fMaxClusterPairHistCorrMajMeasure; + cur.fClusterHistValleyPercentage = leg.fClusterHistValleyPercentage; + cur.fClusterHistClosePeakPercentage = leg.fClusterHistClosePeakPercentage; + cur.fClusterHistMinPeakPercentage = leg.fClusterHistMinPeakPercentage; + cur.nWaveBasisSize = leg.nWaveBasisSize; + cur.nWaveSampleSize = leg.nWaveSampleSize; + return cur; +} + +::cbAdaptControl fromLegacy(const cbAdaptControl& leg) { + ::cbAdaptControl cur{}; + cur.nMode = leg.nMode; + cur.fTimeOutMinutes = leg.fTimeOutMinutes; + cur.fElapsedMinutes = leg.fElapsedMinutes; + return cur; +} + +::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg) { + ::cbPKT_SS_STATUS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats); + cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits); + return cur; +} + +::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg) { + ::cbproto::SpikeSorting cur{}; + copyArr(cur.basis, leg.asBasis, fromLegacy); + copyArr2D(cur.models, leg.asSortModel, fromLegacy); + cur.detect = fromLegacy(leg.pktDetect); + cur.artifact_reject = fromLegacy(leg.pktArtifReject); + copyArr(cur.noise_boundary, leg.pktNoiseBoundary, fromLegacy); + cur.statistics = fromLegacy(leg.pktStatistics); + cur.status = fromLegacy(leg.pktStatus); + return cur; +} + +::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg) { + ::cbPKT_NTRODEINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.ntrode = leg.ntrode; + copyArr(cur.label, leg.label); + copyArr2D(cur.ellipses, leg.ellipses, fromLegacy); + cur.nSite = leg.nSite; + cur.fs = leg.fs; + copyArr(cur.nChan, leg.nChan); + return cur; +} + +::cbWaveformData fromLegacy(const cbWaveformData& leg) { + ::cbWaveformData cur{}; + cur.offset = leg.offset; // aka sineFrequency + cur.seq = leg.seq; // aka sineAmplitude + cur.seqTotal = leg.seqTotal; + cur.phases = leg.phases; + copyArr(cur.duration, leg.duration); + copyArr(cur.amplitude, leg.amplitude); + return cur; +} + +::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) { + ::cbPKT_AOUT_WAVEFORM cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.repeats = leg.repeats; + cur.trig = leg.trig; + cur.trigInst = leg.trigInst; + cur.trigChan = leg.trigChan; + cur.trigValue = leg.trigValue; + cur.trigNum = leg.trigNum; + cur.active = leg.active; + cur.wave = fromLegacy(leg.wave); + return cur; +} + +::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg) { + ::cbPKT_LNC cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.lncFreq = leg.lncFreq; + cur.lncRefChan = leg.lncRefChan; + cur.lncGlobalMode = leg.lncGlobalMode; + return cur; +} + +::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) { + ::cbPKT_NPLAY cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.ftime = leg.ftime; // aka opt + cur.stime = leg.stime; + cur.etime = leg.etime; + cur.val = leg.val; + cur.mode = leg.mode; + cur.flags = leg.flags; + cur.speed = leg.speed; + copyArr(cur.fname, leg.fname); + return cur; +} + +::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg) { + ::cbVIDEOSOURCE cur{}; + copyArr(cur.name, leg.name); + cur.fps = leg.fps; + return cur; +} + +::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) { + ::cbTRACKOBJ cur{}; + copyArr(cur.name, leg.name); + cur.type = leg.type; + cur.pointCount = leg.pointCount; + return cur; +} + +::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) { + ::cbPKT_FILECFG cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.options = leg.options; + cur.duration = leg.duration; + cur.recording = leg.recording; + cur.extctrl = leg.extctrl; + copyArr(cur.username, leg.username); + copyArr(cur.filename, leg.filename); // aka datetime + copyArr(cur.comment, leg.comment); + return cur; +} + +cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) { + cbPKT_HEADER leg{}; + leg.time = cur.time; + leg.chid = cur.chid; + leg.type = cur.type; + leg.dlen = cur.dlen; + leg.instrument = cur.instrument; + leg.reserved = cur.reserved; + return leg; +} + +cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) { + cbPKT_SYSINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.sysfreq = cur.sysfreq; + leg.spikelen = cur.spikelen; + leg.spikepre = cur.spikepre; + leg.resetque = cur.resetque; + leg.runlevel = cur.runlevel; + leg.runflags = cur.runflags; + return leg; +} + +cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) { + cbPKT_PROCINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.idcode = cur.idcode; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; + leg.bankcount = cur.bankcount; + leg.groupcount = cur.groupcount; + leg.filtcount = cur.filtcount; + leg.sortcount = cur.sortcount; + leg.unitcount = cur.unitcount; + leg.hoopcount = cur.hoopcount; + leg.reserved = cur.reserved; + leg.version = cur.version; + return leg; +} + +cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) { + cbPKT_BANKINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + copyArr(leg.label, cur.label); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; + return leg; +} + +cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) { + cbPKT_GROUPINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.group = cur.group; + copyArr(leg.label, cur.label); + leg.period = cur.period; + leg.length = cur.length; + copyArr(leg.list, cur.list); + return leg; +} + +cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) { + cbPKT_FILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.filt = cur.filt; + copyArr(leg.label, cur.label); + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; + leg.gain = cur.gain; + leg.sos1a1 = cur.sos1a1; + leg.sos1a2 = cur.sos1a2; + leg.sos1b1 = cur.sos1b1; + leg.sos1b2 = cur.sos1b2; + leg.sos2a1 = cur.sos2a1; + leg.sos2a2 = cur.sos2a2; + leg.sos2b1 = cur.sos2b1; + leg.sos2b2 = cur.sos2b2; + return leg; +} + +cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) { + cbPKT_ADAPTFILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.dLearningRate = cur.dLearningRate; + leg.nRefChan1 = cur.nRefChan1; + leg.nRefChan2 = cur.nRefChan2; + return leg; +} + +cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur) { + cbPKT_REFELECFILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.nRefChan = cur.nRefChan; + return leg; +} + +cbSCALING toLegacy(const ::cbSCALING& cur) { + cbSCALING leg{}; + leg.digmin = cur.digmin; + leg.digmax = cur.digmax; + leg.anamin = cur.anamin; + leg.anamax = cur.anamax; + leg.anagain = cur.anagain; + copyArr(leg.anaunit, cur.anaunit); + return leg; +} + +cbFILTDESC toLegacy(const ::cbFILTDESC& cur) { + cbFILTDESC leg{}; + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; + return leg; +} + +cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) { + cbMANUALUNITMAPPING leg{}; + leg.nOverride = cur.nOverride; + copyArr(leg.afOrigin, cur.afOrigin); + copyArr2D(leg.afShape, cur.afShape); + leg.aPhi = cur.aPhi; + leg.bValid = cur.bValid; + return leg; +} + +cbHOOP toLegacy(const ::cbHOOP& cur) { + cbHOOP leg{}; + leg.valid = cur.valid; + leg.time = cur.time; + leg.min = cur.min; + leg.max = cur.max; + return leg; +} + +cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) { + cbPKT_CHANINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.term = cur.term; + leg.chancaps = cur.chancaps; + leg.doutcaps = cur.doutcaps; + leg.dinpcaps = cur.dinpcaps; + leg.aoutcaps = cur.aoutcaps; + leg.ainpcaps = cur.ainpcaps; + leg.spkcaps = cur.spkcaps; + leg.physcalin = toLegacy(cur.physcalin); + leg.phyfiltin = toLegacy(cur.phyfiltin); + leg.physcalout = toLegacy(cur.physcalout); + leg.phyfiltout = toLegacy(cur.phyfiltout); + copyArr(leg.label, cur.label); + leg.userflags = cur.userflags; + copyArr(leg.position, cur.position); + leg.scalin = toLegacy(cur.scalin); + leg.scalout = toLegacy(cur.scalout); + leg.doutopts = cur.doutopts; + leg.dinpopts = cur.dinpopts; + leg.aoutopts = cur.aoutopts; + leg.eopchar = cur.eopchar; + leg.moninst = cur.moninst; // aka lowsamples + leg.monchan = cur.monchan; // aka highsamples + leg.outvalue = cur.outvalue; // aka offset + leg.trigtype = cur.trigtype; + copyArr(leg.reserved, cur.reserved); + leg.triginst = cur.triginst; + leg.trigchan = cur.trigchan; + leg.trigval = cur.trigval; + leg.ainpopts = cur.ainpopts; + leg.lncrate = cur.lncrate; + leg.smpfilter = cur.smpfilter; + leg.smpgroup = cur.smpgroup; + leg.smpdispmin = cur.smpdispmin; + leg.smpdispmax = cur.smpdispmax; + leg.spkfilter = cur.spkfilter; + leg.spkdispmax = cur.spkdispmax; + leg.lncdispmax = cur.lncdispmax; + leg.spkopts = cur.spkopts; + leg.spkthrlevel = cur.spkthrlevel; + leg.spkthrlimit = cur.spkthrlimit; + leg.spkgroup = cur.spkgroup; + leg.amplrejpos = cur.amplrejpos; + leg.amplrejneg = cur.amplrejneg; + leg.refelecchan = cur.refelecchan; + copyArr(leg.unitmapping, cur.unitmapping, toLegacy); + copyArr2D(leg.spkhoops, cur.spkhoops, toLegacy); + return leg; +} + +cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) { + cbPKT_FS_BASIS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.fs = cur.fs; + copyArr2D(leg.basis, cur.basis); + return leg; +} + +cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) { + cbPKT_SS_MODELSET leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.unit_number = cur.unit_number; + leg.valid = cur.valid; + leg.inverted = cur.inverted; + leg.num_samples = cur.num_samples; + copyArr(leg.mu_x, cur.mu_x); + copyArr2D(leg.Sigma_x, cur.Sigma_x); + leg.determinant_Sigma_x = cur.determinant_Sigma_x; + copyArr2D(leg.Sigma_x_inv, cur.Sigma_x_inv); + leg.log_determinant_Sigma_x = cur.log_determinant_Sigma_x; + leg.subcluster_spread_factor_numerator = cur.subcluster_spread_factor_numerator; + leg.subcluster_spread_factor_denominator = cur.subcluster_spread_factor_denominator; + leg.mu_e = cur.mu_e; + leg.sigma_e_squared = cur.sigma_e_squared; + return leg; +} + +cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur) { + cbPKT_SS_DETECT leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.fThreshold = cur.fThreshold; + leg.fMultiplier = cur.fMultiplier; + return leg; +} + +cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) { + cbPKT_SS_ARTIF_REJECT leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.nMaxSimulChans = cur.nMaxSimulChans; + leg.nRefractoryCount = cur.nRefractoryCount; + return leg; +} + +cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) { + cbPKT_SS_NOISE_BOUNDARY leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + copyArr(leg.afc, cur.afc); + copyArr2D(leg.afS, cur.afS); + return leg; +} + +cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) { + cbPKT_SS_STATISTICS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.nUpdateSpikes = cur.nUpdateSpikes; + leg.nAutoalg = cur.nAutoalg; + leg.nMode = cur.nMode; + leg.fMinClusterPairSpreadFactor = cur.fMinClusterPairSpreadFactor; + leg.fMaxSubclusterSpreadFactor = cur.fMaxSubclusterSpreadFactor; + leg.fMinClusterHistCorrMajMeasure = cur.fMinClusterHistCorrMajMeasure; + leg.fMaxClusterPairHistCorrMajMeasure = cur.fMaxClusterPairHistCorrMajMeasure; + leg.fClusterHistValleyPercentage = cur.fClusterHistValleyPercentage; + leg.fClusterHistClosePeakPercentage = cur.fClusterHistClosePeakPercentage; + leg.fClusterHistMinPeakPercentage = cur.fClusterHistMinPeakPercentage; + leg.nWaveBasisSize = cur.nWaveBasisSize; + leg.nWaveSampleSize = cur.nWaveSampleSize; + return leg; +} + +cbAdaptControl toLegacy(const ::cbAdaptControl& cur) { + cbAdaptControl leg{}; + leg.nMode = cur.nMode; + leg.fTimeOutMinutes = cur.fTimeOutMinutes; + leg.fElapsedMinutes = cur.fElapsedMinutes; + return leg; +} + +cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur) { + cbPKT_SS_STATUS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cntlUnitStats = toLegacy(cur.cntlUnitStats); + leg.cntlNumUnits = toLegacy(cur.cntlNumUnits); + return leg; +} + +cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur) { + cbSPIKE_SORTING leg{}; + copyArr(leg.asBasis, cur.basis, toLegacy); + copyArr2D(leg.asSortModel, cur.models, toLegacy); + leg.pktDetect = toLegacy(cur.detect); + leg.pktArtifReject = toLegacy(cur.artifact_reject); + copyArr(leg.pktNoiseBoundary, cur.noise_boundary, toLegacy); + leg.pktStatistics = toLegacy(cur.statistics); + leg.pktStatus = toLegacy(cur.status); + return leg; +} + +cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur) { + cbPKT_NTRODEINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.ntrode = cur.ntrode; + copyArr(leg.label, cur.label); + copyArr2D(leg.ellipses, cur.ellipses, toLegacy); + leg.nSite = cur.nSite; + leg.fs = cur.fs; + copyArr(leg.nChan, cur.nChan); + return leg; +} + +cbWaveformData toLegacy(const ::cbWaveformData& cur) { + cbWaveformData leg{}; + leg.offset = cur.offset; // aka sineFrequency + leg.seq = cur.seq; // aka sineAmplitude + leg.seqTotal = cur.seqTotal; + leg.phases = cur.phases; + copyArr(leg.duration, cur.duration); + copyArr(leg.amplitude, cur.amplitude); + return leg; +} + +cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) { + cbPKT_AOUT_WAVEFORM leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.repeats = cur.repeats; + leg.trig = cur.trig; + leg.trigInst = cur.trigInst; + leg.trigChan = cur.trigChan; + leg.trigValue = cur.trigValue; + leg.trigNum = cur.trigNum; + leg.active = cur.active; + leg.wave = toLegacy(cur.wave); + return leg; +} + +cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur) { + cbPKT_LNC leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.lncFreq = cur.lncFreq; + leg.lncRefChan = cur.lncRefChan; + leg.lncGlobalMode = cur.lncGlobalMode; + return leg; +} + +cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) { + cbPKT_NPLAY leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.ftime = cur.ftime; // aka opt + leg.stime = cur.stime; + leg.etime = cur.etime; + leg.val = cur.val; + leg.mode = cur.mode; + leg.flags = cur.flags; + leg.speed = cur.speed; + copyArr(leg.fname, cur.fname); + return leg; +} + +cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) { + cbVIDEOSOURCE leg{}; + copyArr(leg.name, cur.name); + leg.fps = cur.fps; + return leg; +} + +cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) { + cbTRACKOBJ leg{}; + copyArr(leg.name, cur.name); + leg.type = cur.type; + leg.pointCount = cur.pointCount; + return leg; +} + +cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) { + cbPKT_FILECFG leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.options = cur.options; + leg.duration = cur.duration; + leg.recording = cur.recording; + leg.extctrl = cur.extctrl; + copyArr(leg.username, cur.username); + copyArr(leg.filename, cur.filename); // aka datetime + copyArr(leg.comment, cur.comment); + return leg; +} + +} // namespace central_v4_1 + +} // namespace cbshm diff --git a/src/cbshm/src/central_translators/v4_2.cpp b/src/cbshm/src/central_translators/v4_2.cpp new file mode 100644 index 00000000..c2a18890 --- /dev/null +++ b/src/cbshm/src/central_translators/v4_2.cpp @@ -0,0 +1,818 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v4_2.cpp +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Central translator implementations +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "utils.h" +#include +#include + +namespace cbshm { + +namespace central_v4_2 { + +::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) { + ::cbPKT_HEADER cur{}; + cur.time = leg.time; + cur.chid = leg.chid; + cur.type = leg.type; + cur.dlen = leg.dlen; + cur.instrument = leg.instrument; + cur.reserved = leg.reserved; + return cur; +} + +::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) { + ::cbPKT_SYSINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.sysfreq = leg.sysfreq; + cur.spikelen = leg.spikelen; + cur.spikepre = leg.spikepre; + cur.resetque = leg.resetque; + cur.runlevel = leg.runlevel; + cur.runflags = leg.runflags; + return cur; +} + +::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) { + ::cbPKT_PROCINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.idcode = leg.idcode; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; + cur.bankcount = leg.bankcount; + cur.groupcount = leg.groupcount; + cur.filtcount = leg.filtcount; + cur.sortcount = leg.sortcount; + cur.unitcount = leg.unitcount; + cur.hoopcount = leg.hoopcount; + cur.reserved = leg.reserved; + cur.version = leg.version; + return cur; +} + +::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) { + ::cbPKT_BANKINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + copyArr(cur.label, leg.label); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; + return cur; +} + +::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) { + ::cbPKT_GROUPINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.group = leg.group; + copyArr(cur.label, leg.label); + cur.period = leg.period; + cur.length = leg.length; + copyArr(cur.list, leg.list); + return cur; +} + +::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) { + ::cbPKT_FILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.filt = leg.filt; + copyArr(cur.label, leg.label); + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; + cur.gain = leg.gain; + cur.sos1a1 = leg.sos1a1; + cur.sos1a2 = leg.sos1a2; + cur.sos1b1 = leg.sos1b1; + cur.sos1b2 = leg.sos1b2; + cur.sos2a1 = leg.sos2a1; + cur.sos2a2 = leg.sos2a2; + cur.sos2b1 = leg.sos2b1; + cur.sos2b2 = leg.sos2b2; + return cur; +} + +::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) { + ::cbPKT_ADAPTFILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.dLearningRate = leg.dLearningRate; + cur.nRefChan1 = leg.nRefChan1; + cur.nRefChan2 = leg.nRefChan2; + return cur; +} + +::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg) { + ::cbPKT_REFELECFILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.nRefChan = leg.nRefChan; + return cur; +} + +::cbSCALING fromLegacy(const cbSCALING& leg) { + ::cbSCALING cur{}; + cur.digmin = leg.digmin; + cur.digmax = leg.digmax; + cur.anamin = leg.anamin; + cur.anamax = leg.anamax; + cur.anagain = leg.anagain; + copyArr(cur.anaunit, leg.anaunit); + return cur; +} + +::cbFILTDESC fromLegacy(const cbFILTDESC& leg) { + ::cbFILTDESC cur{}; + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; + return cur; +} + +::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) { + ::cbMANUALUNITMAPPING cur{}; + cur.nOverride = leg.nOverride; + copyArr(cur.afOrigin, leg.afOrigin); + copyArr2D(cur.afShape, leg.afShape); + cur.aPhi = leg.aPhi; + cur.bValid = leg.bValid; + return cur; +} + +::cbHOOP fromLegacy(const cbHOOP& leg) { + ::cbHOOP cur{}; + cur.valid = leg.valid; + cur.time = leg.time; + cur.min = leg.min; + cur.max = leg.max; + return cur; +} + +::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) { + ::cbPKT_CHANINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.term = leg.term; + cur.chancaps = leg.chancaps; + cur.doutcaps = leg.doutcaps; + cur.dinpcaps = leg.dinpcaps; + cur.aoutcaps = leg.aoutcaps; + cur.ainpcaps = leg.ainpcaps; + cur.spkcaps = leg.spkcaps; + cur.physcalin = fromLegacy(leg.physcalin); + cur.phyfiltin = fromLegacy(leg.phyfiltin); + cur.physcalout = fromLegacy(leg.physcalout); + cur.phyfiltout = fromLegacy(leg.phyfiltout); + copyArr(cur.label, leg.label); + cur.userflags = leg.userflags; + copyArr(cur.position, leg.position); + cur.scalin = fromLegacy(leg.scalin); + cur.scalout = fromLegacy(leg.scalout); + cur.doutopts = leg.doutopts; + cur.dinpopts = leg.dinpopts; + cur.aoutopts = leg.aoutopts; + cur.eopchar = leg.eopchar; + cur.moninst = leg.moninst; // aka lowsamples + cur.monchan = leg.monchan; // aka highsamples + cur.outvalue = leg.outvalue; // aka offset + cur.trigtype = leg.trigtype; + copyArr(cur.reserved, leg.reserved); + cur.triginst = leg.triginst; + cur.trigchan = leg.trigchan; + cur.trigval = leg.trigval; + cur.ainpopts = leg.ainpopts; + cur.lncrate = leg.lncrate; + cur.smpfilter = leg.smpfilter; + cur.smpgroup = leg.smpgroup; + cur.smpdispmin = leg.smpdispmin; + cur.smpdispmax = leg.smpdispmax; + cur.spkfilter = leg.spkfilter; + cur.spkdispmax = leg.spkdispmax; + cur.lncdispmax = leg.lncdispmax; + cur.spkopts = leg.spkopts; + cur.spkthrlevel = leg.spkthrlevel; + cur.spkthrlimit = leg.spkthrlimit; + cur.spkgroup = leg.spkgroup; + cur.amplrejpos = leg.amplrejpos; + cur.amplrejneg = leg.amplrejneg; + cur.refelecchan = leg.refelecchan; + copyArr(cur.unitmapping, leg.unitmapping, fromLegacy); + copyArr2D(cur.spkhoops, leg.spkhoops, fromLegacy); + return cur; +} + +::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) { + ::cbPKT_FS_BASIS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.fs = leg.fs; + copyArr2D(cur.basis, leg.basis); + return cur; +} + +::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) { + ::cbPKT_SS_MODELSET cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.unit_number = leg.unit_number; + cur.valid = leg.valid; + cur.inverted = leg.inverted; + cur.num_samples = leg.num_samples; + copyArr(cur.mu_x, leg.mu_x); + copyArr2D(cur.Sigma_x, leg.Sigma_x); + cur.determinant_Sigma_x = leg.determinant_Sigma_x; + copyArr2D(cur.Sigma_x_inv, leg.Sigma_x_inv); + cur.log_determinant_Sigma_x = leg.log_determinant_Sigma_x; + cur.subcluster_spread_factor_numerator = leg.subcluster_spread_factor_numerator; + cur.subcluster_spread_factor_denominator = leg.subcluster_spread_factor_denominator; + cur.mu_e = leg.mu_e; + cur.sigma_e_squared = leg.sigma_e_squared; + return cur; +} + +::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg) { + ::cbPKT_SS_DETECT cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.fThreshold = leg.fThreshold; + cur.fMultiplier = leg.fMultiplier; + return cur; +} + +::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) { + ::cbPKT_SS_ARTIF_REJECT cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.nMaxSimulChans = leg.nMaxSimulChans; + cur.nRefractoryCount = leg.nRefractoryCount; + return cur; +} + +::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) { + ::cbPKT_SS_NOISE_BOUNDARY cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + copyArr(cur.afc, leg.afc); + copyArr2D(cur.afS, leg.afS); + return cur; +} + +::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) { + ::cbPKT_SS_STATISTICS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.nUpdateSpikes = leg.nUpdateSpikes; + cur.nAutoalg = leg.nAutoalg; + cur.nMode = leg.nMode; + cur.fMinClusterPairSpreadFactor = leg.fMinClusterPairSpreadFactor; + cur.fMaxSubclusterSpreadFactor = leg.fMaxSubclusterSpreadFactor; + cur.fMinClusterHistCorrMajMeasure = leg.fMinClusterHistCorrMajMeasure; + cur.fMaxClusterPairHistCorrMajMeasure = leg.fMaxClusterPairHistCorrMajMeasure; + cur.fClusterHistValleyPercentage = leg.fClusterHistValleyPercentage; + cur.fClusterHistClosePeakPercentage = leg.fClusterHistClosePeakPercentage; + cur.fClusterHistMinPeakPercentage = leg.fClusterHistMinPeakPercentage; + cur.nWaveBasisSize = leg.nWaveBasisSize; + cur.nWaveSampleSize = leg.nWaveSampleSize; + return cur; +} + +::cbAdaptControl fromLegacy(const cbAdaptControl& leg) { + ::cbAdaptControl cur{}; + cur.nMode = leg.nMode; + cur.fTimeOutMinutes = leg.fTimeOutMinutes; + cur.fElapsedMinutes = leg.fElapsedMinutes; + return cur; +} + +::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg) { + ::cbPKT_SS_STATUS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats); + cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits); + return cur; +} + +::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg) { + ::cbproto::SpikeSorting cur{}; + copyArr(cur.basis, leg.asBasis, fromLegacy); + copyArr2D(cur.models, leg.asSortModel, fromLegacy); + cur.detect = fromLegacy(leg.pktDetect); + cur.artifact_reject = fromLegacy(leg.pktArtifReject); + copyArr(cur.noise_boundary, leg.pktNoiseBoundary, fromLegacy); + cur.statistics = fromLegacy(leg.pktStatistics); + cur.status = fromLegacy(leg.pktStatus); + return cur; +} + +::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg) { + ::cbPKT_NTRODEINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.ntrode = leg.ntrode; + copyArr(cur.label, leg.label); + copyArr2D(cur.ellipses, leg.ellipses, fromLegacy); + cur.nSite = leg.nSite; + cur.fs = leg.fs; + copyArr(cur.nChan, leg.nChan); + return cur; +} + +::cbWaveformData fromLegacy(const cbWaveformData& leg) { + ::cbWaveformData cur{}; + cur.offset = leg.offset; // aka sineFrequency + cur.seq = leg.seq; // aka sineAmplitude + cur.seqTotal = leg.seqTotal; + cur.phases = leg.phases; + copyArr(cur.duration, leg.duration); + copyArr(cur.amplitude, leg.amplitude); + return cur; +} + +::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) { + ::cbPKT_AOUT_WAVEFORM cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.repeats = leg.repeats; + cur.trig = leg.trig; + cur.trigInst = leg.trigInst; + cur.trigChan = leg.trigChan; + cur.trigValue = leg.trigValue; + cur.trigNum = leg.trigNum; + cur.active = leg.active; + cur.wave = fromLegacy(leg.wave); + return cur; +} + +::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg) { + ::cbPKT_LNC cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.lncFreq = leg.lncFreq; + cur.lncRefChan = leg.lncRefChan; + cur.lncGlobalMode = leg.lncGlobalMode; + return cur; +} + +::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) { + ::cbPKT_NPLAY cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.ftime = leg.ftime; // aka opt + cur.stime = leg.stime; + cur.etime = leg.etime; + cur.val = leg.val; + cur.mode = leg.mode; + cur.flags = leg.flags; + cur.speed = leg.speed; + copyArr(cur.fname, leg.fname); + return cur; +} + +::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg) { + ::cbVIDEOSOURCE cur{}; + copyArr(cur.name, leg.name); + cur.fps = leg.fps; + return cur; +} + +::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) { + ::cbTRACKOBJ cur{}; + copyArr(cur.name, leg.name); + cur.type = leg.type; + cur.pointCount = leg.pointCount; + return cur; +} + +::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) { + ::cbPKT_FILECFG cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.options = leg.options; + cur.duration = leg.duration; + cur.recording = leg.recording; + cur.extctrl = leg.extctrl; + copyArr(cur.username, leg.username); + copyArr(cur.filename, leg.filename); // aka datetime + copyArr(cur.comment, leg.comment); + return cur; +} + +cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) { + cbPKT_HEADER leg{}; + leg.time = cur.time; + leg.chid = cur.chid; + leg.type = cur.type; + leg.dlen = cur.dlen; + leg.instrument = cur.instrument; + leg.reserved = cur.reserved; + return leg; +} + +cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) { + cbPKT_SYSINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.sysfreq = cur.sysfreq; + leg.spikelen = cur.spikelen; + leg.spikepre = cur.spikepre; + leg.resetque = cur.resetque; + leg.runlevel = cur.runlevel; + leg.runflags = cur.runflags; + return leg; +} + +cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) { + cbPKT_PROCINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.idcode = cur.idcode; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; + leg.bankcount = cur.bankcount; + leg.groupcount = cur.groupcount; + leg.filtcount = cur.filtcount; + leg.sortcount = cur.sortcount; + leg.unitcount = cur.unitcount; + leg.hoopcount = cur.hoopcount; + leg.reserved = cur.reserved; + leg.version = cur.version; + return leg; +} + +cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) { + cbPKT_BANKINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + copyArr(leg.label, cur.label); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; + return leg; +} + +cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) { + cbPKT_GROUPINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.group = cur.group; + copyArr(leg.label, cur.label); + leg.period = cur.period; + leg.length = cur.length; + copyArr(leg.list, cur.list); + return leg; +} + +cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) { + cbPKT_FILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.filt = cur.filt; + copyArr(leg.label, cur.label); + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; + leg.gain = cur.gain; + leg.sos1a1 = cur.sos1a1; + leg.sos1a2 = cur.sos1a2; + leg.sos1b1 = cur.sos1b1; + leg.sos1b2 = cur.sos1b2; + leg.sos2a1 = cur.sos2a1; + leg.sos2a2 = cur.sos2a2; + leg.sos2b1 = cur.sos2b1; + leg.sos2b2 = cur.sos2b2; + return leg; +} + +cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) { + cbPKT_ADAPTFILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.dLearningRate = cur.dLearningRate; + leg.nRefChan1 = cur.nRefChan1; + leg.nRefChan2 = cur.nRefChan2; + return leg; +} + +cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur) { + cbPKT_REFELECFILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.nRefChan = cur.nRefChan; + return leg; +} + +cbSCALING toLegacy(const ::cbSCALING& cur) { + cbSCALING leg{}; + leg.digmin = cur.digmin; + leg.digmax = cur.digmax; + leg.anamin = cur.anamin; + leg.anamax = cur.anamax; + leg.anagain = cur.anagain; + copyArr(leg.anaunit, cur.anaunit); + return leg; +} + +cbFILTDESC toLegacy(const ::cbFILTDESC& cur) { + cbFILTDESC leg{}; + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; + return leg; +} + +cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) { + cbMANUALUNITMAPPING leg{}; + leg.nOverride = cur.nOverride; + copyArr(leg.afOrigin, cur.afOrigin); + copyArr2D(leg.afShape, cur.afShape); + leg.aPhi = cur.aPhi; + leg.bValid = cur.bValid; + return leg; +} + +cbHOOP toLegacy(const ::cbHOOP& cur) { + cbHOOP leg{}; + leg.valid = cur.valid; + leg.time = cur.time; + leg.min = cur.min; + leg.max = cur.max; + return leg; +} + +cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) { + cbPKT_CHANINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.term = cur.term; + leg.chancaps = cur.chancaps; + leg.doutcaps = cur.doutcaps; + leg.dinpcaps = cur.dinpcaps; + leg.aoutcaps = cur.aoutcaps; + leg.ainpcaps = cur.ainpcaps; + leg.spkcaps = cur.spkcaps; + leg.physcalin = toLegacy(cur.physcalin); + leg.phyfiltin = toLegacy(cur.phyfiltin); + leg.physcalout = toLegacy(cur.physcalout); + leg.phyfiltout = toLegacy(cur.phyfiltout); + copyArr(leg.label, cur.label); + leg.userflags = cur.userflags; + copyArr(leg.position, cur.position); + leg.scalin = toLegacy(cur.scalin); + leg.scalout = toLegacy(cur.scalout); + leg.doutopts = cur.doutopts; + leg.dinpopts = cur.dinpopts; + leg.aoutopts = cur.aoutopts; + leg.eopchar = cur.eopchar; + leg.moninst = cur.moninst; // aka lowsamples + leg.monchan = cur.monchan; // aka highsamples + leg.outvalue = cur.outvalue; // aka offset + leg.trigtype = cur.trigtype; + copyArr(leg.reserved, cur.reserved); + leg.triginst = cur.triginst; + leg.trigchan = cur.trigchan; + leg.trigval = cur.trigval; + leg.ainpopts = cur.ainpopts; + leg.lncrate = cur.lncrate; + leg.smpfilter = cur.smpfilter; + leg.smpgroup = cur.smpgroup; + leg.smpdispmin = cur.smpdispmin; + leg.smpdispmax = cur.smpdispmax; + leg.spkfilter = cur.spkfilter; + leg.spkdispmax = cur.spkdispmax; + leg.lncdispmax = cur.lncdispmax; + leg.spkopts = cur.spkopts; + leg.spkthrlevel = cur.spkthrlevel; + leg.spkthrlimit = cur.spkthrlimit; + leg.spkgroup = cur.spkgroup; + leg.amplrejpos = cur.amplrejpos; + leg.amplrejneg = cur.amplrejneg; + leg.refelecchan = cur.refelecchan; + copyArr(leg.unitmapping, cur.unitmapping, toLegacy); + copyArr2D(leg.spkhoops, cur.spkhoops, toLegacy); + return leg; +} + +cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) { + cbPKT_FS_BASIS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.fs = cur.fs; + copyArr2D(leg.basis, cur.basis); + return leg; +} + +cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) { + cbPKT_SS_MODELSET leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.unit_number = cur.unit_number; + leg.valid = cur.valid; + leg.inverted = cur.inverted; + leg.num_samples = cur.num_samples; + copyArr(leg.mu_x, cur.mu_x); + copyArr2D(leg.Sigma_x, cur.Sigma_x); + leg.determinant_Sigma_x = cur.determinant_Sigma_x; + copyArr2D(leg.Sigma_x_inv, cur.Sigma_x_inv); + leg.log_determinant_Sigma_x = cur.log_determinant_Sigma_x; + leg.subcluster_spread_factor_numerator = cur.subcluster_spread_factor_numerator; + leg.subcluster_spread_factor_denominator = cur.subcluster_spread_factor_denominator; + leg.mu_e = cur.mu_e; + leg.sigma_e_squared = cur.sigma_e_squared; + return leg; +} + +cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur) { + cbPKT_SS_DETECT leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.fThreshold = cur.fThreshold; + leg.fMultiplier = cur.fMultiplier; + return leg; +} + +cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) { + cbPKT_SS_ARTIF_REJECT leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.nMaxSimulChans = cur.nMaxSimulChans; + leg.nRefractoryCount = cur.nRefractoryCount; + return leg; +} + +cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) { + cbPKT_SS_NOISE_BOUNDARY leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + copyArr(leg.afc, cur.afc); + copyArr2D(leg.afS, cur.afS); + return leg; +} + +cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) { + cbPKT_SS_STATISTICS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.nUpdateSpikes = cur.nUpdateSpikes; + leg.nAutoalg = cur.nAutoalg; + leg.nMode = cur.nMode; + leg.fMinClusterPairSpreadFactor = cur.fMinClusterPairSpreadFactor; + leg.fMaxSubclusterSpreadFactor = cur.fMaxSubclusterSpreadFactor; + leg.fMinClusterHistCorrMajMeasure = cur.fMinClusterHistCorrMajMeasure; + leg.fMaxClusterPairHistCorrMajMeasure = cur.fMaxClusterPairHistCorrMajMeasure; + leg.fClusterHistValleyPercentage = cur.fClusterHistValleyPercentage; + leg.fClusterHistClosePeakPercentage = cur.fClusterHistClosePeakPercentage; + leg.fClusterHistMinPeakPercentage = cur.fClusterHistMinPeakPercentage; + leg.nWaveBasisSize = cur.nWaveBasisSize; + leg.nWaveSampleSize = cur.nWaveSampleSize; + return leg; +} + +cbAdaptControl toLegacy(const ::cbAdaptControl& cur) { + cbAdaptControl leg{}; + leg.nMode = cur.nMode; + leg.fTimeOutMinutes = cur.fTimeOutMinutes; + leg.fElapsedMinutes = cur.fElapsedMinutes; + return leg; +} + +cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur) { + cbPKT_SS_STATUS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cntlUnitStats = toLegacy(cur.cntlUnitStats); + leg.cntlNumUnits = toLegacy(cur.cntlNumUnits); + return leg; +} + +cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur) { + cbSPIKE_SORTING leg{}; + copyArr(leg.asBasis, cur.basis, toLegacy); + copyArr2D(leg.asSortModel, cur.models, toLegacy); + leg.pktDetect = toLegacy(cur.detect); + leg.pktArtifReject = toLegacy(cur.artifact_reject); + copyArr(leg.pktNoiseBoundary, cur.noise_boundary, toLegacy); + leg.pktStatistics = toLegacy(cur.statistics); + leg.pktStatus = toLegacy(cur.status); + return leg; +} + +cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur) { + cbPKT_NTRODEINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.ntrode = cur.ntrode; + copyArr(leg.label, cur.label); + copyArr2D(leg.ellipses, cur.ellipses, toLegacy); + leg.nSite = cur.nSite; + leg.fs = cur.fs; + copyArr(leg.nChan, cur.nChan); + return leg; +} + +cbWaveformData toLegacy(const ::cbWaveformData& cur) { + cbWaveformData leg{}; + leg.offset = cur.offset; // aka sineFrequency + leg.seq = cur.seq; // aka sineAmplitude + leg.seqTotal = cur.seqTotal; + leg.phases = cur.phases; + copyArr(leg.duration, cur.duration); + copyArr(leg.amplitude, cur.amplitude); + return leg; +} + +cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) { + cbPKT_AOUT_WAVEFORM leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.repeats = cur.repeats; + leg.trig = cur.trig; + leg.trigInst = cur.trigInst; + leg.trigChan = cur.trigChan; + leg.trigValue = cur.trigValue; + leg.trigNum = cur.trigNum; + leg.active = cur.active; + leg.wave = toLegacy(cur.wave); + return leg; +} + +cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur) { + cbPKT_LNC leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.lncFreq = cur.lncFreq; + leg.lncRefChan = cur.lncRefChan; + leg.lncGlobalMode = cur.lncGlobalMode; + return leg; +} + +cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) { + cbPKT_NPLAY leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.ftime = cur.ftime; // aka opt + leg.stime = cur.stime; + leg.etime = cur.etime; + leg.val = cur.val; + leg.mode = cur.mode; + leg.flags = cur.flags; + leg.speed = cur.speed; + copyArr(leg.fname, cur.fname); + return leg; +} + +cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) { + cbVIDEOSOURCE leg{}; + copyArr(leg.name, cur.name); + leg.fps = cur.fps; + return leg; +} + +cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) { + cbTRACKOBJ leg{}; + copyArr(leg.name, cur.name); + leg.type = cur.type; + leg.pointCount = cur.pointCount; + return leg; +} + +cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) { + cbPKT_FILECFG leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.options = cur.options; + leg.duration = cur.duration; + leg.recording = cur.recording; + leg.extctrl = cur.extctrl; + copyArr(leg.username, cur.username); + copyArr(leg.filename, cur.filename); // aka datetime + copyArr(leg.comment, cur.comment); + return leg; +} + +} // namespace central_v4_2 + +} // namespace cbshm From f121b8cac1b1097b852dea9aa01801d7d29e13de Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Tue, 26 May 2026 17:12:57 -0600 Subject: [PATCH 12/62] Add Central adapters and basic integration with ShmemSession Diffable adapter files for quickly seeing differences between versions. Implement primitive get/set methods for all planned legacy versions (v3.11, v4.0, v4.1, v4.2). Partially implement integration with ShmemSession. Functional v4.2 and v4.1 compatiblity. Theoretically functional v4.0 and v3.11 compatibility, but untested. --- src/cbshm/CMakeLists.txt | 8 + .../include/cbshm/central_types/adapters.h | 177 ++++ src/cbshm/include/cbshm/shmem_session.h | 23 +- src/cbshm/src/central_adapters/v3_11.cpp | 129 +++ src/cbshm/src/central_adapters/v4_0.cpp | 129 +++ src/cbshm/src/central_adapters/v4_1.cpp | 129 +++ src/cbshm/src/central_adapters/v4_2.cpp | 129 +++ src/cbshm/src/shmem_session.cpp | 824 ++++++++++-------- 8 files changed, 1186 insertions(+), 362 deletions(-) create mode 100644 src/cbshm/include/cbshm/central_types/adapters.h create mode 100644 src/cbshm/src/central_adapters/v3_11.cpp create mode 100644 src/cbshm/src/central_adapters/v4_0.cpp create mode 100644 src/cbshm/src/central_adapters/v4_1.cpp create mode 100644 src/cbshm/src/central_adapters/v4_2.cpp diff --git a/src/cbshm/CMakeLists.txt b/src/cbshm/CMakeLists.txt index d053e369..7f1cb364 100644 --- a/src/cbshm/CMakeLists.txt +++ b/src/cbshm/CMakeLists.txt @@ -9,6 +9,14 @@ project(cbshm # Library sources set(CBSHMEM_SOURCES src/shmem_session.cpp + src/central_translators/v4_2.cpp + src/central_translators/v4_1.cpp + src/central_translators/v4_0.cpp + src/central_translators/v3_11.cpp + src/central_adapters/v4_2.cpp + src/central_adapters/v4_1.cpp + src/central_adapters/v4_0.cpp + src/central_adapters/v3_11.cpp ) # Build as STATIC library diff --git a/src/cbshm/include/cbshm/central_types/adapters.h b/src/cbshm/include/cbshm/central_types/adapters.h new file mode 100644 index 00000000..40b07a35 --- /dev/null +++ b/src/cbshm/include/cbshm/central_types/adapters.h @@ -0,0 +1,177 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file adapters.h +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Adapters for Central-compatible shared memory access +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include + +#ifndef CBSHM_CENTRAL_TYPES_ADAPTERS_H +#define CBSHM_CENTRAL_TYPES_ADAPTERS_H + +namespace cbshm { + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Base-class adapter for Central-compatible shared memory access +/// +class CentralAdapterBase { +public: + virtual ~CentralAdapterBase() = default; + + /// Config read operations + virtual Result<::cbPKT_PROCINFO> getProcInfo(uint8_t instrument_idx) const = 0; + virtual Result<::cbPKT_BANKINFO> getBankInfo(uint8_t instrument_idx, uint32_t bank) const = 0; + virtual Result<::cbPKT_FILTINFO> getFilterInfo(uint8_t instrument_idx, uint32_t filter) const = 0; + virtual Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel) const = 0; + virtual Result<::cbPKT_SYSINFO> getSysInfo() const = 0; + virtual Result<::cbPKT_GROUPINFO> getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const = 0; + + /// Config write operations + virtual Result setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) = 0; + virtual Result setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) = 0; + virtual Result setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) = 0; + virtual Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) = 0; + virtual Result setSysInfo(const ::cbPKT_SYSINFO& info) = 0; + virtual Result setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) = 0; +}; + +namespace central_v4_2 { + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Adapter for Central-compatible shared memory access +/// +class Adapter : public CentralAdapterBase { +private: + CentralLegacyCFGBUFF* cfg; + +public: + Adapter(void* cfg_ptr); + ~Adapter() = default; + + /// Config read operations + Result<::cbPKT_PROCINFO> getProcInfo(uint8_t instrument_idx) const override; + Result<::cbPKT_BANKINFO> getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const override; + Result<::cbPKT_FILTINFO> getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const override; + Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const override; + Result<::cbPKT_SYSINFO> getSysInfo() const override; + Result<::cbPKT_GROUPINFO> getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const override; + + /// Config write operations + Result setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) override; + Result setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; + Result setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; + Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; + Result setSysInfo(const ::cbPKT_SYSINFO& info) override; + Result setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; +}; + +} // namespace central_v4_2 + +namespace central_v4_1 { + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Adapter for Central-compatible shared memory access +/// +class Adapter : public CentralAdapterBase { +private: + CentralLegacyCFGBUFF* cfg; + +public: + Adapter(void* cfg_ptr); + ~Adapter() = default; + + /// Config read operations + Result<::cbPKT_PROCINFO> getProcInfo(uint8_t instrument_idx) const override; + Result<::cbPKT_BANKINFO> getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const override; + Result<::cbPKT_FILTINFO> getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const override; + Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const override; + Result<::cbPKT_SYSINFO> getSysInfo() const override; + Result<::cbPKT_GROUPINFO> getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const override; + + /// Config write operations + Result setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) override; + Result setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; + Result setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; + Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; + Result setSysInfo(const ::cbPKT_SYSINFO& info) override; + Result setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; +}; + +} // namespace central_v4_1 + +namespace central_v4_0 { + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Adapter for Central-compatible shared memory access +/// +class Adapter : public CentralAdapterBase { +private: + CentralLegacyCFGBUFF* cfg; + +public: + Adapter(void* cfg_ptr); + ~Adapter() = default; + + /// Config read operations + Result<::cbPKT_PROCINFO> getProcInfo(uint8_t instrument_idx) const override; + Result<::cbPKT_BANKINFO> getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const override; + Result<::cbPKT_FILTINFO> getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const override; + Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const override; + Result<::cbPKT_SYSINFO> getSysInfo() const override; + Result<::cbPKT_GROUPINFO> getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const override; + + /// Config write operations + Result setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) override; + Result setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; + Result setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; + Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; + Result setSysInfo(const ::cbPKT_SYSINFO& info) override; + Result setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; +}; + +} // namespace central_v4_0 + +namespace central_v3_11 { + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Adapter for Central-compatible shared memory access +/// +class Adapter : public CentralAdapterBase { +private: + CentralLegacyCFGBUFF* cfg; + +public: + Adapter(void* cfg_ptr); + ~Adapter() = default; + + /// Config read operations + Result<::cbPKT_PROCINFO> getProcInfo(uint8_t instrument_idx) const override; + Result<::cbPKT_BANKINFO> getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const override; + Result<::cbPKT_FILTINFO> getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const override; + Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const override; + Result<::cbPKT_SYSINFO> getSysInfo() const override; + Result<::cbPKT_GROUPINFO> getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const override; + + /// Config write operations + Result setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) override; + Result setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; + Result setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; + Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; + Result setSysInfo(const ::cbPKT_SYSINFO& info) override; + Result setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; +}; + +} // namespace central_v3_11 + +} // namespace cbshm + +#endif // CBSHM_CENTRAL_TYPES_ADAPTERS_H diff --git a/src/cbshm/include/cbshm/shmem_session.h b/src/cbshm/include/cbshm/shmem_session.h index e5f12cc5..2d2fd4e6 100644 --- a/src/cbshm/include/cbshm/shmem_session.h +++ b/src/cbshm/include/cbshm/shmem_session.h @@ -20,8 +20,8 @@ #define CBSHM_SHMEM_SESSION_H // Include Central-compatible types which bring in protocol definitions -#include #include +#include #include #include #include @@ -231,13 +231,16 @@ class ShmemSession { /// @return Const pointer to native configuration buffer, or nullptr if not NATIVE layout const NativeConfigBuffer* getNativeConfigBuffer() const; - /// @brief Get direct pointer to Central legacy configuration buffer - /// @return Pointer to legacy config buffer, or nullptr if not CENTRAL_COMPAT layout - CentralLegacyCFGBUFF* getLegacyConfigBuffer(); + // TODO: REMOVE getLegacyConfigBuffer due to fundamental incompatibility with multi-version-central-compat - /// @brief Get direct pointer to Central legacy configuration buffer (const version) - /// @return Const pointer to legacy config buffer, or nullptr if not CENTRAL_COMPAT layout - const CentralLegacyCFGBUFF* getLegacyConfigBuffer() const; + // /// @brief Get direct pointer to Central legacy configuration buffer + // /// @return Pointer to legacy config buffer, or nullptr if not CENTRAL_COMPAT layout + // CentralLegacyCFGBUFF* getLegacyConfigBuffer(); + // + // /// @brief Get direct pointer to Central legacy configuration buffer (const version) + // /// @deprecated since multi-version-central-compat merged with master. + // /// @return Const pointer to legacy config buffer, or nullptr if not CENTRAL_COMPAT layout + // const CentralLegacyCFGBUFF* getLegacyConfigBuffer() const; /// @} @@ -363,13 +366,13 @@ class ShmemSession { /// @brief Get NSP status for specified instrument /// @param id Instrument ID (1-based) /// @return NSP status (INIT, NOIPADDR, NOREPLY, FOUND, INVALID) - Result getNspStatus(cbproto::InstrumentId id) const; + Result getNspStatus(cbproto::InstrumentId id) const; /// @brief Set NSP status for specified instrument /// @param id Instrument ID (1-based) /// @param status NSP status to set /// @return Result indicating success or failure - Result setNspStatus(cbproto::InstrumentId id, NSPStatus status); + Result setNspStatus(cbproto::InstrumentId id, central::NSPStatus status); /// @brief Check if system is configured as Gemini /// @return true if Gemini system, false otherwise @@ -395,7 +398,7 @@ class ShmemSession { /// @param channel Channel number (0-based) /// @param cache Output parameter to receive spike cache /// @return Result indicating success or failure - Result getSpikeCache(uint32_t channel, CentralSpikeCache& cache) const; + Result getSpikeCache(uint32_t channel, central::CentralSpikeCache& cache) const; /// @brief Get most recent spike packet from cache /// diff --git a/src/cbshm/src/central_adapters/v3_11.cpp b/src/cbshm/src/central_adapters/v3_11.cpp new file mode 100644 index 00000000..44058f4c --- /dev/null +++ b/src/cbshm/src/central_adapters/v3_11.cpp @@ -0,0 +1,129 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v3_11.cpp +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Central adapter implementation +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +namespace cbshm { + +namespace central_v3_11 { + +Adapter::Adapter(void* cfg_ptr) : cfg(static_cast(cfg_ptr)) { +} + +Result<::cbPKT_PROCINFO> Adapter::getProcInfo(uint8_t instrument_idx) const { + if (instrument_idx >= std::size(cfg->procinfo)) { + return Result<::cbPKT_PROCINFO>::error("Instrument index out of range"); + } + return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx])); +} + +Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const { + if (instrument_idx >= std::size(cfg->bankinfo)) { + return Result<::cbPKT_BANKINFO>::error("Instrument index out of range"); + } + uint32_t bank_idx = bank_num - 1; + if (bank_idx >= std::size(cfg->bankinfo[0])) { + return Result<::cbPKT_BANKINFO>::error("Bank number out of range"); + } + return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx])); +} + +Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const { + if (instrument_idx >= std::size(cfg->filtinfo)) { + return Result<::cbPKT_FILTINFO>::error("Instrument index out of range"); + } + uint32_t filter_idx = filter_num - 1; + if (filter_idx >= std::size(cfg->filtinfo[0])) { + return Result<::cbPKT_FILTINFO>::error("Filter number out of range"); + } + return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx])); +} + +Result<::cbPKT_CHANINFO> Adapter::getChanInfo(uint32_t channel_idx) const { + if (channel_idx >= std::size(cfg->chaninfo)) { + return Result<::cbPKT_CHANINFO>::error("Channel number out of range"); + } + return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx])); +} + +Result<::cbPKT_SYSINFO> Adapter::getSysInfo() const { + return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo)); +} + +Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const { + if (instrument_idx >= std::size(cfg->groupinfo)) { + return Result<::cbPKT_GROUPINFO>::error("Instrument index out of range"); + } + if (group_idx >= std::size(cfg->groupinfo[0])) { + return Result<::cbPKT_GROUPINFO>::error("Group index out of range"); + } + return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx])); +} + +Result Adapter::setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) { + if (instrument_idx >= std::size(cfg->procinfo)) { + return Result::error("Instrument index out of range"); + } + cfg->procinfo[instrument_idx] = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) { + if (instrument_idx >= std::size(cfg->bankinfo)) { + return Result::error("Instrument index out of range"); + } + uint32_t bank_idx = bank_num - 1; + if (bank_idx >= std::size(cfg->bankinfo[0])) { + return Result::error("Bank number out of range"); + } + cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) { + if (instrument_idx >= std::size(cfg->filtinfo)) { + return Result::error("Instrument index out of range"); + } + uint32_t filter_idx = filter_num - 1; + if (filter_idx >= std::size(cfg->filtinfo[0])) { + return Result::error("Filter number out of range"); + } + cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) { + if (channel_idx >= std::size(cfg->chaninfo)) { + return Result::error("Channel number out of range"); + } + cfg->chaninfo[channel_idx] = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { + cfg->sysinfo = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { + if (instrument_idx >= std::size(cfg->groupinfo)) { + return Result::error("Instrument index out of range"); + } + if (group_idx >= std::size(cfg->groupinfo[0])) { + return Result::error("Group index out of range"); + } + cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info); + return Result::ok(); +} + +} // namespace central_v3_11 + +} // namespace cbshm diff --git a/src/cbshm/src/central_adapters/v4_0.cpp b/src/cbshm/src/central_adapters/v4_0.cpp new file mode 100644 index 00000000..9c66bb16 --- /dev/null +++ b/src/cbshm/src/central_adapters/v4_0.cpp @@ -0,0 +1,129 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v4_0.cpp +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Central adapter implementation +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +namespace cbshm { + +namespace central_v4_0 { + +Adapter::Adapter(void* cfg_ptr) : cfg(static_cast(cfg_ptr)) { +} + +Result<::cbPKT_PROCINFO> Adapter::getProcInfo(uint8_t instrument_idx) const { + if (instrument_idx >= std::size(cfg->procinfo)) { + return Result<::cbPKT_PROCINFO>::error("Instrument index out of range"); + } + return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx])); +} + +Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const { + if (instrument_idx >= std::size(cfg->bankinfo)) { + return Result<::cbPKT_BANKINFO>::error("Instrument index out of range"); + } + uint32_t bank_idx = bank_num - 1; + if (bank_idx >= std::size(cfg->bankinfo[0])) { + return Result<::cbPKT_BANKINFO>::error("Bank number out of range"); + } + return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx])); +} + +Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const { + if (instrument_idx >= std::size(cfg->filtinfo)) { + return Result<::cbPKT_FILTINFO>::error("Instrument index out of range"); + } + uint32_t filter_idx = filter_num - 1; + if (filter_idx >= std::size(cfg->filtinfo[0])) { + return Result<::cbPKT_FILTINFO>::error("Filter number out of range"); + } + return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx])); +} + +Result<::cbPKT_CHANINFO> Adapter::getChanInfo(uint32_t channel_idx) const { + if (channel_idx >= std::size(cfg->chaninfo)) { + return Result<::cbPKT_CHANINFO>::error("Channel number out of range"); + } + return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx])); +} + +Result<::cbPKT_SYSINFO> Adapter::getSysInfo() const { + return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo)); +} + +Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const { + if (instrument_idx >= std::size(cfg->groupinfo)) { + return Result<::cbPKT_GROUPINFO>::error("Instrument index out of range"); + } + if (group_idx >= std::size(cfg->groupinfo[0])) { + return Result<::cbPKT_GROUPINFO>::error("Group index out of range"); + } + return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx])); +} + +Result Adapter::setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) { + if (instrument_idx >= std::size(cfg->procinfo)) { + return Result::error("Instrument index out of range"); + } + cfg->procinfo[instrument_idx] = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) { + if (instrument_idx >= std::size(cfg->bankinfo)) { + return Result::error("Instrument index out of range"); + } + uint32_t bank_idx = bank_num - 1; + if (bank_idx >= std::size(cfg->bankinfo[0])) { + return Result::error("Bank number out of range"); + } + cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) { + if (instrument_idx >= std::size(cfg->filtinfo)) { + return Result::error("Instrument index out of range"); + } + uint32_t filter_idx = filter_num - 1; + if (filter_idx >= std::size(cfg->filtinfo[0])) { + return Result::error("Filter number out of range"); + } + cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) { + if (channel_idx >= std::size(cfg->chaninfo)) { + return Result::error("Channel number out of range"); + } + cfg->chaninfo[channel_idx] = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { + cfg->sysinfo = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { + if (instrument_idx >= std::size(cfg->groupinfo)) { + return Result::error("Instrument index out of range"); + } + if (group_idx >= std::size(cfg->groupinfo[0])) { + return Result::error("Group index out of range"); + } + cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info); + return Result::ok(); +} + +} // namespace central_v4_0 + +} // namespace cbshm diff --git a/src/cbshm/src/central_adapters/v4_1.cpp b/src/cbshm/src/central_adapters/v4_1.cpp new file mode 100644 index 00000000..c040623d --- /dev/null +++ b/src/cbshm/src/central_adapters/v4_1.cpp @@ -0,0 +1,129 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v4_1.cpp +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Central adapter implementation +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +namespace cbshm { + +namespace central_v4_1 { + +Adapter::Adapter(void* cfg_ptr) : cfg(static_cast(cfg_ptr)) { +} + +Result<::cbPKT_PROCINFO> Adapter::getProcInfo(uint8_t instrument_idx) const { + if (instrument_idx >= std::size(cfg->procinfo)) { + return Result<::cbPKT_PROCINFO>::error("Instrument index out of range"); + } + return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx])); +} + +Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const { + if (instrument_idx >= std::size(cfg->bankinfo)) { + return Result<::cbPKT_BANKINFO>::error("Instrument index out of range"); + } + uint32_t bank_idx = bank_num - 1; + if (bank_idx >= std::size(cfg->bankinfo[0])) { + return Result<::cbPKT_BANKINFO>::error("Bank number out of range"); + } + return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx])); +} + +Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const { + if (instrument_idx >= std::size(cfg->filtinfo)) { + return Result<::cbPKT_FILTINFO>::error("Instrument index out of range"); + } + uint32_t filter_idx = filter_num - 1; + if (filter_idx >= std::size(cfg->filtinfo[0])) { + return Result<::cbPKT_FILTINFO>::error("Filter number out of range"); + } + return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx])); +} + +Result<::cbPKT_CHANINFO> Adapter::getChanInfo(uint32_t channel_idx) const { + if (channel_idx >= std::size(cfg->chaninfo)) { + return Result<::cbPKT_CHANINFO>::error("Channel number out of range"); + } + return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx])); +} + +Result<::cbPKT_SYSINFO> Adapter::getSysInfo() const { + return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo)); +} + +Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const { + if (instrument_idx >= std::size(cfg->groupinfo)) { + return Result<::cbPKT_GROUPINFO>::error("Instrument index out of range"); + } + if (group_idx >= std::size(cfg->groupinfo[0])) { + return Result<::cbPKT_GROUPINFO>::error("Group index out of range"); + } + return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx])); +} + +Result Adapter::setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) { + if (instrument_idx >= std::size(cfg->procinfo)) { + return Result::error("Instrument index out of range"); + } + cfg->procinfo[instrument_idx] = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) { + if (instrument_idx >= std::size(cfg->bankinfo)) { + return Result::error("Instrument index out of range"); + } + uint32_t bank_idx = bank_num - 1; + if (bank_idx >= std::size(cfg->bankinfo[0])) { + return Result::error("Bank number out of range"); + } + cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) { + if (instrument_idx >= std::size(cfg->filtinfo)) { + return Result::error("Instrument index out of range"); + } + uint32_t filter_idx = filter_num - 1; + if (filter_idx >= std::size(cfg->filtinfo[0])) { + return Result::error("Filter number out of range"); + } + cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) { + if (channel_idx >= std::size(cfg->chaninfo)) { + return Result::error("Channel number out of range"); + } + cfg->chaninfo[channel_idx] = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { + cfg->sysinfo = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { + if (instrument_idx >= std::size(cfg->groupinfo)) { + return Result::error("Instrument index out of range"); + } + if (group_idx >= std::size(cfg->groupinfo[0])) { + return Result::error("Group index out of range"); + } + cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info); + return Result::ok(); +} + +} // namespace central_v4_1 + +} // namespace cbshm diff --git a/src/cbshm/src/central_adapters/v4_2.cpp b/src/cbshm/src/central_adapters/v4_2.cpp new file mode 100644 index 00000000..01e5ea00 --- /dev/null +++ b/src/cbshm/src/central_adapters/v4_2.cpp @@ -0,0 +1,129 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v4_2.cpp +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Central adapter implementation +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +namespace cbshm { + +namespace central_v4_2 { + +Adapter::Adapter(void* cfg_ptr) : cfg(static_cast(cfg_ptr)) { +} + +Result<::cbPKT_PROCINFO> Adapter::getProcInfo(uint8_t instrument_idx) const { + if (instrument_idx >= std::size(cfg->procinfo)) { + return Result<::cbPKT_PROCINFO>::error("Instrument index out of range"); + } + return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx])); +} + +Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const { + if (instrument_idx >= std::size(cfg->bankinfo)) { + return Result<::cbPKT_BANKINFO>::error("Instrument index out of range"); + } + uint32_t bank_idx = bank_num - 1; + if (bank_idx >= std::size(cfg->bankinfo[0])) { + return Result<::cbPKT_BANKINFO>::error("Bank number out of range"); + } + return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx])); +} + +Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const { + if (instrument_idx >= std::size(cfg->filtinfo)) { + return Result<::cbPKT_FILTINFO>::error("Instrument index out of range"); + } + uint32_t filter_idx = filter_num - 1; + if (filter_idx >= std::size(cfg->filtinfo[0])) { + return Result<::cbPKT_FILTINFO>::error("Filter number out of range"); + } + return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx])); +} + +Result<::cbPKT_CHANINFO> Adapter::getChanInfo(uint32_t channel_idx) const { + if (channel_idx >= std::size(cfg->chaninfo)) { + return Result<::cbPKT_CHANINFO>::error("Channel number out of range"); + } + return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx])); +} + +Result<::cbPKT_SYSINFO> Adapter::getSysInfo() const { + return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo)); +} + +Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const { + if (instrument_idx >= std::size(cfg->groupinfo)) { + return Result<::cbPKT_GROUPINFO>::error("Instrument index out of range"); + } + if (group_idx >= std::size(cfg->groupinfo[0])) { + return Result<::cbPKT_GROUPINFO>::error("Group index out of range"); + } + return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx])); +} + +Result Adapter::setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) { + if (instrument_idx >= std::size(cfg->procinfo)) { + return Result::error("Instrument index out of range"); + } + cfg->procinfo[instrument_idx] = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) { + if (instrument_idx >= std::size(cfg->bankinfo)) { + return Result::error("Instrument index out of range"); + } + uint32_t bank_idx = bank_num - 1; + if (bank_idx >= std::size(cfg->bankinfo[0])) { + return Result::error("Bank number out of range"); + } + cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) { + if (instrument_idx >= std::size(cfg->filtinfo)) { + return Result::error("Instrument index out of range"); + } + uint32_t filter_idx = filter_num - 1; + if (filter_idx >= std::size(cfg->filtinfo[0])) { + return Result::error("Filter number out of range"); + } + cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) { + if (channel_idx >= std::size(cfg->chaninfo)) { + return Result::error("Channel number out of range"); + } + cfg->chaninfo[channel_idx] = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { + cfg->sysinfo = toLegacy(info); + return Result::ok(); +} + +Result Adapter::setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { + if (instrument_idx >= std::size(cfg->groupinfo)) { + return Result::error("Instrument index out of range"); + } + if (group_idx >= std::size(cfg->groupinfo[0])) { + return Result::error("Group index out of range"); + } + cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info); + return Result::ok(); +} + +} // namespace central_v4_2 + +} // namespace cbshm diff --git a/src/cbshm/src/shmem_session.cpp b/src/cbshm/src/shmem_session.cpp index 3bc02800..fba792ee 100644 --- a/src/cbshm/src/shmem_session.cpp +++ b/src/cbshm/src/shmem_session.cpp @@ -21,8 +21,6 @@ #include #endif -#include // TODO: REMOVE THIS!!! - #ifndef _WIN32 #include #include @@ -35,9 +33,16 @@ #endif #include -#include +#include +#include // TODO: Remove; should be hidden within the adapter +#include +#include +#include +#include +#include #include #include +#include #include #include #include // std::gcd @@ -96,6 +101,7 @@ inline uint32_t shm_load_relaxed_u32(const uint32_t* p) { struct ShmemSession::Impl { Mode mode; ShmemLayout layout; + std::unique_ptr adapter; std::string cfg_name; // Config buffer name (e.g., "cbCFGbuffer") std::string rec_name; // Receive buffer name (e.g., "cbRECbuffer") std::string xmt_name; // Transmit buffer name (e.g., "XmtGlobal") @@ -158,8 +164,104 @@ struct ShmemSession::Impl { const CentralConfigBuffer* centralCfg() const { return static_cast(cfg_buffer_raw); } NativeConfigBuffer* nativeCfg() { return static_cast(cfg_buffer_raw); } const NativeConfigBuffer* nativeCfg() const { return static_cast(cfg_buffer_raw); } - CentralLegacyCFGBUFF* legacyCfg() { return static_cast(cfg_buffer_raw); } - const CentralLegacyCFGBUFF* legacyCfg() const { return static_cast(cfg_buffer_raw); } + // CentralLegacyCFGBUFF* legacyCfg() { return static_cast(cfg_buffer_raw); } + // const CentralLegacyCFGBUFF* legacyCfg() const { return static_cast(cfg_buffer_raw); } + + // // Read-only config accessor for CENTRAL_COMPAT mode + // CentralConfigBuffer legacyCfg() const { + // switch (compat_protocol) { + // default: + // /* fallthrough */ + // case CBPROTO_PROTOCOL_CURRENT: { + // auto buf = static_cast(cfg_buffer_raw); + // + // CentralConfigBuffer cfg; + // + // cfg.version = buf->version; + // cfg.sysflags = buf->sysflags; + // // skip optiontable + // // skip colortable + // + // cfg.sysinfo = fromLegacyPktSysinfo(&buf->sysinfo); + // + // for (size_t i = 0; i < std::size(buf->procinfo); ++i) { // TODO: Handle cfg < buf + // cfg.procinfo[i] = fromLegacyPktProcinfo(&buf->procinfo[i]); + // } // TODO: Handle cfg > buf + // + // for (size_t i = 0; i < std::size(buf->bankinfo); ++i) { // TODO: Handle cfg != buf + // for (size_t j = 0; j < std::size(buf->bankinfo[i]); ++j) { + // + // cfg.bankinfo[i][j] = fromLegacyPktBankInfo(&buf->bankinfo[i][j]); + // } + // } + // + // for (size_t i = 0; i < std::size(buf->groupinfo); ++i) { // TODO: Handle cfg != buf + // for (size_t j = 0; j < std::size(buf->bankinfo[i]); ++j) { + // cfg.groupinfo[i][j] = fromLegacyPktGroupInfo(&buf->groupinfo[i][j]); + // } + // } + // + // for (size_t i = 0; i < std::size(buf->filtinfo); ++i) { // TODO: Handle cfg != buf + // for (size_t j = 0; j < std::size(buf->filtinfo[i]); ++j) { + // cfg.filtinfo[i][j] = fromLegacyPktFiltInfo(&buf->filtinfo[i][j]); + // } + // } + // + // for (size_t n = 0; n < std::size(buf->adaptinfo); ++n) { // TODO: Handle cfg < buf + // cfg.adaptinfo[n] = fromLegacyPktAdaptFiltInfo(&buf->adaptinfo[n]); + // } // TODO: Handle cfg > buf + // + // for (size_t n = 0; n < std::size(buf->refelecinfo); ++n) { // TODO: Handle cfg < buf + // cfg.refelecinfo[n] = fromLegacyPktRefElecInfo(&buf->refelecinfo[n]); + // } // TODO: Handle cfg > buf + // + // for (size_t i = 0; i < std::size(buf->chaninfo); ++i) { // TODO: Handle cfg < buf + // const auto& buf_chaninfo = buf->chaninfo[i]; + // auto& cfg_chaninfo = cfg.chaninfo[i]; + // } // TODO: Handle cfg > buf + // for (size_t n = 0; n < std::size(buf->isSortingOptions.asBasis); ++n) { // TODO: Handle cfg < buf + // const auto& buf_isSortingOptions_asBasis = buf->isSortingOptions.asBasis[n]; + // auto& cfg_isSortingOptions_asBasis = cfg.isSortingOptions.asBasis[n]; + // cfg_isSortingOptions_asBasis.cbpkt_header = fromLegacyPktHeader(&buf_isSortingOptions_asBasis.cbpkt_header); + // cfg_isSortingOptions_asBasis.chan = buf_isSortingOptions_asBasis.chan; + // cfg_isSortingOptions_asBasis.mode = buf_isSortingOptions_asBasis.mode; + // cfg_isSortingOptions_asBasis.fs = buf_isSortingOptions_asBasis.fs; + // for (size_t y = 0; y < std::size(buf_isSortingOptions_asBasis.basis); ++y) { // TODO: Handle cfg < buf + // for (size_t x = 0; x < std::size(buf_isSortingOptions_asBasis.basis[y]); ++x) { // TODO: Handle cfg < buf + // cfg_isSortingOptions_asBasis.basis[y][x] = buf_isSortingOptions_asBasis.basis[y][x]; + // } // TODO: Handle cfg > buf + // } // TODO: Handle cfg > buf + // } // TODO: Handle cfg > buf + // for (size_t i = 0; i < std::size(buf->isSortingOptions.asSortModel); ++i) { // TODO: Handle cfg != buf + // for (size_t j = 0; j < std::size(buf->isSortingOptions.asSortModel[i]); ++j) { + // const auto& buf_isSortingOptions_asSortModel = buf->isSortingOptions.asSortModel[i][j]; + // auto& cfg_isSortingOptions_asSortModel = cfg.isSortingOptions.asSortModel[i][j]; + // cfg_isSortingOptions_asSortModel.cbpkt_header = fromLegacyPktHeader(&buf_isSortingOptions_asSortModel.cbpkt_header); + // cfg_isSortingOptions_asSortModel.chan = buf_isSortingOptions_asSortModel.chan; + // cfg_isSortingOptions_asSortModel.unit_number = buf_isSortingOptions_asSortModel.unit_number; + // } + // } + // cfg.isSortingOptions.pktDetect + // cfg.isSortingOptions.pktArtifReject + // cfg.isSortingOptions.pktNoiseBoundary + // cfg.isSortingOptions.pktStatistics + // cfg.isSortingOptions.pktStatus + // break; + // } + // case CBPROTO_PROTOCOL_410: { + // // TODO: + // break; + // } + // case CBPROTO_PROTOCOL_400: { + // // TODO: + // break; + // } + // case CBPROTO_PROTOCOL_311: { + // // TODO: + // break; + // } + // } + // } // Generic receive buffer header access (header fields are at identical offsets in both layouts) uint32_t& recReceived() { @@ -195,6 +297,7 @@ struct ShmemSession::Impl { Impl() : mode(Mode::STANDALONE) , layout(ShmemLayout::CENTRAL) + , adapter(nullptr) , is_open(false) #ifdef _WIN32 , cfg_file_mapping(nullptr) @@ -236,36 +339,6 @@ struct ShmemSession::Impl { close(); } - /// @brief Compute buffer sizes based on layout - void computeBufferSizes() { - if (layout == ShmemLayout::NATIVE) { - cfg_buffer_size = sizeof(NativeConfigBuffer); - rec_buffer_size = sizeof(NativeReceiveBuffer); - xmt_buffer_size = sizeof(NativeTransmitBuffer); - xmt_local_buffer_size = sizeof(NativeTransmitBufferLocal); - status_buffer_size = sizeof(NativePCStatus); - spike_buffer_size = sizeof(NativeSpikeBuffer); - rec_buffer_len = NATIVE_cbRECBUFFLEN; - } else if (layout == ShmemLayout::CENTRAL_COMPAT) { - cfg_buffer_size = sizeof(CentralLegacyCFGBUFF); - // All other buffers use Central sizes (receive, xmt, spike, status are compatible) - rec_buffer_size = sizeof(CentralReceiveBuffer); - xmt_buffer_size = sizeof(CentralTransmitBuffer); - xmt_local_buffer_size = sizeof(CentralTransmitBufferLocal); - status_buffer_size = sizeof(CentralPCStatus); - spike_buffer_size = sizeof(CentralSpikeBuffer); - rec_buffer_len = CENTRAL_cbRECBUFFLEN; - } else { - cfg_buffer_size = sizeof(CentralConfigBuffer); - rec_buffer_size = sizeof(CentralReceiveBuffer); - xmt_buffer_size = sizeof(CentralTransmitBuffer); - xmt_local_buffer_size = sizeof(CentralTransmitBufferLocal); - status_buffer_size = sizeof(CentralPCStatus); - spike_buffer_size = sizeof(CentralSpikeBuffer); - rec_buffer_len = CENTRAL_cbRECBUFFLEN; - } - } - void close() { if (!is_open) return; @@ -355,82 +428,6 @@ struct ShmemSession::Impl { is_open = false; } - /// @brief Write a packet to the receive buffer ring. - /// - /// Cross-process publication: the consumer (CLIENT) reads head_index and - /// then reads packet bytes up to that index. On weak memory ordering - /// architectures (e.g. ARM/Apple Silicon) the head_index update must be - /// release-ordered with respect to the preceding memcpy and wrap update, - /// otherwise the consumer can observe an advanced head_index but stale - /// or partial bytes — which manifests as misaligned packets. - /// - /// Wrap padding: when a packet would not fit at @c head, the writer wraps - /// to offset 0. The skipped bytes between the previous packet and - /// @c buflen would otherwise leave the consumer's tail stranded inside - /// random gap data after the wrap. We pad the gap with a synthetic "wrap - /// marker" packet (chid=0, type=0, non-zero dlen) so the consumer can - /// advance tail through it cleanly and drop into the wrap. Wrap policy - /// also ensures the gap left after each write is either 0 or large - /// enough (>= cbPKT_HEADER_32SIZE) to fit a marker. - Result writeToReceiveBuffer(const cbPKT_GENERIC& pkt) { - if (!rec_buffer_raw) { - return Result::error("Receive buffer not initialized"); - } - - uint32_t pkt_size_words = cbPKT_HEADER_32SIZE + pkt.cbpkt_header.dlen; - - if (pkt_size_words > rec_buffer_len) { - return Result::error("Packet too large for receive buffwither"); - } - - uint32_t head = recHeadindex(); - uint32_t* buf = recBuffer(); - - // Decide whether to wrap. Wrap if either (a) the packet would not - // fit, or (b) writing it would leave a 1..3 dword tail gap that we - // cannot mark with a wrap-marker header on the next wrap. - const uint32_t end_after = head + pkt_size_words; - bool need_wrap = false; - if (end_after > rec_buffer_len) { - need_wrap = true; - } else if (end_after < rec_buffer_len && - (rec_buffer_len - end_after) < cbPKT_HEADER_32SIZE) { - need_wrap = true; - } - - if (need_wrap) { - // Pad the gap [head, buflen) with a wrap marker so the consumer - // can step over it. By the wrap-policy invariant above, gap is - // either 0 or >= cbPKT_HEADER_32SIZE. - uint32_t gap_dwords = rec_buffer_len - head; - if (gap_dwords >= cbPKT_HEADER_32SIZE) { - cbPKT_HEADER marker{}; - marker.time = 0; - marker.chid = 0; - marker.type = 0; - marker.dlen = static_cast(gap_dwords - cbPKT_HEADER_32SIZE); - marker.instrument = 0; - marker.reserved = 0; - std::memcpy(&buf[head], &marker, sizeof(cbPKT_HEADER)); - } - head = 0; - shm_store_relaxed_u32(&recHeadwrap(), recHeadwrap() + 1); - } - - const uint32_t* pkt_data = reinterpret_cast(&pkt); - std::memcpy(&buf[head], pkt_data, pkt_size_words * sizeof(uint32_t)); - - recReceived()++; - recLasttime() = pkt.cbpkt_header.time; - - // Release fence: head_index store synchronizes-with the consumer's - // acquire load, ensuring all prior writes (marker, memcpy, wrap, - // lasttime) are visible before the consumer sees the new head_index. - shm_store_release_u32(&recHeadindex(), head + pkt_size_words); - - return Result::ok(); - } - #ifndef _WIN32 /// @brief POSIX helper: open/create one shared memory segment and mmap it /// @return Result with mapped pointer on success @@ -472,8 +469,79 @@ struct ShmemSession::Impl { return Result::error("Session already open"); } + if (mode == Mode::CLIENT && layout == ShmemLayout::CENTRAL_COMPAT) { + // Detect protocol version for CLIENT + CENTRAL_COMPAT mode + auto compat_result = detectCompatProtocol(); + if (compat_result.isError()) { + return Result::error("Failed to get Central's protocol version: " + compat_result.error()); + } + compat_protocol = compat_result.value(); + } else { + // The compatibility protocol is ignored for NATIVE or CENTRAL + // layouts and is always current for STANDALONE mode. + compat_protocol = CBPROTO_PROTOCOL_CURRENT; + } + // Compute buffer sizes based on layout - computeBufferSizes(); + if (layout == ShmemLayout::NATIVE) { + cfg_buffer_size = sizeof(NativeConfigBuffer); + rec_buffer_size = sizeof(NativeReceiveBuffer); + xmt_buffer_size = sizeof(NativeTransmitBuffer); + xmt_local_buffer_size = sizeof(NativeTransmitBufferLocal); + status_buffer_size = sizeof(NativePCStatus); + spike_buffer_size = sizeof(NativeSpikeBuffer); + rec_buffer_len = NATIVE_cbRECBUFFLEN; + } else if (layout == ShmemLayout::CENTRAL_COMPAT) { + switch (compat_protocol) { + default: + /* fallthrough */ + case CBPROTO_PROTOCOL_CURRENT: + cfg_buffer_size = sizeof(central::CentralLegacyCFGBUFF); + rec_buffer_size = sizeof(central::CentralReceiveBuffer); + xmt_buffer_size = sizeof(central::CentralTransmitBuffer); + xmt_local_buffer_size = sizeof(central::CentralTransmitBufferLocal); + status_buffer_size = sizeof(central::CentralPCStatus); + spike_buffer_size = sizeof(central::CentralSpikeBuffer); + rec_buffer_len = central::cbRECBUFFLEN; + break; + case CBPROTO_PROTOCOL_410: + cfg_buffer_size = sizeof(central_v4_1::CentralLegacyCFGBUFF); + rec_buffer_size = sizeof(central_v4_1::CentralReceiveBuffer); + xmt_buffer_size = sizeof(central_v4_1::CentralTransmitBuffer); + xmt_local_buffer_size = sizeof(central_v4_1::CentralTransmitBufferLocal); + status_buffer_size = sizeof(central_v4_1::CentralPCStatus); + spike_buffer_size = sizeof(central_v4_1::CentralSpikeBuffer); + rec_buffer_len = central_v4_1::cbRECBUFFLEN; + break; + case CBPROTO_PROTOCOL_400: + cfg_buffer_size = sizeof(central_v4_0::CentralLegacyCFGBUFF); + rec_buffer_size = sizeof(central_v4_0::CentralReceiveBuffer); + xmt_buffer_size = sizeof(central_v4_0::CentralTransmitBuffer); + xmt_local_buffer_size = sizeof(central_v4_0::CentralTransmitBufferLocal); + status_buffer_size = sizeof(central_v4_0::CentralPCStatus); + spike_buffer_size = sizeof(central_v4_0::CentralSpikeBuffer); + rec_buffer_len = central_v4_0::cbRECBUFFLEN; + break; + case CBPROTO_PROTOCOL_311: + cfg_buffer_size = sizeof(central_v3_11::CentralLegacyCFGBUFF); + rec_buffer_size = sizeof(central_v3_11::CentralReceiveBuffer); + xmt_buffer_size = sizeof(central_v3_11::CentralTransmitBuffer); + xmt_local_buffer_size = sizeof(central_v3_11::CentralTransmitBufferLocal); + status_buffer_size = sizeof(central_v3_11::CentralPCStatus); + spike_buffer_size = sizeof(central_v3_11::CentralSpikeBuffer); + rec_buffer_len = central_v3_11::cbRECBUFFLEN; + break; + } + } else { + // TODO: Remove CENTRAL mode and only keep NATIVE and CENTRAL_COMPAT (?) + cfg_buffer_size = sizeof(CentralConfigBuffer); + rec_buffer_size = sizeof(central::CentralReceiveBuffer); + xmt_buffer_size = sizeof(central::CentralTransmitBuffer); + xmt_local_buffer_size = sizeof(central::CentralTransmitBufferLocal); + status_buffer_size = sizeof(central::CentralPCStatus); + spike_buffer_size = sizeof(central::CentralSpikeBuffer); + rec_buffer_len = central::cbRECBUFFLEN; + } #ifdef _WIN32 // Windows implementation @@ -614,17 +682,23 @@ struct ShmemSession::Impl { rec_tailwrap = shm_load_relaxed_u32(&recHeadwrap()); } - if (mode == Mode::CLIENT && layout == ShmemLayout::CENTRAL_COMPAT) { - // Detect protocol version for CLIENT + CENTRAL_COMPAT mode - auto compat_result = detectCompatProtocol(); - if (compat_result.isError()) { - return Result::error("Failed to detect Central's shared memory: " + compat_result.error()); - } - compat_protocol = compat_result.value(); - } else { - // The compatibility protocol is ignored for NATIVE or CENTRAL - // layouts and is always current for STANDALONE mode. - compat_protocol = CBPROTO_PROTOCOL_CURRENT; + // Select the adapter for compatiibility with Central's shared memory. + // This adapter is used in Mode::CENTRAL and Mode::CENTRAL_COMPAT. + switch (compat_protocol) { + default: + /* fallthrough */ + case CBPROTO_PROTOCOL_CURRENT: + adapter = std::make_unique(cfg_buffer_raw); + break; + case CBPROTO_PROTOCOL_410: + adapter = std::make_unique(cfg_buffer_raw); + break; + case CBPROTO_PROTOCOL_400: + adapter = std::make_unique(cfg_buffer_raw); + break; + case CBPROTO_PROTOCOL_311: + adapter = std::make_unique(cfg_buffer_raw); + break; } return Result::ok(); @@ -632,120 +706,124 @@ struct ShmemSession::Impl { /// @brief Initialize buffers for STANDALONE mode void initBuffers() { + // TODO: modes CENTRAL and CENTRAL_COMPAT should never instantiate their own buffers if (layout == ShmemLayout::NATIVE) { initNativeBuffers(); } else if (layout == ShmemLayout::CENTRAL_COMPAT) { - initLegacyBuffers(); + // // TODO: REMOVE + // initLegacyBuffers(); } else { - initCentralBuffers(); - } - } - - void initCentralBuffers() { - auto* cfg = centralCfg(); - std::memset(cfg, 0, cfg_buffer_size); - cfg->version = cbVERSION_MAJOR * 100 + cbVERSION_MINOR; - for (int i = 0; i < CENTRAL_cbMAXPROCS; ++i) { - cfg->instrument_status[i] = static_cast(InstrumentStatus::INACTIVE); - } - - // Initialize receive buffer - std::memset(rec_buffer_raw, 0, rec_buffer_size); - - // Initialize transmit buffers - auto* xmt = static_cast(xmt_buffer_raw); - std::memset(xmt, 0, xmt_buffer_size); - xmt->last_valid_index = CENTRAL_cbXMT_GLOBAL_BUFFLEN - 1; - xmt->bufferlen = CENTRAL_cbXMT_GLOBAL_BUFFLEN; - - auto* xmt_local = static_cast(xmt_local_buffer_raw); - std::memset(xmt_local, 0, xmt_local_buffer_size); - xmt_local->last_valid_index = CENTRAL_cbXMT_LOCAL_BUFFLEN - 1; - xmt_local->bufferlen = CENTRAL_cbXMT_LOCAL_BUFFLEN; - - // Initialize status buffer - auto* status = static_cast(status_buffer_raw); - std::memset(status, 0, status_buffer_size); - status->m_nNumFEChans = CENTRAL_cbNUM_FE_CHANS; - status->m_nNumAnainChans = CENTRAL_cbNUM_ANAIN_CHANS; - status->m_nNumAnalogChans = CENTRAL_cbNUM_ANALOG_CHANS; - status->m_nNumAoutChans = CENTRAL_cbNUM_ANAOUT_CHANS; - status->m_nNumAudioChans = CENTRAL_cbNUM_AUDOUT_CHANS; - status->m_nNumAnalogoutChans = CENTRAL_cbNUM_ANALOGOUT_CHANS; - status->m_nNumDiginChans = CENTRAL_cbNUM_DIGIN_CHANS; - status->m_nNumSerialChans = CENTRAL_cbNUM_SERIAL_CHANS; - status->m_nNumDigoutChans = CENTRAL_cbNUM_DIGOUT_CHANS; - status->m_nNumTotalChans = CENTRAL_cbMAXCHANS; - for (int i = 0; i < CENTRAL_cbMAXPROCS; ++i) { - status->m_nNspStatus[i] = NSPStatus::NSP_INIT; - } - - // Initialize spike cache buffer - auto* spike = static_cast(spike_buffer_raw); - std::memset(spike, 0, spike_buffer_size); - spike->chidmax = CENTRAL_cbNUM_ANALOG_CHANS; - spike->linesize = sizeof(CentralSpikeCache); - for (uint32_t ch = 0; ch < CENTRAL_cbPKT_SPKCACHELINECNT; ++ch) { - spike->cache[ch].chid = ch; - spike->cache[ch].pktcnt = CENTRAL_cbPKT_SPKCACHEPKTCNT; - spike->cache[ch].pktsize = sizeof(cbPKT_SPK); + // // TODO: REMOVE + // initCentralBuffers(); } } - void initLegacyBuffers() { - auto* cfg = legacyCfg(); - std::memset(cfg, 0, cfg_buffer_size); - cfg->version = cbVERSION_MAJOR * 100 + cbVERSION_MINOR; - - // Set procinfo version so detectCompatProtocol() identifies current format. - // In STANDALONE mode, CereLink owns the memory and writes current-format packets. - // MAKELONG(minor, major) = (major << 16) | minor - for (int i = 0; i < CENTRAL_cbMAXPROCS; ++i) { - cfg->procinfo[i].version = (cbVERSION_MAJOR << 16) | cbVERSION_MINOR; - } - - // Initialize receive buffer - std::memset(rec_buffer_raw, 0, rec_buffer_size); - - // Initialize transmit buffers (same struct as Central) - auto* xmt = static_cast(xmt_buffer_raw); - std::memset(xmt, 0, xmt_buffer_size); - xmt->last_valid_index = CENTRAL_cbXMT_GLOBAL_BUFFLEN - 1; - xmt->bufferlen = CENTRAL_cbXMT_GLOBAL_BUFFLEN; - - auto* xmt_local = static_cast(xmt_local_buffer_raw); - std::memset(xmt_local, 0, xmt_local_buffer_size); - xmt_local->last_valid_index = CENTRAL_cbXMT_LOCAL_BUFFLEN - 1; - xmt_local->bufferlen = CENTRAL_cbXMT_LOCAL_BUFFLEN; - - // Initialize status buffer (same struct as Central) - auto* status = static_cast(status_buffer_raw); - std::memset(status, 0, status_buffer_size); - status->m_nNumFEChans = CENTRAL_cbNUM_FE_CHANS; - status->m_nNumAnainChans = CENTRAL_cbNUM_ANAIN_CHANS; - status->m_nNumAnalogChans = CENTRAL_cbNUM_ANALOG_CHANS; - status->m_nNumAoutChans = CENTRAL_cbNUM_ANAOUT_CHANS; - status->m_nNumAudioChans = CENTRAL_cbNUM_AUDOUT_CHANS; - status->m_nNumAnalogoutChans = CENTRAL_cbNUM_ANALOGOUT_CHANS; - status->m_nNumDiginChans = CENTRAL_cbNUM_DIGIN_CHANS; - status->m_nNumSerialChans = CENTRAL_cbNUM_SERIAL_CHANS; - status->m_nNumDigoutChans = CENTRAL_cbNUM_DIGOUT_CHANS; - status->m_nNumTotalChans = CENTRAL_cbMAXCHANS; - for (int i = 0; i < CENTRAL_cbMAXPROCS; ++i) { - status->m_nNspStatus[i] = NSPStatus::NSP_INIT; - } - - // Initialize spike cache buffer (same struct as Central) - auto* spike = static_cast(spike_buffer_raw); - std::memset(spike, 0, spike_buffer_size); - spike->chidmax = CENTRAL_cbNUM_ANALOG_CHANS; - spike->linesize = sizeof(CentralSpikeCache); - for (uint32_t ch = 0; ch < CENTRAL_cbPKT_SPKCACHELINECNT; ++ch) { - spike->cache[ch].chid = ch; - spike->cache[ch].pktcnt = CENTRAL_cbPKT_SPKCACHEPKTCNT; - spike->cache[ch].pktsize = sizeof(cbPKT_SPK); - } - } + // void initCentralBuffers() { + // auto* cfg = centralCfg(); + // std::memset(cfg, 0, cfg_buffer_size); + // cfg->version = cbVERSION_MAJOR * 100 + cbVERSION_MINOR; + // for (int i = 0; i < central::cbMAXPROCS; ++i) { + // cfg->instrument_status[i] = static_cast(InstrumentStatus::INACTIVE); + // } + // + // // Initialize receive buffer + // std::memset(rec_buffer_raw, 0, rec_buffer_size); + // + // // Initialize transmit buffers + // auto* xmt = static_cast(xmt_buffer_raw); + // std::memset(xmt, 0, xmt_buffer_size); + // xmt->last_valid_index = central::cbXMT_GLOBAL_BUFFLEN - 1; + // xmt->bufferlen = central::cbXMT_GLOBAL_BUFFLEN; + // + // auto* xmt_local = static_cast(xmt_local_buffer_raw); + // std::memset(xmt_local, 0, xmt_local_buffer_size); + // xmt_local->last_valid_index = central::cbXMT_LOCAL_BUFFLEN - 1; + // xmt_local->bufferlen = central::cbXMT_LOCAL_BUFFLEN; + // + // // Initialize status buffer + // auto* status = static_cast(status_buffer_raw); + // std::memset(status, 0, status_buffer_size); + // status->m_nNumFEChans = central::cbNUM_FE_CHANS; + // status->m_nNumAnainChans = central::cbNUM_ANAIN_CHANS; + // status->m_nNumAnalogChans = central::cbNUM_ANALOG_CHANS; + // status->m_nNumAoutChans = central::cbNUM_ANAOUT_CHANS; + // status->m_nNumAudioChans = central::cbNUM_AUDOUT_CHANS; + // status->m_nNumAnalogoutChans = central::cbNUM_ANALOGOUT_CHANS; + // status->m_nNumDiginChans = central::cbNUM_DIGIN_CHANS; + // status->m_nNumSerialChans = central::cbNUM_SERIAL_CHANS; + // status->m_nNumDigoutChans = central::cbNUM_DIGOUT_CHANS; + // status->m_nNumTotalChans = central::cbMAXCHANS; + // for (int i = 0; i < central::cbMAXPROCS; ++i) { + // status->m_nNspStatus[i] = central::NSPStatus::NSP_INIT; + // } + // + // // Initialize spike cache buffer + // auto* spike = static_cast(spike_buffer_raw); + // std::memset(spike, 0, spike_buffer_size); + // spike->chidmax = central::cbNUM_ANALOG_CHANS; + // spike->linesize = sizeof(central::CentralSpikeCache); + // for (uint32_t ch = 0; ch < central::cbPKT_SPKCACHELINECNT; ++ch) { + // spike->cache[ch].chid = ch; + // spike->cache[ch].pktcnt = central::cbPKT_SPKCACHEPKTCNT; + // spike->cache[ch].pktsize = sizeof(central::cbPKT_SPK); + // } + // } + + // void initLegacyBuffers() { + // // TODO: FIX + // auto* cfg = legacyCfg(); + // std::memset(cfg, 0, cfg_buffer_size); + // cfg->version = cbVERSION_MAJOR * 100 + cbVERSION_MINOR; + // + // // Set procinfo version so detectCompatProtocol() identifies current format. + // // In STANDALONE mode, CereLink owns the memory and writes current-format packets. + // // MAKELONG(minor, major) = (major << 16) | minor + // for (int i = 0; i < CENTRAL_cbMAXPROCS; ++i) { + // cfg->procinfo[i].version = (cbVERSION_MAJOR << 16) | cbVERSION_MINOR; + // } + // + // // Initialize receive buffer + // std::memset(rec_buffer_raw, 0, rec_buffer_size); + // + // // Initialize transmit buffers (same struct as Central) + // auto* xmt = static_cast(xmt_buffer_raw); + // std::memset(xmt, 0, xmt_buffer_size); + // xmt->last_valid_index = CENTRAL_cbXMT_GLOBAL_BUFFLEN - 1; + // xmt->bufferlen = CENTRAL_cbXMT_GLOBAL_BUFFLEN; + // + // auto* xmt_local = static_cast(xmt_local_buffer_raw); + // std::memset(xmt_local, 0, xmt_local_buffer_size); + // xmt_local->last_valid_index = CENTRAL_cbXMT_LOCAL_BUFFLEN - 1; + // xmt_local->bufferlen = CENTRAL_cbXMT_LOCAL_BUFFLEN; + // + // // Initialize status buffer (same struct as Central) + // auto* status = static_cast(status_buffer_raw); + // std::memset(status, 0, status_buffer_size); + // status->m_nNumFEChans = CENTRAL_cbNUM_FE_CHANS; + // status->m_nNumAnainChans = CENTRAL_cbNUM_ANAIN_CHANS; + // status->m_nNumAnalogChans = CENTRAL_cbNUM_ANALOG_CHANS; + // status->m_nNumAoutChans = CENTRAL_cbNUM_ANAOUT_CHANS; + // status->m_nNumAudioChans = CENTRAL_cbNUM_AUDOUT_CHANS; + // status->m_nNumAnalogoutChans = CENTRAL_cbNUM_ANALOGOUT_CHANS; + // status->m_nNumDiginChans = CENTRAL_cbNUM_DIGIN_CHANS; + // status->m_nNumSerialChans = CENTRAL_cbNUM_SERIAL_CHANS; + // status->m_nNumDigoutChans = CENTRAL_cbNUM_DIGOUT_CHANS; + // status->m_nNumTotalChans = CENTRAL_cbMAXCHANS; + // for (int i = 0; i < CENTRAL_cbMAXPROCS; ++i) { + // status->m_nNspStatus[i] = NSPStatus::NSP_INIT; + // } + // + // // Initialize spike cache buffer (same struct as Central) + // auto* spike = static_cast(spike_buffer_raw); + // std::memset(spike, 0, spike_buffer_size); + // spike->chidmax = CENTRAL_cbNUM_ANALOG_CHANS; + // spike->linesize = sizeof(CentralSpikeCache); + // for (uint32_t ch = 0; ch < CENTRAL_cbPKT_SPKCACHELINECNT; ++ch) { + // spike->cache[ch].chid = ch; + // spike->cache[ch].pktcnt = CENTRAL_cbPKT_SPKCACHEPKTCNT; + // spike->cache[ch].pktsize = sizeof(cbPKT_SPK); + // } + // } void initNativeBuffers() { auto* cfg = nativeCfg(); @@ -785,7 +863,7 @@ struct ShmemSession::Impl { status->m_nNumSerialChans = cbNUM_SERIAL_CHANS; status->m_nNumDigoutChans = cbNUM_DIGOUT_CHANS; status->m_nNumTotalChans = NATIVE_MAXCHANS; - status->m_nNspStatus = NSPStatus::NSP_INIT; + status->m_nNspStatus = central::NSPStatus::NSP_INIT; // Initialize spike cache buffer auto* spike = static_cast(spike_buffer_raw); @@ -799,6 +877,86 @@ struct ShmemSession::Impl { } } + + /////////////////////////////////////////////////////////////////////////////////////////////////// + // Packet Routing (THE KEY FIX!) + + /// @brief Write a packet to the receive buffer ring. + /// + /// Cross-process publication: the consumer (CLIENT) reads head_index and + /// then reads packet bytes up to that index. On weak memory ordering + /// architectures (e.g. ARM/Apple Silicon) the head_index update must be + /// release-ordered with respect to the preceding memcpy and wrap update, + /// otherwise the consumer can observe an advanced head_index but stale + /// or partial bytes — which manifests as misaligned packets. + /// + /// Wrap padding: when a packet would not fit at @c head, the writer wraps + /// to offset 0. The skipped bytes between the previous packet and + /// @c buflen would otherwise leave the consumer's tail stranded inside + /// random gap data after the wrap. We pad the gap with a synthetic "wrap + /// marker" packet (chid=0, type=0, non-zero dlen) so the consumer can + /// advance tail through it cleanly and drop into the wrap. Wrap policy + /// also ensures the gap left after each write is either 0 or large + /// enough (>= cbPKT_HEADER_32SIZE) to fit a marker. + Result writeToReceiveBuffer(const cbPKT_GENERIC& pkt) { + if (!rec_buffer_raw) { + return Result::error("Receive buffer not initialized"); + } + + uint32_t pkt_size_words = cbPKT_HEADER_32SIZE + pkt.cbpkt_header.dlen; + + if (pkt_size_words > rec_buffer_len) { + return Result::error("Packet too large for receive buffwither"); + } + + uint32_t head = recHeadindex(); + uint32_t* buf = recBuffer(); + + // Decide whether to wrap. Wrap if either (a) the packet would not + // fit, or (b) writing it would leave a 1..3 dword tail gap that we + // cannot mark with a wrap-marker header on the next wrap. + const uint32_t end_after = head + pkt_size_words; + bool need_wrap = false; + if (end_after > rec_buffer_len) { + need_wrap = true; + } else if (end_after < rec_buffer_len && + (rec_buffer_len - end_after) < cbPKT_HEADER_32SIZE) { + need_wrap = true; + } + + if (need_wrap) { + // Pad the gap [head, buflen) with a wrap marker so the consumer + // can step over it. By the wrap-policy invariant above, gap is + // either 0 or >= cbPKT_HEADER_32SIZE. + uint32_t gap_dwords = rec_buffer_len - head; + if (gap_dwords >= cbPKT_HEADER_32SIZE) { + cbPKT_HEADER marker{}; + marker.time = 0; + marker.chid = 0; + marker.type = 0; + marker.dlen = static_cast(gap_dwords - cbPKT_HEADER_32SIZE); + marker.instrument = 0; + marker.reserved = 0; + std::memcpy(&buf[head], &marker, sizeof(cbPKT_HEADER)); + } + head = 0; + shm_store_relaxed_u32(&recHeadwrap(), recHeadwrap() + 1); + } + + const uint32_t* pkt_data = reinterpret_cast(&pkt); + std::memcpy(&buf[head], pkt_data, pkt_size_words * sizeof(uint32_t)); + + recReceived()++; + recLasttime() = pkt.cbpkt_header.time; + + // Release fence: head_index store synchronizes-with the consumer's + // acquire load, ensuring all prior writes (marker, memcpy, wrap, + // lasttime) are visible before the consumer sees the new head_index. + shm_store_release_u32(&recHeadindex(), head + pkt_size_words); + + return Result::ok(); + } + /// @brief Detect the protocol version from Central's binary (CENTRAL_COMPAT only). Result detectCompatProtocol() { #ifdef _WIN32 @@ -1071,7 +1229,7 @@ Result ShmemSession::getFirstActiveInstrument() const { // No instrument_status in legacy layout; return first instrument (always "active") return Result::ok(cbproto::InstrumentId::fromIndex(0)); } else { - for (uint8_t i = 0; i < CENTRAL_cbMAXPROCS; ++i) { + for (uint8_t i = 0; i < central::cbMAXPROCS; ++i) { if (m_impl->centralCfg()->instrument_status[i] == static_cast(InstrumentStatus::ACTIVE)) { return Result::ok(cbproto::InstrumentId::fromIndex(i)); } @@ -1099,11 +1257,8 @@ Result ShmemSession::getProcInfo(cbproto::InstrumentId id) const return Result::error("Native mode: single instrument only"); } return Result::ok(m_impl->nativeCfg()->procinfo); - } else if (m_impl->layout == ShmemLayout::CENTRAL_COMPAT) { - if (idx >= CENTRAL_cbMAXPROCS) return Result::error("instrument index out of range"); - return Result::ok(m_impl->legacyCfg()->procinfo[idx]); } else { - return Result::ok(m_impl->centralCfg()->procinfo[idx]); + return m_impl->adapter->getProcInfo(idx); } } @@ -1116,22 +1271,17 @@ Result ShmemSession::getBankInfo(cbproto::InstrumentId id, uint3 } uint8_t idx = id.toIndex(); - uint32_t max_banks = (m_impl->layout == ShmemLayout::NATIVE) ? NATIVE_MAXBANKS : CENTRAL_cbMAXBANKS; - - if (bank == 0 || bank > max_banks) { - return Result::error("Bank number out of range"); - } if (m_impl->layout == ShmemLayout::NATIVE) { if (idx != 0) { return Result::error("Native mode: single instrument only"); } + if (bank == 0 || bank > NATIVE_MAXBANKS) { + return Result::error("Bank number out of range"); + } return Result::ok(m_impl->nativeCfg()->bankinfo[bank - 1]); - } else if (m_impl->layout == ShmemLayout::CENTRAL_COMPAT) { - if (idx >= CENTRAL_cbMAXPROCS) return Result::error("instrument index out of range"); - return Result::ok(m_impl->legacyCfg()->bankinfo[idx][bank - 1]); } else { - return Result::ok(m_impl->centralCfg()->bankinfo[idx][bank - 1]); + return m_impl->adapter->getBankInfo(idx, bank); } } @@ -1144,22 +1294,17 @@ Result ShmemSession::getFilterInfo(cbproto::InstrumentId id, uin } uint8_t idx = id.toIndex(); - uint32_t max_filts = (m_impl->layout == ShmemLayout::NATIVE) ? NATIVE_MAXFILTS : CENTRAL_cbMAXFILTS; - - if (filter == 0 || filter > max_filts) { - return Result::error("Filter number out of range"); - } if (m_impl->layout == ShmemLayout::NATIVE) { if (idx != 0) { return Result::error("Native mode: single instrument only"); } + if (filter == 0 || filter > NATIVE_MAXFILTS) { + return Result::error("Filter number out of range"); + } return Result::ok(m_impl->nativeCfg()->filtinfo[filter - 1]); - } else if (m_impl->layout == ShmemLayout::CENTRAL_COMPAT) { - if (idx >= CENTRAL_cbMAXPROCS) return Result::error("instrument index out of range"); - return Result::ok(m_impl->legacyCfg()->filtinfo[idx][filter - 1]); } else { - return Result::ok(m_impl->centralCfg()->filtinfo[idx][filter - 1]); + return m_impl->adapter->getFilterInfo(idx, filter); } } @@ -1168,18 +1313,13 @@ Result ShmemSession::getChanInfo(uint32_t channel) const { return Result::error("Session not open"); } - uint32_t max_chans = (m_impl->layout == ShmemLayout::NATIVE) ? NATIVE_MAXCHANS : CENTRAL_cbMAXCHANS; - - if (channel >= max_chans) { - return Result::error("Channel index out of range"); - } - if (m_impl->layout == ShmemLayout::NATIVE) { + if (channel >= NATIVE_MAXCHANS) { + return Result::error("Channel index out of range"); + } return Result::ok(m_impl->nativeCfg()->chaninfo[channel]); - } else if (m_impl->layout == ShmemLayout::CENTRAL_COMPAT) { - return Result::ok(m_impl->legacyCfg()->chaninfo[channel]); } else { - return Result::ok(m_impl->centralCfg()->chaninfo[channel]); + return m_impl->adapter->getChanInfo(channel); } } @@ -1201,14 +1341,10 @@ Result ShmemSession::setProcInfo(cbproto::InstrumentId id, const cbPKT_PRO return Result::error("Native mode: single instrument only"); } m_impl->nativeCfg()->procinfo = info; - } else if (m_impl->layout == ShmemLayout::CENTRAL_COMPAT) { - if (idx >= CENTRAL_cbMAXPROCS) return Result::error("instrument index out of range"); - m_impl->legacyCfg()->procinfo[idx] = info; + return Result::ok(); } else { - m_impl->centralCfg()->procinfo[idx] = info; + return m_impl->adapter->setProcInfo(idx, info); } - - return Result::ok(); } Result ShmemSession::setBankInfo(cbproto::InstrumentId id, uint32_t bank, const cbPKT_BANKINFO& info) { @@ -1220,25 +1356,19 @@ Result ShmemSession::setBankInfo(cbproto::InstrumentId id, uint32_t bank, } uint8_t idx = id.toIndex(); - uint32_t max_banks = (m_impl->layout == ShmemLayout::NATIVE) ? NATIVE_MAXBANKS : CENTRAL_cbMAXBANKS; - - if (bank == 0 || bank > max_banks) { - return Result::error("Bank number out of range"); - } if (m_impl->layout == ShmemLayout::NATIVE) { if (idx != 0) { return Result::error("Native mode: single instrument only"); } + if (bank == 0 || bank > NATIVE_MAXBANKS) { + return Result::error("Bank number out of range"); + } m_impl->nativeCfg()->bankinfo[bank - 1] = info; - } else if (m_impl->layout == ShmemLayout::CENTRAL_COMPAT) { - if (idx >= CENTRAL_cbMAXPROCS) return Result::error("instrument index out of range"); - m_impl->legacyCfg()->bankinfo[idx][bank - 1] = info; + return Result::ok(); } else { - m_impl->centralCfg()->bankinfo[idx][bank - 1] = info; + return m_impl->adapter->setBankInfo(idx, bank, info); } - - return Result::ok(); } Result ShmemSession::setFilterInfo(cbproto::InstrumentId id, uint32_t filter, const cbPKT_FILTINFO& info) { @@ -1250,25 +1380,19 @@ Result ShmemSession::setFilterInfo(cbproto::InstrumentId id, uint32_t filt } uint8_t idx = id.toIndex(); - uint32_t max_filts = (m_impl->layout == ShmemLayout::NATIVE) ? NATIVE_MAXFILTS : CENTRAL_cbMAXFILTS; - - if (filter == 0 || filter > max_filts) { - return Result::error("Filter number out of range"); - } if (m_impl->layout == ShmemLayout::NATIVE) { if (idx != 0) { return Result::error("Native mode: single instrument only"); } + if (filter == 0 || filter > NATIVE_MAXFILTS) { + return Result::error("Filter number out of range"); + } m_impl->nativeCfg()->filtinfo[filter - 1] = info; - } else if (m_impl->layout == ShmemLayout::CENTRAL_COMPAT) { - if (idx >= CENTRAL_cbMAXPROCS) return Result::error("instrument index out of range"); - m_impl->legacyCfg()->filtinfo[idx][filter - 1] = info; + return Result::ok(); } else { - m_impl->centralCfg()->filtinfo[idx][filter - 1] = info; + return m_impl->adapter->setFilterInfo(idx, filter, info); } - - return Result::ok(); } Result ShmemSession::setChanInfo(uint32_t channel, const cbPKT_CHANINFO& info) { @@ -1276,21 +1400,15 @@ Result ShmemSession::setChanInfo(uint32_t channel, const cbPKT_CHANINFO& i return Result::error("Session not open"); } - uint32_t max_chans = (m_impl->layout == ShmemLayout::NATIVE) ? NATIVE_MAXCHANS : CENTRAL_cbMAXCHANS; - - if (channel >= max_chans) { - return Result::error("Channel index out of range"); - } - if (m_impl->layout == ShmemLayout::NATIVE) { + if (channel >= NATIVE_MAXCHANS) { + return Result::error("Channel index out of range"); + } m_impl->nativeCfg()->chaninfo[channel] = info; - } else if (m_impl->layout == ShmemLayout::CENTRAL_COMPAT) { - m_impl->legacyCfg()->chaninfo[channel] = info; + return Result::ok(); } else { - m_impl->centralCfg()->chaninfo[channel] = info; + return m_impl->adapter->setChanInfo(channel, info); } - - return Result::ok(); } Result ShmemSession::setSysInfo(const cbPKT_SYSINFO& info) { @@ -1300,13 +1418,10 @@ Result ShmemSession::setSysInfo(const cbPKT_SYSINFO& info) { if (m_impl->layout == ShmemLayout::NATIVE) { m_impl->nativeCfg()->sysinfo = info; - } else if (m_impl->layout == ShmemLayout::CENTRAL_COMPAT) { - m_impl->legacyCfg()->sysinfo = info; + return Result::ok(); } else { - m_impl->centralCfg()->sysinfo = info; + return m_impl->adapter->setSysInfo(info); } - - return Result::ok(); } Result ShmemSession::setGroupInfo(cbproto::InstrumentId id, uint32_t group, const cbPKT_GROUPINFO& info) { @@ -1327,13 +1442,8 @@ Result ShmemSession::setGroupInfo(cbproto::InstrumentId id, uint32_t group return Result::error("Group index out of range"); } m_impl->nativeCfg()->groupinfo[group] = info; - } else if (m_impl->layout == ShmemLayout::CENTRAL_COMPAT) { - if (idx >= CENTRAL_cbMAXPROCS) return Result::error("instrument index out of range"); - if (group >= CENTRAL_cbMAXGROUPS) return Result::error("Group index out of range"); - m_impl->legacyCfg()->groupinfo[idx][group] = info; } else { - if (group >= CENTRAL_cbMAXGROUPS) return Result::error("Group index out of range"); - m_impl->centralCfg()->groupinfo[idx][group] = info; + return m_impl->adapter->setGroupInfo(idx, group, info); } return Result::ok(); @@ -1370,22 +1480,22 @@ const NativeConfigBuffer* ShmemSession::getNativeConfigBuffer() const { return m_impl->nativeCfg(); } -CentralLegacyCFGBUFF* ShmemSession::getLegacyConfigBuffer() { - if (!isOpen() || m_impl->layout != ShmemLayout::CENTRAL_COMPAT) { - return nullptr; - } - return m_impl->legacyCfg(); -} +// TODO: REMOVE getLegacyConfigBuffer due to fundamental incompatibility with multi-version-central-compat -const CentralLegacyCFGBUFF* ShmemSession::getLegacyConfigBuffer() const { - if (!isOpen() || m_impl->layout != ShmemLayout::CENTRAL_COMPAT) { - return nullptr; - } - return m_impl->legacyCfg(); -} +// CentralLegacyCFGBUFF* ShmemSession::getLegacyConfigBuffer() { +// if (!isOpen() || m_impl->layout != ShmemLayout::CENTRAL_COMPAT) { +// return nullptr; +// } +// return m_impl->legacyCfg(); +// } +// +// const CentralLegacyCFGBUFF* ShmemSession::getLegacyConfigBuffer() const { +// if (!isOpen() || m_impl->layout != ShmemLayout::CENTRAL_COMPAT) { +// return nullptr; +// } +// return m_impl->legacyCfg(); +// } -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Packet Routing (THE KEY FIX!) Result ShmemSession::storePacket(const cbPKT_GENERIC& pkt) { if (!isOpen()) { @@ -1462,7 +1572,7 @@ Result ShmemSession::enqueuePacket(const cbPKT_GENERIC& pkt) { // Central's xmt consumer expects device-native format. auto gemini = isGeminiSystem(); if (gemini.isOk() && !gemini.value() && dest_hdr.time != 0) { - uint32_t sysfreq = m_impl->legacyCfg()->sysinfo.sysfreq; + uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check if (sysfreq == 0) sysfreq = 30000; uint64_t g = std::gcd(uint64_t(1000000000), uint64_t(sysfreq)); dest_hdr.time = dest_hdr.time * (sysfreq / g) / (1000000000 / g); @@ -1485,7 +1595,7 @@ Result ShmemSession::enqueuePacket(const cbPKT_GENERIC& pkt) { // Non-Gemini: convert nanosecond timestamp back to device clock ticks. auto gemini = isGeminiSystem(); if (gemini.isOk() && !gemini.value() && dest_hdr.time != 0) { - uint32_t sysfreq = m_impl->legacyCfg()->sysinfo.sysfreq; + uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check if (sysfreq == 0) sysfreq = 30000; uint64_t g = std::gcd(uint64_t(1000000000), uint64_t(sysfreq)); dest_hdr.time = dest_hdr.time * (sysfreq / g) / (1000000000 / g); @@ -1500,7 +1610,7 @@ Result ShmemSession::enqueuePacket(const cbPKT_GENERIC& pkt) { std::memcpy(translated_buf, &pkt, (cbPKT_HEADER_32SIZE + pkt.cbpkt_header.dlen) * sizeof(uint32_t)); auto& dest_hdr = *reinterpret_cast(translated_buf); - uint32_t sysfreq = m_impl->legacyCfg()->sysinfo.sysfreq; + uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check if (sysfreq == 0) sysfreq = 30000; uint64_t g = std::gcd(uint64_t(1000000000), uint64_t(sysfreq)); dest_hdr.time = dest_hdr.time * (sysfreq / g) / (1000000000 / g); @@ -1763,35 +1873,37 @@ Result ShmemSession::getNumTotalChans() const { if (m_impl->layout == ShmemLayout::NATIVE) { return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nNumTotalChans); } else { + // TODO: Use adapter instead // CENTRAL and CENTRAL_COMPAT share the same CentralPCStatus struct - return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nNumTotalChans); + return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nNumTotalChans); } } -Result ShmemSession::getNspStatus(cbproto::InstrumentId id) const { +Result ShmemSession::getNspStatus(cbproto::InstrumentId id) const { if (!m_impl || !m_impl->is_open) { - return Result::error("Session is not open"); + return Result::error("Session is not open"); } if (!m_impl->status_buffer_raw) { - return Result::error("Status buffer not initialized"); + return Result::error("Status buffer not initialized"); } uint32_t index = id.toIndex(); if (m_impl->layout == ShmemLayout::NATIVE) { if (index != 0) { - return Result::error("Native mode: single instrument only"); + return Result::error("Native mode: single instrument only"); } - return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nNspStatus); + return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nNspStatus); } else { - if (index >= CENTRAL_cbMAXPROCS) { - return Result::error("Invalid instrument ID"); + // TODO: Use adapter instead + if (index >= central::cbMAXPROCS) { + return Result::error("Invalid instrument ID"); } - return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nNspStatus[index]); + return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nNspStatus[index]); } } -Result ShmemSession::setNspStatus(cbproto::InstrumentId id, NSPStatus status) { +Result ShmemSession::setNspStatus(cbproto::InstrumentId id, central::NSPStatus status) { if (!m_impl || !m_impl->is_open) { return Result::error("Session is not open"); } @@ -1807,10 +1919,12 @@ Result ShmemSession::setNspStatus(cbproto::InstrumentId id, NSPStatus stat } static_cast(m_impl->status_buffer_raw)->m_nNspStatus = status; } else { - if (index >= CENTRAL_cbMAXPROCS) { + // TODO: Use adapter instead + if (index >= central::cbMAXPROCS) { return Result::error("Invalid instrument ID"); } - static_cast(m_impl->status_buffer_raw)->m_nNspStatus[index] = status; + static_cast(m_impl->status_buffer_raw)->m_nNspStatus[index] = status; + return Result::error("Not Implemented"); } return Result::ok(); @@ -1827,7 +1941,8 @@ Result ShmemSession::isGeminiSystem() const { if (m_impl->layout == ShmemLayout::NATIVE) { return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nGeminiSystem != 0); } else { - return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nGeminiSystem != 0); + // TODO: Use adapter instead + return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nGeminiSystem != 0); } } @@ -1842,7 +1957,8 @@ Result ShmemSession::setGeminiSystem(bool is_gemini) { if (m_impl->layout == ShmemLayout::NATIVE) { static_cast(m_impl->status_buffer_raw)->m_nGeminiSystem = is_gemini ? 1 : 0; } else { - static_cast(m_impl->status_buffer_raw)->m_nGeminiSystem = is_gemini ? 1 : 0; + // TODO: Use adapter instead + static_cast(m_impl->status_buffer_raw)->m_nGeminiSystem = is_gemini ? 1 : 0; } return Result::ok(); @@ -1851,7 +1967,7 @@ Result ShmemSession::setGeminiSystem(bool is_gemini) { /////////////////////////////////////////////////////////////////////////////////////////////////// // Spike Cache Buffer Access -Result ShmemSession::getSpikeCache(uint32_t channel, CentralSpikeCache& cache) const { +Result ShmemSession::getSpikeCache(uint32_t channel, central::CentralSpikeCache& cache) const { if (!m_impl || !m_impl->is_open) { return Result::error("Session is not open"); } @@ -1873,10 +1989,11 @@ Result ShmemSession::getSpikeCache(uint32_t channel, CentralSpikeCache& ca cache.valid = src.valid; std::memcpy(cache.spkpkt, src.spkpkt, sizeof(cbPKT_SPK) * src.pktcnt); } else { - if (channel >= CENTRAL_cbPKT_SPKCACHELINECNT) { + // TODO: Use adapter instead + if (channel >= central::cbPKT_SPKCACHELINECNT) { return Result::error("Invalid channel number"); } - auto* spike = static_cast(m_impl->spike_buffer_raw); + auto* spike = static_cast(m_impl->spike_buffer_raw); cache = spike->cache[channel]; } @@ -1904,16 +2021,19 @@ Result ShmemSession::getRecentSpike(uint32_t channel, cbPKT_SPK& spike) co spike = cache.spkpkt[recent_idx]; return Result::ok(true); } else { - if (channel >= CENTRAL_cbPKT_SPKCACHELINECNT) { + // TODO: Use adapter instead + if (channel >= central::cbPKT_SPKCACHELINECNT) { return Result::error("Invalid channel number"); } - auto* buf = static_cast(m_impl->spike_buffer_raw); + auto* buf = static_cast(m_impl->spike_buffer_raw); const auto& cache = buf->cache[channel]; if (cache.valid == 0) { return Result::ok(false); } uint32_t recent_idx = (cache.head == 0) ? (cache.pktcnt - 1) : (cache.head - 1); - spike = cache.spkpkt[recent_idx]; + // TODO: Use adapter instead + // TODO: Implement + // spike = central::fromLegacy(cache.spkpkt[recent_idx]); return Result::ok(true); } } @@ -2042,7 +2162,7 @@ PROCTIME ShmemSession::getLastTime() const { if (t != 0 && m_impl->layout == ShmemLayout::CENTRAL_COMPAT) { auto gemini = isGeminiSystem(); if (gemini.isOk() && !gemini.value()) { - uint32_t sysfreq = m_impl->legacyCfg()->sysinfo.sysfreq; + uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check if (sysfreq == 0) sysfreq = 30000; uint64_t g = std::gcd(uint64_t(1000000000), uint64_t(sysfreq)); t = t * (1000000000 / g) / (sysfreq / g); @@ -2109,7 +2229,7 @@ Result ShmemSession::readReceiveBuffer(cbPKT_GENERIC* packets, size_t max_ m_impl->status_buffer_raw) { auto gemini = isGeminiSystem(); if (gemini.isOk() && !gemini.value()) { - uint32_t sysfreq = m_impl->legacyCfg()->sysinfo.sysfreq; + uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check if (sysfreq == 0) sysfreq = 30000; uint64_t g = std::gcd(uint64_t(1000000000), uint64_t(sysfreq)); ts_num = 1000000000 / g; From 99c1a42de7acddb0ea5473a348e46debcd91bacf Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Wed, 27 May 2026 10:09:32 -0600 Subject: [PATCH 13/62] Fix array size bugs in central_translators/utils.h --- src/cbshm/src/central_translators/utils.h | 28 ++++++++++------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/cbshm/src/central_translators/utils.h b/src/cbshm/src/central_translators/utils.h index e1f8ae55..1bdfbb04 100644 --- a/src/cbshm/src/central_translators/utils.h +++ b/src/cbshm/src/central_translators/utils.h @@ -10,23 +10,23 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#include - #ifndef CBSHM_CENTRAL_TRANSLATORS_UTILS_H #define CBSHM_CENTRAL_TRANSLATORS_UTILS_H +#include + template void copyArr(T(&lhs)[lhs_n], const T(&rhs)[rhs_n]) { if (lhs_n <= rhs_n) { // Either the current array has fewer elements than the legacy array, // or they both have the same length. Either way, copy only as much // as the current array has space for. - std::memcpy(lhs, rhs, lhs_n); + std::memcpy(lhs, rhs, lhs_n * sizeof(T)); } else { // Current array has more entries! Copy everything from the legacy // array to the current array and zero out the remaining space. - std::memcpy(lhs, rhs, rhs_n); - std::memset(lhs + rhs_n, 0, lhs_n - rhs_n); + std::memcpy(lhs, rhs, rhs_n * sizeof(T)); + std::memset(lhs + rhs_n, 0, (lhs_n - rhs_n) * sizeof(T)); } } @@ -45,7 +45,7 @@ void copyArr(LHS_T(&lhs)[lhs_n], const RHS_T(&rhs)[rhs_n], LHS_T(*translation_fu for (size_t i = 0; i < rhs_n; ++i) { lhs[i] = translation_func(rhs[i]); } - std::memset(lhs + rhs_n, 0, lhs_n - rhs_n); + std::memset(lhs + rhs_n, 0, (lhs_n - rhs_n) * sizeof(LHS_T)); } } @@ -56,7 +56,7 @@ void copyArr2D(T(&lhs)[lhs_ny][lhs_nx], const T(&rhs)[rhs_ny][rhs_nx]) { // or they both have the same length. Either way, copy only as much // as the current array has space for. if (lhs_nx == rhs_nx) { - std::memcpy(lhs, rhs, lhs_ny * lhs_nx); + std::memcpy(lhs, rhs, (lhs_ny * lhs_nx) * sizeof(T)); } else { for (size_t i = 0; i < lhs_ny; ++i) { copyArr(lhs[i], rhs[i]); @@ -66,13 +66,13 @@ void copyArr2D(T(&lhs)[lhs_ny][lhs_nx], const T(&rhs)[rhs_ny][rhs_nx]) { // Current array has more entries! Copy everything from the legacy // array to the current array and zero out the remaining space. if (lhs_nx == rhs_nx) { - std::memcpy(lhs, rhs, rhs_ny * rhs_nx); + std::memcpy(lhs, rhs, (rhs_ny * rhs_nx) * sizeof(T)); } else { for (size_t i = 0; i < rhs_ny; ++i) { copyArr(lhs[i], rhs[i]); } } - std::memset(lhs + (rhs_ny * rhs_nx), 0, (lhs_ny * lhs_nx) - (rhs_ny * rhs_nx)); + std::memset(lhs + rhs_ny, 0, ((lhs_ny - rhs_ny) * lhs_nx) * sizeof(T)); } } @@ -83,19 +83,15 @@ void copyArr2D(LHS_T(&lhs)[lhs_ny][lhs_nx], const RHS_T(&rhs)[rhs_ny][rhs_nx], L // or they both have the same length. Either way, copy only as much // as the current array has space for. for (size_t i = 0; i < lhs_ny; ++i) { - for (size_t j = 0; j < lhs_nx; ++j) { - lhs[i][j] = translation_func(rhs[i][j]); - } + copyArr(lhs[i], rhs[i], translation_func); } } else { // Current array has more entries! Copy everything from the legacy // array to the current array and zero out the remaining space. for (size_t i = 0; i < rhs_ny; ++i) { - for (size_t j = 0; j < rhs_nx; ++j) { - lhs[i][j] = translation_func(rhs[i][j]); - } + copyArr(lhs[i], rhs[i], translation_func); } - std::memset(lhs + (rhs_ny * rhs_nx), 0, (lhs_ny * lhs_nx) - (rhs_ny * rhs_nx)); + std::memset(lhs + rhs_ny, 0, ((lhs_ny - rhs_ny) * lhs_nx) * sizeof(LHS_T)); } } From 1583c3d0e0970fb187922142cb9c2e1a8246e1ff Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Wed, 27 May 2026 16:38:21 -0600 Subject: [PATCH 14/62] Change type names to match Central --- src/cbshm/include/cbshm/central_types/v3_11.h | 27 +-- src/cbshm/include/cbshm/central_types/v4_0.h | 18 +- src/cbshm/include/cbshm/central_types/v4_1.h | 18 +- src/cbshm/include/cbshm/central_types/v4_2.h | 22 +- src/cbshm/include/cbshm/config_buffer.h | 216 ------------------ src/cbshm/include/cbshm/native_types.h | 49 +++- src/cbshm/include/cbshm/receive_buffer.h | 52 ----- 7 files changed, 75 insertions(+), 327 deletions(-) delete mode 100644 src/cbshm/include/cbshm/config_buffer.h delete mode 100644 src/cbshm/include/cbshm/receive_buffer.h diff --git a/src/cbshm/include/cbshm/central_types/v3_11.h b/src/cbshm/include/cbshm/central_types/v3_11.h index 9bfb77cd..612f4502 100644 --- a/src/cbshm/include/cbshm/central_types/v3_11.h +++ b/src/cbshm/include/cbshm/central_types/v3_11.h @@ -653,7 +653,7 @@ typedef struct { /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Central's actual binary layout (CentralLegacyCFGBUFF) +/// @brief Central's actual binary layout /// /// This struct matches Central's cbCFGBUFF field order EXACTLY (from cbhwlib.h). /// It is NOT the same as CereLink's cbConfigBuffer (which reorders fields and adds @@ -666,7 +666,7 @@ typedef struct { /// - isLnc: after isWaveform here, before chaninfo in CereLink /// - hwndCentral: omitted (at end, variable size, not needed) /// -struct CentralLegacyCFGBUFF { +struct cbCFGBUFF { uint32_t version; uint32_t sysflags; cbOPTIONTABLE optiontable; @@ -699,9 +699,7 @@ struct CentralLegacyCFGBUFF { /// This is stored in a separate shared memory segment (not embedded in config buffer) /// to match Central's architecture. /// -/// TODO: Rename to cbXMTBUFF (?) -/// -struct CentralTransmitBuffer { +struct cbXMTBUFF { uint32_t transmitted; ///< How many packets have been sent uint32_t headindex; ///< First empty position (write index) uint32_t tailindex; ///< One past last emptied position (read index) @@ -716,9 +714,7 @@ struct CentralTransmitBuffer { /// Smaller than Global buffer, used for cbSendLoopbackPacket() - packets meant only for /// local processes, not sent to device. /// -/// TODO: Rename to cbXMTBUFF (?) -/// -struct CentralTransmitBufferLocal { +struct cbXMTBUFFLOCAL { uint32_t transmitted; ///< How many packets have been sent uint32_t headindex; ///< First empty position (write index) uint32_t tailindex; ///< One past last emptied position (read index) @@ -751,9 +747,7 @@ typedef struct { /// Caches recent spike packets for each channel to allow quick access without /// scanning the entire receive buffer. /// -/// TODO: rename to cbSPKCACHE (?) -/// -struct CentralSpikeCache { +struct cbSPKCACHE { uint32_t chid; ///< Channel ID uint32_t pktcnt; ///< Number of packets that can be saved uint32_t pktsize; ///< Size of individual packet @@ -762,15 +756,12 @@ struct CentralSpikeCache { cbPKT_SPK spkpkt[cbPKT_SPKCACHEPKTCNT]; ///< Circular buffer of cached spikes }; -/// -/// TODO: rename to cbSPKBUFF (?) -/// -struct CentralSpikeBuffer { +struct cbSPKBUFF { uint32_t flags; ///< Status flags uint32_t chidmax; ///< Maximum channel ID uint32_t linesize; ///< Size of each cache line uint32_t spkcount; ///< Total spike count - CentralSpikeCache cache[cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches + cbSPKCACHE cache[cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -809,7 +800,7 @@ typedef struct uint16_t abyUnitSelections[cbMAXCHANS]; ///< one for each channel, channels are 0 based here, shows units selected } cbPKT_UNIT_SELECTION; -struct CentralPCStatus { +struct cbPcStatus { // Public data cbPKT_UNIT_SELECTION isSelection[cbMAXPROCS]; ///< Unit selection per instrument @@ -832,7 +823,7 @@ struct CentralPCStatus { /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Receive buffer for incoming packets (simplified for Phase 2) /// -struct CentralReceiveBuffer { +struct cbRECBUFF { uint32_t received; ///< Number of packets received PROCTIME lasttime; ///< Last timestamp uint32_t headwrap; ///< Head wrap counter diff --git a/src/cbshm/include/cbshm/central_types/v4_0.h b/src/cbshm/include/cbshm/central_types/v4_0.h index 588f492a..70de771f 100644 --- a/src/cbshm/include/cbshm/central_types/v4_0.h +++ b/src/cbshm/include/cbshm/central_types/v4_0.h @@ -653,7 +653,7 @@ typedef struct { /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Central's actual binary layout (CentralLegacyCFGBUFF) +/// @brief Central's actual binary layout /// /// This struct matches Central's cbCFGBUFF field order EXACTLY (from cbhwlib.h). /// It is NOT the same as CereLink's cbConfigBuffer (which reorders fields and adds @@ -666,7 +666,7 @@ typedef struct { /// - isLnc: after isWaveform here, before chaninfo in CereLink /// - hwndCentral: omitted (at end, variable size, not needed) /// -struct CentralLegacyCFGBUFF { +struct cbCFGBUFF { uint32_t version; uint32_t sysflags; cbOPTIONTABLE optiontable; @@ -699,7 +699,7 @@ struct CentralLegacyCFGBUFF { /// This is stored in a separate shared memory segment (not embedded in config buffer) /// to match Central's architecture. /// -struct CentralTransmitBuffer { +struct cbXMTBUFF { uint32_t transmitted; ///< How many packets have been sent uint32_t headindex; ///< First empty position (write index) uint32_t tailindex; ///< One past last emptied position (read index) @@ -714,7 +714,7 @@ struct CentralTransmitBuffer { /// Smaller than Global buffer, used for cbSendLoopbackPacket() - packets meant only for /// local processes, not sent to device. /// -struct CentralTransmitBufferLocal { +struct cbXMTBUFFLOCAL { uint32_t transmitted; ///< How many packets have been sent uint32_t headindex; ///< First empty position (write index) uint32_t tailindex; ///< One past last emptied position (read index) @@ -747,7 +747,7 @@ typedef struct { /// Caches recent spike packets for each channel to allow quick access without /// scanning the entire receive buffer. /// -struct CentralSpikeCache { +struct cbSPKCACHE { uint32_t chid; ///< Channel ID uint32_t pktcnt; ///< Number of packets that can be saved uint32_t pktsize; ///< Size of individual packet @@ -756,12 +756,12 @@ struct CentralSpikeCache { cbPKT_SPK spkpkt[cbPKT_SPKCACHEPKTCNT]; ///< Circular buffer of cached spikes }; -struct CentralSpikeBuffer { +struct cbSPKBUFF { uint32_t flags; ///< Status flags uint32_t chidmax; ///< Maximum channel ID uint32_t linesize; ///< Size of each cache line uint32_t spkcount; ///< Total spike count - CentralSpikeCache cache[cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches + cbSPKCACHE cache[cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -800,7 +800,7 @@ typedef struct uint16_t abyUnitSelections[(cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - sizeof(int32_t))]; ///< one for each channel, channels are 0 based here, shows units selected } cbPKT_UNIT_SELECTION; -struct CentralPCStatus { +struct cbPcStatus { // Public data cbPKT_UNIT_SELECTION isSelection[cbMAXPROCS]; ///< Unit selection per instrument @@ -825,7 +825,7 @@ struct CentralPCStatus { /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Receive buffer for incoming packets (simplified for Phase 2) /// -struct CentralReceiveBuffer { +struct cbRECBUFF { uint32_t received; ///< Number of packets received PROCTIME lasttime; ///< Last timestamp uint32_t headwrap; ///< Head wrap counter diff --git a/src/cbshm/include/cbshm/central_types/v4_1.h b/src/cbshm/include/cbshm/central_types/v4_1.h index 3d12436c..22447d9d 100644 --- a/src/cbshm/include/cbshm/central_types/v4_1.h +++ b/src/cbshm/include/cbshm/central_types/v4_1.h @@ -657,7 +657,7 @@ typedef struct { /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Central's actual binary layout (CentralLegacyCFGBUFF) +/// @brief Central's actual binary layout /// /// This struct matches Central's cbCFGBUFF field order EXACTLY (from cbhwlib.h). /// It is NOT the same as CereLink's cbConfigBuffer (which reorders fields and adds @@ -670,7 +670,7 @@ typedef struct { /// - isLnc: after isWaveform here, before chaninfo in CereLink /// - hwndCentral: omitted (at end, variable size, not needed) /// -struct CentralLegacyCFGBUFF { +struct cbCFGBUFF { uint32_t version; uint32_t sysflags; cbOPTIONTABLE optiontable; @@ -703,7 +703,7 @@ struct CentralLegacyCFGBUFF { /// This is stored in a separate shared memory segment (not embedded in config buffer) /// to match Central's architecture. /// -struct CentralTransmitBuffer { +struct cbXMTBUFF { uint32_t transmitted; ///< How many packets have been sent uint32_t headindex; ///< First empty position (write index) uint32_t tailindex; ///< One past last emptied position (read index) @@ -718,7 +718,7 @@ struct CentralTransmitBuffer { /// Smaller than Global buffer, used for cbSendLoopbackPacket() - packets meant only for /// local processes, not sent to device. /// -struct CentralTransmitBufferLocal { +struct cbXMTBUFFLOCAL { uint32_t transmitted; ///< How many packets have been sent uint32_t headindex; ///< First empty position (write index) uint32_t tailindex; ///< One past last emptied position (read index) @@ -751,7 +751,7 @@ typedef struct { /// Caches recent spike packets for each channel to allow quick access without /// scanning the entire receive buffer. /// -struct CentralSpikeCache { +struct cbSPKCACHE { uint32_t chid; ///< Channel ID uint32_t pktcnt; ///< Number of packets that can be saved uint32_t pktsize; ///< Size of individual packet @@ -760,12 +760,12 @@ struct CentralSpikeCache { cbPKT_SPK spkpkt[cbPKT_SPKCACHEPKTCNT]; ///< Circular buffer of cached spikes }; -struct CentralSpikeBuffer { +struct cbSPKBUFF { uint32_t flags; ///< Status flags uint32_t chidmax; ///< Maximum channel ID uint32_t linesize; ///< Size of each cache line uint32_t spkcount; ///< Total spike count - CentralSpikeCache cache[cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches + cbSPKCACHE cache[cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -804,7 +804,7 @@ typedef struct uint16_t abyUnitSelections[(cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - sizeof(int32_t))]; ///< one for each channel, channels are 0 based here, shows units selected } cbPKT_UNIT_SELECTION; -struct CentralPCStatus { +struct cbPcStatus { // Public data cbPKT_UNIT_SELECTION isSelection[cbMAXPROCS]; ///< Unit selection per instrument @@ -829,7 +829,7 @@ struct CentralPCStatus { /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Receive buffer for incoming packets (simplified for Phase 2) /// -struct CentralReceiveBuffer { +struct cbRECBUFF { uint32_t received; ///< Number of packets received PROCTIME lasttime; ///< Last timestamp uint32_t headwrap; ///< Head wrap counter diff --git a/src/cbshm/include/cbshm/central_types/v4_2.h b/src/cbshm/include/cbshm/central_types/v4_2.h index 1b1ca059..339098f6 100644 --- a/src/cbshm/include/cbshm/central_types/v4_2.h +++ b/src/cbshm/include/cbshm/central_types/v4_2.h @@ -657,7 +657,7 @@ typedef struct { /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Central's actual binary layout (CentralLegacyCFGBUFF) +/// @brief Central's actual binary layout /// /// This struct matches Central's cbCFGBUFF field order EXACTLY (from cbhwlib.h). /// It is NOT the same as CereLink's cbConfigBuffer (which reorders fields and adds @@ -670,7 +670,7 @@ typedef struct { /// - isLnc: after isWaveform here, before chaninfo in CereLink /// - hwndCentral: omitted (at end, variable size, not needed) /// -struct CentralLegacyCFGBUFF { +struct cbCFGBUFF { uint32_t version; uint32_t sysflags; cbOPTIONTABLE optiontable; @@ -703,7 +703,7 @@ struct CentralLegacyCFGBUFF { /// This is stored in a separate shared memory segment (not embedded in config buffer) /// to match Central's architecture. /// -struct CentralTransmitBuffer { +struct cbXMTBUFF { uint32_t transmitted; ///< How many packets have been sent uint32_t headindex; ///< First empty position (write index) uint32_t tailindex; ///< One past last emptied position (read index) @@ -718,7 +718,7 @@ struct CentralTransmitBuffer { /// Smaller than Global buffer, used for cbSendLoopbackPacket() - packets meant only for /// local processes, not sent to device. /// -struct CentralTransmitBufferLocal { +struct cbXMTBUFFLOCAL { uint32_t transmitted; ///< How many packets have been sent uint32_t headindex; ///< First empty position (write index) uint32_t tailindex; ///< One past last emptied position (read index) @@ -751,7 +751,7 @@ typedef struct { /// Caches recent spike packets for each channel to allow quick access without /// scanning the entire receive buffer. /// -struct CentralSpikeCache { +struct cbSPKCACHE { uint32_t chid; ///< Channel ID uint32_t pktcnt; ///< Number of packets that can be saved uint32_t pktsize; ///< Size of individual packet @@ -760,12 +760,12 @@ struct CentralSpikeCache { cbPKT_SPK spkpkt[cbPKT_SPKCACHEPKTCNT]; ///< Circular buffer of cached spikes }; -struct CentralSpikeBuffer { +struct cbSPKBUFF { uint32_t flags; ///< Status flags uint32_t chidmax; ///< Maximum channel ID uint32_t linesize; ///< Size of each cache line uint32_t spkcount; ///< Total spike count - CentralSpikeCache cache[cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches + cbSPKCACHE cache[cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -799,7 +799,7 @@ enum class NSPStatus : uint32_t { /// constexpr uint32_t cbMAXAPPWORKSPACES = 10; -struct CentralAppWorkspace { +struct APP_WORKSPACE { uint32_t m_nWorkspace; ///< Workspace number (1-based) uint32_t m_nApplication; ///< Application index (enLaunchView in Central, uint32_t for ABI compat) uint32_t m_nChannel; ///< Channel number displayed (1-based) @@ -821,7 +821,7 @@ typedef struct uint16_t abyUnitSelections[(cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - sizeof(int32_t))]; ///< one for each channel, channels are 0 based here, shows units selected } cbPKT_UNIT_SELECTION; -struct CentralPCStatus { +struct cbPcStatus { // Public data cbPKT_UNIT_SELECTION isSelection[cbMAXPROCS]; ///< Unit selection per instrument @@ -841,13 +841,13 @@ struct CentralPCStatus { NSPStatus m_nNspStatus[cbMAXPROCS]; ///< NSP status per instrument uint32_t m_nNumNTrodesPerInstrument[cbMAXPROCS];///< NTrode count per instrument uint32_t m_nGeminiSystem; ///< Gemini system flag - CentralAppWorkspace m_icAppWorkspace[cbMAXAPPWORKSPACES]; ///< App workspace config + APP_WORKSPACE m_icAppWorkspace[cbMAXAPPWORKSPACES]; ///< App workspace config }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Receive buffer for incoming packets (simplified for Phase 2) /// -struct CentralReceiveBuffer { +struct cbRECBUFF { uint32_t received; ///< Number of packets received PROCTIME lasttime; ///< Last timestamp uint32_t headwrap; ///< Head wrap counter diff --git a/src/cbshm/include/cbshm/config_buffer.h b/src/cbshm/include/cbshm/config_buffer.h deleted file mode 100644 index f64f9eba..00000000 --- a/src/cbshm/include/cbshm/config_buffer.h +++ /dev/null @@ -1,216 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file config_buffer.h -/// @author CereLink Development Team -/// @date 2025-11-14 -/// -/// @brief Device configuration buffer structure -/// -/// This file defines the configuration buffer structure used to store device state. -/// It supports up to 4 instruments (NSPs) to match Central's capabilities. -/// -/// This structure is used by cbshm: -/// For shared memory (multiple clients access same config) -/// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#ifndef CBPROTO_CONFIG_BUFFER_H -#define CBPROTO_CONFIG_BUFFER_H - -#include - -namespace cbshm { - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @name Configuration Buffer Constants -/// @{ - -/// Maximum number of instruments (NSPs) supported -/// This matches Central's multi-instrument capability (up to 4 NSPs) -constexpr uint32_t cbCONFIG_MAXPROCS = 4; - -/// Maximum number of sample rate groups per instrument -constexpr uint32_t cbCONFIG_MAXGROUPS = 8; - -/// Maximum number of digital filters per instrument -constexpr uint32_t cbCONFIG_MAXFILTS = 32; - -/// Number of front-end channels per instrument (Gemini = 768) -constexpr uint32_t cbCONFIG_NUM_FE_CHANS = 768; - -/// Number of analog input channels per instrument -constexpr uint32_t cbCONFIG_NUM_ANAIN_CHANS = (16 * cbCONFIG_MAXPROCS); - -/// Total analog channels -constexpr uint32_t cbCONFIG_NUM_ANALOG_CHANS = (cbCONFIG_NUM_FE_CHANS + cbCONFIG_NUM_ANAIN_CHANS); - -/// Number of analog output channels -constexpr uint32_t cbCONFIG_NUM_ANAOUT_CHANS = (4 * cbCONFIG_MAXPROCS); - -/// Number of audio output channels -constexpr uint32_t cbCONFIG_NUM_AUDOUT_CHANS = (2 * cbCONFIG_MAXPROCS); - -/// Total analog output channels -constexpr uint32_t cbCONFIG_NUM_ANALOGOUT_CHANS = (cbCONFIG_NUM_ANAOUT_CHANS + cbCONFIG_NUM_AUDOUT_CHANS); - -/// Number of digital input channels -constexpr uint32_t cbCONFIG_NUM_DIGIN_CHANS = (1 * cbCONFIG_MAXPROCS); - -/// Number of serial channels -constexpr uint32_t cbCONFIG_NUM_SERIAL_CHANS = (1 * cbCONFIG_MAXPROCS); - -/// Number of digital output channels -constexpr uint32_t cbCONFIG_NUM_DIGOUT_CHANS = (4 * cbCONFIG_MAXPROCS); - -/// Total channels supported -constexpr uint32_t cbCONFIG_MAXCHANS = (cbCONFIG_NUM_ANALOG_CHANS + cbCONFIG_NUM_ANALOGOUT_CHANS + \ - cbCONFIG_NUM_DIGIN_CHANS + cbCONFIG_NUM_SERIAL_CHANS + \ - cbCONFIG_NUM_DIGOUT_CHANS); - -/// Channels per bank -constexpr uint32_t cbCONFIG_CHAN_PER_BANK = 32; - -/// Number of front-end banks -constexpr uint32_t cbCONFIG_NUM_FE_BANKS = (cbCONFIG_NUM_FE_CHANS / cbCONFIG_CHAN_PER_BANK); - -/// Number of banks per type -constexpr uint32_t cbCONFIG_NUM_ANAIN_BANKS = 1; -constexpr uint32_t cbCONFIG_NUM_ANAOUT_BANKS = 1; -constexpr uint32_t cbCONFIG_NUM_AUDOUT_BANKS = 1; -constexpr uint32_t cbCONFIG_NUM_DIGIN_BANKS = 1; -constexpr uint32_t cbCONFIG_NUM_SERIAL_BANKS = 1; -constexpr uint32_t cbCONFIG_NUM_DIGOUT_BANKS = 1; - -/// Total banks per instrument -constexpr uint32_t cbCONFIG_MAXBANKS = (cbCONFIG_NUM_FE_BANKS + cbCONFIG_NUM_ANAIN_BANKS + \ - cbCONFIG_NUM_ANAOUT_BANKS + cbCONFIG_NUM_AUDOUT_BANKS + \ - cbCONFIG_NUM_DIGIN_BANKS + cbCONFIG_NUM_SERIAL_BANKS + \ - cbCONFIG_NUM_DIGOUT_BANKS); - -/// Maximum n-trodes (stereotrode minimum) for multi-instrument config buffer -constexpr uint32_t cbCONFIG_MAXNTRODES = (cbCONFIG_NUM_FE_CHANS / 2); - -/// Analog output gain channels for multi-instrument config buffer -constexpr uint32_t cbCONFIG_AOUT_NUM_GAIN_CHANS = (cbCONFIG_NUM_ANAOUT_CHANS + cbCONFIG_NUM_AUDOUT_CHANS); - -/// @} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Instrument status enumeration -/// -/// Used to track which instruments are active in the config buffer -/// -typedef enum { - cbINSTRUMENT_STATUS_INACTIVE = 0x00000000, ///< Instrument slot is not in use - cbINSTRUMENT_STATUS_ACTIVE = 0x00000001, ///< Instrument is active and has data -} cbInstrumentStatus; - -#ifdef __cplusplus -/// C++ type-safe version -enum class InstrumentStatus : uint32_t { - INACTIVE = cbINSTRUMENT_STATUS_INACTIVE, - ACTIVE = cbINSTRUMENT_STATUS_ACTIVE, -}; -#endif - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Spike Sorting Combined Structure (Config Buffer Version) -/// -/// This structure aggregates all spike sorting configuration across all channels. -/// This is NOT a packet structure - it's a config storage structure used by Central -/// to maintain the complete spike sorting state. -/// -/// IMPORTANT: Uses cbCONFIG_MAXCHANS (multi-device, 848 channels) not cbMAXCHANS (single-device, 256 channels) -/// -/// Ground truth from upstream/cbhwlib/cbhwlib.h lines 1012-1025 -/// Modified to use config buffer channel counts -/// -typedef struct { - // ***** THESE MUST BE 1ST IN THE STRUCTURE WITH MODELSET LAST OF THESE *** - // ***** SEE WriteCCFNoPrompt() *** - cbPKT_FS_BASIS asBasis[cbCONFIG_MAXCHANS]; ///< All PCA basis values (config buffer size) - cbPKT_SS_MODELSET asSortModel[cbCONFIG_MAXCHANS][cbMAXUNITS + 2]; ///< All spike sorting models (config buffer size) - - //////// Spike sorting options (not channel-specific) - cbPKT_SS_DETECT pktDetect; ///< Detection parameters - cbPKT_SS_ARTIF_REJECT pktArtifReject; ///< Artifact rejection - cbPKT_SS_NOISE_BOUNDARY pktNoiseBoundary[cbCONFIG_MAXCHANS]; ///< Noise boundaries (config buffer size) - cbPKT_SS_STATISTICS pktStatistics; ///< Statistics information - cbPKT_SS_STATUS pktStatus; ///< Spike sorting status - -} cbSPIKE_SORTING; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Device configuration buffer -/// -/// This structure stores the complete configuration state for up to 4 instruments (NSPs). -/// Configuration packets received from the device update this buffer, providing a queryable -/// "database" of the current system configuration. -/// -/// Memory layout matches Central's cbCFGBUFF for compatibility. -/// -/// Size: ~4MB (large structure, typically heap-allocated or in shared memory) -/// -typedef struct { - uint32_t version; ///< Buffer structure version - uint32_t sysflags; ///< System-wide flags - - // Instrument status (multi-instrument tracking) - uint32_t instrument_status[cbCONFIG_MAXPROCS]; ///< Active status for each instrument - - // System configuration - cbPKT_SYSINFO sysinfo; ///< System information - - // Per-instrument configuration - cbPKT_PROCINFO procinfo[cbCONFIG_MAXPROCS]; ///< Processor info - cbPKT_BANKINFO bankinfo[cbCONFIG_MAXPROCS][cbCONFIG_MAXBANKS]; ///< Bank info - cbPKT_GROUPINFO groupinfo[cbCONFIG_MAXPROCS][cbCONFIG_MAXGROUPS]; ///< Sample group info - cbPKT_FILTINFO filtinfo[cbCONFIG_MAXPROCS][cbCONFIG_MAXFILTS]; ///< Filter info - cbPKT_ADAPTFILTINFO adaptinfo[cbCONFIG_MAXPROCS]; ///< Adaptive filter settings - cbPKT_REFELECFILTINFO refelecinfo[cbCONFIG_MAXPROCS]; ///< Reference electrode filter - cbPKT_LNC isLnc[cbCONFIG_MAXPROCS]; ///< Line noise cancellation - - // Channel configuration (shared across all instruments) - cbPKT_CHANINFO chaninfo[cbCONFIG_MAXCHANS]; ///< Channel configuration - - // Spike sorting configuration - cbSPIKE_SORTING isSortingOptions; ///< Spike sorting parameters - - // N-Trode configuration (stereotrode, tetrode, etc.) - cbPKT_NTRODEINFO isNTrodeInfo[cbCONFIG_MAXNTRODES]; ///< N-Trode information - - // Analog output waveform configuration - cbPKT_AOUT_WAVEFORM isWaveform[cbCONFIG_AOUT_NUM_GAIN_CHANS][cbMAX_AOUT_TRIGGER]; ///< Waveform params - - // nPlay file playback configuration - cbPKT_NPLAY isNPlay; ///< nPlay information - - // Video tracking (NeuroMotive) - cbVIDEOSOURCE isVideoSource[cbMAXVIDEOSOURCE]; ///< Video source configuration - cbTRACKOBJ isTrackObj[cbMAXTRACKOBJ]; ///< Trackable objects - - // File recording status - cbPKT_FILECFG fileinfo; ///< File recording configuration - - // Central application UI configuration (option/color tables) - cbOPTIONTABLE optiontable; ///< Option table (32 values) - cbCOLORTABLE colortable; ///< Color table (96 values) - - // Note: hwndCentral (HANDLE) is omitted - platform-specific and only used by Central -} cbConfigBuffer; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Central-compatible configuration buffer -/// -/// This is now an alias to cbConfigBuffer (defined in cbproto/config_buffer.h). -/// The structure maintains Central's cbCFGBUFF layout compatibility. -/// -/// The CENTRAL_* constants are kept for backward compatibility in this module, -/// while cbConfigBuffer uses cbCONFIG_* constants (which have the same values). -/// -/// Static asserts below verify the constants match. -/// -using CentralConfigBuffer = cbConfigBuffer; - -} // namespace cbshm - -#endif // CBPROTO_CONFIG_BUFFER_H diff --git a/src/cbshm/include/cbshm/native_types.h b/src/cbshm/include/cbshm/native_types.h index 87de941b..44086106 100644 --- a/src/cbshm/include/cbshm/native_types.h +++ b/src/cbshm/include/cbshm/native_types.h @@ -24,9 +24,6 @@ #define CBSHM_NATIVE_TYPES_H #include -#include // For cbMAXBANKS -#include // For cbRECBUFFLEN -#include #include #pragma pack(push, 1) @@ -46,8 +43,7 @@ constexpr uint32_t NATIVE_MAXFILTS = 32; constexpr uint32_t NATIVE_MAXBANKS = cbMAXBANKS; /// Receive buffer length (same formula as cbproto, using 256 FE channels) -/// This reuses cbRECBUFFLEN from receive_buffer.h -constexpr uint32_t NATIVE_cbRECBUFFLEN = cbRECBUFFLEN; +constexpr uint32_t NATIVE_cbRECBUFFLEN = cbNUM_FE_CHANS * 65536 * 4 - 1; /// Transmit buffer sizes - slots sized for cbPKT_MAX_SIZE (1024 bytes = 256 uint32_t words) /// instead of Central's cbCER_UDP_SIZE_MAX (58080 bytes = 14520 uint32_t words) @@ -56,7 +52,7 @@ constexpr uint32_t NATIVE_cbXMT_GLOBAL_BUFFLEN = (NATIVE_XMT_SLOT_WORDS * 5000 + constexpr uint32_t NATIVE_cbXMT_LOCAL_BUFFLEN = (NATIVE_XMT_SLOT_WORDS * 2000 + 2); /// Spike cache constants (one cache per native analog channel) -constexpr uint32_t NATIVE_cbPKT_SPKCACHEPKTCNT = central::cbPKT_SPKCACHEPKTCNT; +constexpr uint32_t NATIVE_cbPKT_SPKCACHEPKTCNT = 400; constexpr uint32_t NATIVE_cbPKT_SPKCACHELINECNT = NATIVE_NUM_ANALOG_CHANS; // 272 /// @} @@ -173,6 +169,27 @@ struct NativeSpikeBuffer { NativeSpikeCache cache[NATIVE_cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches }; +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Instrument status flags (bit field) +/// +/// Used to track which instruments are active in shared memory +/// +enum class InstrumentStatus : uint32_t { + INACTIVE = 0x00000000, ///< Instrument slot is not in use + ACTIVE = 0x00000001, ///< Instrument is active and has data +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief PC Status buffer (flattened from cbPcStatus class) +/// +enum class NativeNSPStatus : uint32_t { + NSP_INIT = 0, + NSP_NOIPADDR = 1, + NSP_NOREPLY = 2, + NSP_FOUND = 3, + NSP_INVALID = 4 +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Native-mode PC status (single instrument) /// @@ -191,19 +208,27 @@ struct NativePCStatus { uint32_t m_nNumSerialChans; ///< Number of serial channels uint32_t m_nNumDigoutChans; ///< Number of digital output channels uint32_t m_nNumTotalChans; ///< Total channel count - central::NSPStatus m_nNspStatus; ///< NSP status (single instrument) + NativeNSPStatus m_nNspStatus; ///< NSP status (single instrument) uint32_t m_nNumNTrodesPerInstrument; ///< NTrode count (single instrument) uint32_t m_nGeminiSystem; ///< Gemini system flag }; /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Native-mode receive buffer (reuses cbReceiveBuffer from receive_buffer.h) +/// @brief Receive buffer for incoming packets /// -/// The cbReceiveBuffer struct defined in receive_buffer.h already uses cbNUM_FE_CHANS=256, -/// so it's already native-sized. We use it directly for native mode. +/// Ring buffer that stores raw packet data received from the device. /// -/// For convenience, create a type alias: -using NativeReceiveBuffer = cbReceiveBuffer; +/// The buffer stores packets as uint32_t words, and the headindex tracks where +/// new data should be written. Packets are modified in-place (instrument ID, proc, bank) +/// before being stored. +/// +struct NativeReceiveBuffer { + uint32_t received; ///< Number of packets received + PROCTIME lasttime; ///< Last timestamp seen + uint32_t headwrap; ///< Head wrap counter (for detecting buffer wraps) + uint32_t headindex; ///< Current head index (write position) + uint32_t buffer[NATIVE_cbRECBUFFLEN]; ///< Ring buffer for packet data +}; } // namespace cbshm diff --git a/src/cbshm/include/cbshm/receive_buffer.h b/src/cbshm/include/cbshm/receive_buffer.h deleted file mode 100644 index 5f46a875..00000000 --- a/src/cbshm/include/cbshm/receive_buffer.h +++ /dev/null @@ -1,52 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file receive_buffer.h -/// @author CereLink Development Team -/// @date 2025-11-15 -/// -/// @brief Receive buffer structure for incoming packets -/// -/// Central-compatible receive buffer that can be shared between cbdev and cbshm. -/// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#ifndef CBPROTO_RECEIVE_BUFFER_H -#define CBPROTO_RECEIVE_BUFFER_H - -#include -#include - -// Ensure tight packing for shared memory structures -#pragma pack(push, 1) - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @name Receive Buffer Constants -/// @{ - -/// Receive buffer length (matches Central's calculation) -/// Formula: cbNUM_FE_CHANS * 65536 * 4 - 1 -/// This provides enough space for a ring buffer of packets from all FE channels -constexpr uint32_t cbRECBUFFLEN = cbNUM_FE_CHANS * 65536 * 4 - 1; - -/// @} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Receive buffer for incoming packets -/// -/// Ring buffer that stores raw packet data received from the device. -/// Matches Central's cbRECBUFF structure exactly. -/// -/// The buffer stores packets as uint32_t words, and the headindex tracks where -/// new data should be written. Packets are modified in-place (instrument ID, proc, bank) -/// before being stored. -/// -struct cbReceiveBuffer { - uint32_t received; ///< Number of packets received - PROCTIME lasttime; ///< Last timestamp seen - uint32_t headwrap; ///< Head wrap counter (for detecting buffer wraps) - uint32_t headindex; ///< Current head index (write position) - uint32_t buffer[cbRECBUFFLEN]; ///< Ring buffer for packet data -}; - -#pragma pack(pop) - -#endif // CBPROTO_RECEIVE_BUFFER_H From 3699222cf77f89b9e775d01b3030aa81d900e931 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Thu, 28 May 2026 14:52:46 -0600 Subject: [PATCH 15/62] Add context for translations --- .../include/cbshm/central_types/translators.h | 13 ++++++ src/cbshm/src/central_translators/utils.h | 45 +++++++------------ 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/cbshm/include/cbshm/central_types/translators.h b/src/cbshm/include/cbshm/central_types/translators.h index 44cf3fb2..3ca5d80e 100644 --- a/src/cbshm/include/cbshm/central_types/translators.h +++ b/src/cbshm/include/cbshm/central_types/translators.h @@ -19,6 +19,19 @@ namespace cbshm { +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Additional context for the translation functions +/// +/// Not all translators need this context, but it's provided to all functions so the signatures +/// remain the same. +/// +/// TODO: Move all translations to within the adapter classes as well as the translation context. +/// +struct TranslationContext { + // cbCFGBUFF + uint8_t instrument_idx; +}; + namespace central_v4_2 { ::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg); diff --git a/src/cbshm/src/central_translators/utils.h b/src/cbshm/src/central_translators/utils.h index 1bdfbb04..4062964a 100644 --- a/src/cbshm/src/central_translators/utils.h +++ b/src/cbshm/src/central_translators/utils.h @@ -5,8 +5,8 @@ /// /// @brief Common utilities for the Central-compatible object translators /// -/// leg -> Legacy Version -/// cur -> Current Version +/// lhs -> left-hand side (copy to) +/// rhs -> right-hand side (copy from) /// /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -14,36 +14,29 @@ #define CBSHM_CENTRAL_TRANSLATORS_UTILS_H #include +#include + +namespace cbshm { template void copyArr(T(&lhs)[lhs_n], const T(&rhs)[rhs_n]) { if (lhs_n <= rhs_n) { - // Either the current array has fewer elements than the legacy array, - // or they both have the same length. Either way, copy only as much - // as the current array has space for. std::memcpy(lhs, rhs, lhs_n * sizeof(T)); } else { - // Current array has more entries! Copy everything from the legacy - // array to the current array and zero out the remaining space. std::memcpy(lhs, rhs, rhs_n * sizeof(T)); std::memset(lhs + rhs_n, 0, (lhs_n - rhs_n) * sizeof(T)); } } -template -void copyArr(LHS_T(&lhs)[lhs_n], const RHS_T(&rhs)[rhs_n], LHS_T(*translation_func)(const RHS_T&)) { +template +void copyArr(LHS_T(&lhs)[lhs_n], const RHS_T(&rhs)[rhs_n], LHS_T(*translation_func)(const RHS_T&, const TranslationContext&), const TranslationContext& ctx) { if (lhs_n <= rhs_n) { - // Either the current array has fewer elements than the legacy array, - // or they both have the same length. Either way, copy only as much - // as the current array has space for. for (size_t i = 0; i < lhs_n; ++i) { - lhs[i] = translation_func(rhs[i]); + lhs[i] = translation_func(rhs[i], ctx); } } else { - // Current array has more entries! Copy everything from the legacy - // array to the current array and zero out the remaining space. for (size_t i = 0; i < rhs_n; ++i) { - lhs[i] = translation_func(rhs[i]); + lhs[i] = translation_func(rhs[i], ctx); } std::memset(lhs + rhs_n, 0, (lhs_n - rhs_n) * sizeof(LHS_T)); } @@ -52,9 +45,6 @@ void copyArr(LHS_T(&lhs)[lhs_n], const RHS_T(&rhs)[rhs_n], LHS_T(*translation_fu template void copyArr2D(T(&lhs)[lhs_ny][lhs_nx], const T(&rhs)[rhs_ny][rhs_nx]) { if (lhs_ny <= rhs_ny) { - // Either the current array has fewer elements than the legacy array, - // or they both have the same length. Either way, copy only as much - // as the current array has space for. if (lhs_nx == rhs_nx) { std::memcpy(lhs, rhs, (lhs_ny * lhs_nx) * sizeof(T)); } else { @@ -63,8 +53,6 @@ void copyArr2D(T(&lhs)[lhs_ny][lhs_nx], const T(&rhs)[rhs_ny][rhs_nx]) { } } } else { - // Current array has more entries! Copy everything from the legacy - // array to the current array and zero out the remaining space. if (lhs_nx == rhs_nx) { std::memcpy(lhs, rhs, (rhs_ny * rhs_nx) * sizeof(T)); } else { @@ -76,23 +64,20 @@ void copyArr2D(T(&lhs)[lhs_ny][lhs_nx], const T(&rhs)[rhs_ny][rhs_nx]) { } } -template -void copyArr2D(LHS_T(&lhs)[lhs_ny][lhs_nx], const RHS_T(&rhs)[rhs_ny][rhs_nx], LHS_T(*translation_func)(const RHS_T&)) { +template +void copyArr2D(LHS_T(&lhs)[lhs_ny][lhs_nx], const RHS_T(&rhs)[rhs_ny][rhs_nx], LHS_T(*translation_func)(const RHS_T&, const TranslationContext&), const TranslationContext& ctx) { if (lhs_ny <= rhs_ny) { - // Either the current array has fewer elements than the legacy array, - // or they both have the same length. Either way, copy only as much - // as the current array has space for. for (size_t i = 0; i < lhs_ny; ++i) { - copyArr(lhs[i], rhs[i], translation_func); + copyArr(lhs[i], rhs[i], translation_func, ctx); } } else { - // Current array has more entries! Copy everything from the legacy - // array to the current array and zero out the remaining space. for (size_t i = 0; i < rhs_ny; ++i) { - copyArr(lhs[i], rhs[i], translation_func); + copyArr(lhs[i], rhs[i], translation_func, ctx); } std::memset(lhs + rhs_ny, 0, ((lhs_ny - rhs_ny) * lhs_nx) * sizeof(LHS_T)); } } +} // namespace cbshm + #endif // CBSHM_CENTRAL_TRANSLATORS_UTILS_H From d5ff5168d2da9ce9f90d14c15c6c887010e01a90 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Fri, 5 Jun 2026 17:05:03 -0600 Subject: [PATCH 16/62] Implement remaining translator and adapter methods for ShmemSession Each Central adapter has access to all raw pointer buffers used by ShmemSession. These pointers are provided to the Adapter constructor. Buffer size methods are within the BootstrapAdapter so the buffer pointers are initialized before getting passed to the Adapter constructor. All translator methods must have the translation context provided so the signatures remains the same. The translator for cbCFGBUFF has a fromLegacy translator but not a toLegacy translator. This is due to cbCFGBUFF containing information for multiple instruments which is lost upon translation, thus making reversing the operation impossible without access to the original buffer. The translators for cbPcStatus also result in loss of multi-instrument information. This issue would be resolved by combining the translators with the central adapter. Translators for the spike buffer and cache are necessary for full compatibility. --- .../include/cbshm/central_types/adapters.h | 256 ++++++++- .../include/cbshm/central_types/translators.h | 531 ++++++++++-------- src/cbshm/src/central_adapters/v3_11.cpp | 154 ++++- src/cbshm/src/central_adapters/v4_0.cpp | 154 ++++- src/cbshm/src/central_adapters/v4_1.cpp | 154 ++++- src/cbshm/src/central_adapters/v4_2.cpp | 154 ++++- src/cbshm/src/central_translators/v3_11.cpp | 464 ++++++++++----- src/cbshm/src/central_translators/v4_0.cpp | 465 ++++++++++----- src/cbshm/src/central_translators/v4_1.cpp | 465 ++++++++++----- src/cbshm/src/central_translators/v4_2.cpp | 465 ++++++++++----- 10 files changed, 2409 insertions(+), 853 deletions(-) diff --git a/src/cbshm/include/cbshm/central_types/adapters.h b/src/cbshm/include/cbshm/central_types/adapters.h index 40b07a35..6c517eae 100644 --- a/src/cbshm/include/cbshm/central_types/adapters.h +++ b/src/cbshm/include/cbshm/central_types/adapters.h @@ -7,6 +7,9 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// +#ifndef CBSHM_CENTRAL_TYPES_ADAPTERS_H +#define CBSHM_CENTRAL_TYPES_ADAPTERS_H + #include #include #include @@ -15,11 +18,23 @@ #include #include -#ifndef CBSHM_CENTRAL_TYPES_ADAPTERS_H -#define CBSHM_CENTRAL_TYPES_ADAPTERS_H - namespace cbshm { +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Base-class adapter that provides information used to fetch pointers to Central's shared memory +/// +class CentralBootstrapAdapterBase { +public: + // Buffer sizes + virtual size_t getConfigBufferSize() const = 0; + virtual size_t getReceiveBufferSize() const = 0; + virtual size_t getTransmitBufferSize() const = 0; + virtual size_t getTransmitBufferLocalSize() const = 0; + virtual size_t getStatusBufferSize() const = 0; + virtual size_t getSpikeBufferSize() const = 0; + virtual size_t getReceiveBufferLen() const = 0; +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Base-class adapter for Central-compatible shared memory access /// @@ -27,13 +42,45 @@ class CentralAdapterBase { public: virtual ~CentralAdapterBase() = default; + /////////////////////////////////////////////////////////////////////////////////////////////// + // DANGER !!! + // These methods are brittle and serve as a workaround for the ShmemSession + // implementation requiring direct pointer access to the receive and transmit buffers. + + // Receive buffer access + virtual uint32_t& getRecReceived() = 0; + virtual uint64_t getRecLasttime() = 0; + virtual void setRecLasttime(uint64_t lasttime) = 0; + virtual uint32_t& getRecHeadwrapPtr() = 0; + virtual uint32_t& getRecHeadindexPtr() = 0; + virtual uint32_t* getRecBufferPtr() = 0; + + // Transmit buffer access + virtual uint32_t& getXmtTransmittedPtr() = 0; + virtual uint32_t& getXmtHeadindexPtr() = 0; + virtual uint32_t& getXmtTailindexPtr() = 0; + virtual uint32_t& getXmtLastValidIndexPtr() = 0; + virtual uint32_t& getXmtBufferlenPtr() = 0; + virtual uint32_t* getXmtBufferPtr() = 0; + + virtual uint32_t& getLocalXmtTransmittedPtr() = 0; + virtual uint32_t& getLocalXmtHeadindexPtr() = 0; + virtual uint32_t& getLocalXmtTailindexPtr() = 0; + virtual uint32_t& getLocalXmtLastValidIndexPtr() = 0; + virtual uint32_t& getLocalXmtBufferlenPtr() = 0; + virtual uint32_t* getLocalXmtBufferPtr() = 0; + + /////////////////////////////////////////////////////////////////////////////////////////////// + /// Config read operations virtual Result<::cbPKT_PROCINFO> getProcInfo(uint8_t instrument_idx) const = 0; virtual Result<::cbPKT_BANKINFO> getBankInfo(uint8_t instrument_idx, uint32_t bank) const = 0; virtual Result<::cbPKT_FILTINFO> getFilterInfo(uint8_t instrument_idx, uint32_t filter) const = 0; - virtual Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel) const = 0; + virtual Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const = 0; virtual Result<::cbPKT_SYSINFO> getSysInfo() const = 0; virtual Result<::cbPKT_GROUPINFO> getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const = 0; + virtual Result getConfigBuffer(uint8_t instrument_idx) const = 0; + virtual Result getPcStatus(uint8_t instrument_idx) const = 0; /// Config write operations virtual Result setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) = 0; @@ -42,21 +89,65 @@ class CentralAdapterBase { virtual Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) = 0; virtual Result setSysInfo(const ::cbPKT_SYSINFO& info) = 0; virtual Result setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) = 0; + virtual Result setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const = 0; // TODO: currently single-instrument only! needs to be multi-instrument safe }; namespace central_v4_2 { +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Adapter that provides information for fetching pointers to Central's shared memory +/// +class BootstrapAdapter : public CentralBootstrapAdapterBase { +public: + // Buffer sizes + size_t getConfigBufferSize() const override; + size_t getReceiveBufferSize() const override; + size_t getTransmitBufferSize() const override; + size_t getTransmitBufferLocalSize() const override; + size_t getStatusBufferSize() const override; + size_t getSpikeBufferSize() const override; + size_t getReceiveBufferLen() const override; +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Adapter for Central-compatible shared memory access /// class Adapter : public CentralAdapterBase { private: - CentralLegacyCFGBUFF* cfg; + cbCFGBUFF* cfg; + cbRECBUFF* rec; + cbXMTBUFF* xmt; + cbXMTBUFFLOCAL* xmt_local; + cbPcStatus* status; + cbSPKBUFF* spike; public: - Adapter(void* cfg_ptr); + Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr); ~Adapter() = default; + // Receive buffer access + uint32_t& getRecReceived() override; + uint64_t getRecLasttime() override; + void setRecLasttime(uint64_t lasttime) override; + uint32_t& getRecHeadwrapPtr() override; + uint32_t& getRecHeadindexPtr() override; + uint32_t* getRecBufferPtr() override; + + // Transmit buffer access + uint32_t& getXmtTransmittedPtr() override; + uint32_t& getXmtHeadindexPtr() override; + uint32_t& getXmtTailindexPtr() override; + uint32_t& getXmtLastValidIndexPtr() override; + uint32_t& getXmtBufferlenPtr() override; + uint32_t* getXmtBufferPtr() override; + + uint32_t& getLocalXmtTransmittedPtr() override; + uint32_t& getLocalXmtHeadindexPtr() override; + uint32_t& getLocalXmtTailindexPtr() override; + uint32_t& getLocalXmtLastValidIndexPtr() override; + uint32_t& getLocalXmtBufferlenPtr() override; + uint32_t* getLocalXmtBufferPtr() override; + /// Config read operations Result<::cbPKT_PROCINFO> getProcInfo(uint8_t instrument_idx) const override; Result<::cbPKT_BANKINFO> getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const override; @@ -64,6 +155,8 @@ class Adapter : public CentralAdapterBase { Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const override; Result<::cbPKT_SYSINFO> getSysInfo() const override; Result<::cbPKT_GROUPINFO> getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const override; + Result getConfigBuffer(uint8_t instrument_idx) const override; + Result getPcStatus(uint8_t instrument_idx) const override; /// Config write operations Result setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) override; @@ -72,23 +165,67 @@ class Adapter : public CentralAdapterBase { Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; Result setSysInfo(const ::cbPKT_SYSINFO& info) override; Result setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; + Result setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const override; }; } // namespace central_v4_2 namespace central_v4_1 { +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Adapter that provides information for fetching pointers to Central's shared memory +/// +class BootstrapAdapter : public CentralBootstrapAdapterBase { +public: + // Buffer sizes + size_t getConfigBufferSize() const override; + size_t getReceiveBufferSize() const override; + size_t getTransmitBufferSize() const override; + size_t getTransmitBufferLocalSize() const override; + size_t getStatusBufferSize() const override; + size_t getSpikeBufferSize() const override; + size_t getReceiveBufferLen() const override; +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Adapter for Central-compatible shared memory access /// class Adapter : public CentralAdapterBase { private: - CentralLegacyCFGBUFF* cfg; + cbCFGBUFF* cfg; + cbRECBUFF* rec; + cbXMTBUFF* xmt; + cbXMTBUFFLOCAL* xmt_local; + cbPcStatus* status; + cbSPKBUFF* spike; public: - Adapter(void* cfg_ptr); + Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr); ~Adapter() = default; + // Receive buffer access + uint32_t& getRecReceived() override; + uint64_t getRecLasttime() override; + void setRecLasttime(uint64_t lasttime) override; + uint32_t& getRecHeadwrapPtr() override; + uint32_t& getRecHeadindexPtr() override; + uint32_t* getRecBufferPtr() override; + + // Transmit buffer access + uint32_t& getXmtTransmittedPtr() override; + uint32_t& getXmtHeadindexPtr() override; + uint32_t& getXmtTailindexPtr() override; + uint32_t& getXmtLastValidIndexPtr() override; + uint32_t& getXmtBufferlenPtr() override; + uint32_t* getXmtBufferPtr() override; + + uint32_t& getLocalXmtTransmittedPtr() override; + uint32_t& getLocalXmtHeadindexPtr() override; + uint32_t& getLocalXmtTailindexPtr() override; + uint32_t& getLocalXmtLastValidIndexPtr() override; + uint32_t& getLocalXmtBufferlenPtr() override; + uint32_t* getLocalXmtBufferPtr() override; + /// Config read operations Result<::cbPKT_PROCINFO> getProcInfo(uint8_t instrument_idx) const override; Result<::cbPKT_BANKINFO> getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const override; @@ -96,6 +233,8 @@ class Adapter : public CentralAdapterBase { Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const override; Result<::cbPKT_SYSINFO> getSysInfo() const override; Result<::cbPKT_GROUPINFO> getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const override; + Result getConfigBuffer(uint8_t instrument_idx) const override; + Result getPcStatus(uint8_t instrument_idx) const override; /// Config write operations Result setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) override; @@ -104,23 +243,67 @@ class Adapter : public CentralAdapterBase { Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; Result setSysInfo(const ::cbPKT_SYSINFO& info) override; Result setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; + Result setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const override; }; } // namespace central_v4_1 namespace central_v4_0 { +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Adapter that provides information for fetching pointers to Central's shared memory +/// +class BootstrapAdapter : public CentralBootstrapAdapterBase { +public: + // Buffer sizes + size_t getConfigBufferSize() const override; + size_t getReceiveBufferSize() const override; + size_t getTransmitBufferSize() const override; + size_t getTransmitBufferLocalSize() const override; + size_t getStatusBufferSize() const override; + size_t getSpikeBufferSize() const override; + size_t getReceiveBufferLen() const override; +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Adapter for Central-compatible shared memory access /// class Adapter : public CentralAdapterBase { private: - CentralLegacyCFGBUFF* cfg; + cbCFGBUFF* cfg; + cbRECBUFF* rec; + cbXMTBUFF* xmt; + cbXMTBUFFLOCAL* xmt_local; + cbPcStatus* status; + cbSPKBUFF* spike; public: - Adapter(void* cfg_ptr); + Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr); ~Adapter() = default; + // Receive buffer access + uint32_t& getRecReceived() override; + uint64_t getRecLasttime() override; + void setRecLasttime(uint64_t lasttime) override; + uint32_t& getRecHeadwrapPtr() override; + uint32_t& getRecHeadindexPtr() override; + uint32_t* getRecBufferPtr() override; + + // Transmit buffer access + uint32_t& getXmtTransmittedPtr() override; + uint32_t& getXmtHeadindexPtr() override; + uint32_t& getXmtTailindexPtr() override; + uint32_t& getXmtLastValidIndexPtr() override; + uint32_t& getXmtBufferlenPtr() override; + uint32_t* getXmtBufferPtr() override; + + uint32_t& getLocalXmtTransmittedPtr() override; + uint32_t& getLocalXmtHeadindexPtr() override; + uint32_t& getLocalXmtTailindexPtr() override; + uint32_t& getLocalXmtLastValidIndexPtr() override; + uint32_t& getLocalXmtBufferlenPtr() override; + uint32_t* getLocalXmtBufferPtr() override; + /// Config read operations Result<::cbPKT_PROCINFO> getProcInfo(uint8_t instrument_idx) const override; Result<::cbPKT_BANKINFO> getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const override; @@ -128,6 +311,8 @@ class Adapter : public CentralAdapterBase { Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const override; Result<::cbPKT_SYSINFO> getSysInfo() const override; Result<::cbPKT_GROUPINFO> getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const override; + Result getConfigBuffer(uint8_t instrument_idx) const override; + Result getPcStatus(uint8_t instrument_idx) const override; /// Config write operations Result setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) override; @@ -136,23 +321,67 @@ class Adapter : public CentralAdapterBase { Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; Result setSysInfo(const ::cbPKT_SYSINFO& info) override; Result setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; + Result setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const override; }; } // namespace central_v4_0 namespace central_v3_11 { +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Adapter that provides information for fetching pointers to Central's shared memory +/// +class BootstrapAdapter : public CentralBootstrapAdapterBase { +public: + // Buffer sizes + size_t getConfigBufferSize() const override; + size_t getReceiveBufferSize() const override; + size_t getTransmitBufferSize() const override; + size_t getTransmitBufferLocalSize() const override; + size_t getStatusBufferSize() const override; + size_t getSpikeBufferSize() const override; + size_t getReceiveBufferLen() const override; +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Adapter for Central-compatible shared memory access /// class Adapter : public CentralAdapterBase { private: - CentralLegacyCFGBUFF* cfg; + cbCFGBUFF* cfg; + cbRECBUFF* rec; + cbXMTBUFF* xmt; + cbXMTBUFFLOCAL* xmt_local; + cbPcStatus* status; + cbSPKBUFF* spike; public: - Adapter(void* cfg_ptr); + Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr); ~Adapter() = default; + // Receive buffer access + uint32_t& getRecReceived() override; + uint64_t getRecLasttime() override; + void setRecLasttime(uint64_t lasttime) override; + uint32_t& getRecHeadwrapPtr() override; + uint32_t& getRecHeadindexPtr() override; + uint32_t* getRecBufferPtr() override; + + // Transmit buffer access + uint32_t& getXmtTransmittedPtr() override; + uint32_t& getXmtHeadindexPtr() override; + uint32_t& getXmtTailindexPtr() override; + uint32_t& getXmtLastValidIndexPtr() override; + uint32_t& getXmtBufferlenPtr() override; + uint32_t* getXmtBufferPtr() override; + + uint32_t& getLocalXmtTransmittedPtr() override; + uint32_t& getLocalXmtHeadindexPtr() override; + uint32_t& getLocalXmtTailindexPtr() override; + uint32_t& getLocalXmtLastValidIndexPtr() override; + uint32_t& getLocalXmtBufferlenPtr() override; + uint32_t* getLocalXmtBufferPtr() override; + /// Config read operations Result<::cbPKT_PROCINFO> getProcInfo(uint8_t instrument_idx) const override; Result<::cbPKT_BANKINFO> getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const override; @@ -160,6 +389,8 @@ class Adapter : public CentralAdapterBase { Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const override; Result<::cbPKT_SYSINFO> getSysInfo() const override; Result<::cbPKT_GROUPINFO> getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const override; + Result getConfigBuffer(uint8_t instrument_idx) const override; + Result getPcStatus(uint8_t instrument_idx) const override; /// Config write operations Result setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) override; @@ -168,6 +399,7 @@ class Adapter : public CentralAdapterBase { Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; Result setSysInfo(const ::cbPKT_SYSINFO& info) override; Result setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; + Result setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const override; }; } // namespace central_v3_11 diff --git a/src/cbshm/include/cbshm/central_types/translators.h b/src/cbshm/include/cbshm/central_types/translators.h index 3ca5d80e..1898c62a 100644 --- a/src/cbshm/include/cbshm/central_types/translators.h +++ b/src/cbshm/include/cbshm/central_types/translators.h @@ -5,17 +5,20 @@ /// /// @brief Translators for Central-compatible shared memory access /// +/// Downstream functions require that translations always succeed. +/// /////////////////////////////////////////////////////////////////////////////////////////////////// +#ifndef CBSHM_CENTRAL_TYPES_TRANSLATORS_H +#define CBSHM_CENTRAL_TYPES_TRANSLATORS_H + #include #include #include #include #include #include - -#ifndef CBSHM_CENTRAL_TYPES_TRANSLATORS_H -#define CBSHM_CENTRAL_TYPES_TRANSLATORS_H +#include namespace cbshm { @@ -28,263 +31,319 @@ namespace cbshm { /// TODO: Move all translations to within the adapter classes as well as the translation context. /// struct TranslationContext { - // cbCFGBUFF + // cbCFGBUFF, cbPcStatus uint8_t instrument_idx; }; namespace central_v4_2 { -::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg); -::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg); -::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg); -::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg); -::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg); -::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg); -::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg); -::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg); -::cbSCALING fromLegacy(const cbSCALING& leg); -::cbFILTDESC fromLegacy(const cbFILTDESC& leg); -::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg); -::cbHOOP fromLegacy(const cbHOOP& leg); -::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg); -::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg); -::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg); -::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg); -::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg); -::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg); -::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg); -::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg); -::cbproto::SpikeSorting fromLegacy(const cbproto::SpikeSorting& leg); -::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg); -::cbWaveformData fromLegacy(const cbWaveformData& leg); -::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg); -::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg); -::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg); -::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg); -::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg); -::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg); +::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg, const TranslationContext& ctx); +::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg, const TranslationContext& ctx); +::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg, const TranslationContext& ctx); +::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg, const TranslationContext& ctx); +::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg, const TranslationContext& ctx); +::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg, const TranslationContext& ctx); +::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg, const TranslationContext& ctx); +::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg, const TranslationContext& ctx); +::cbSCALING fromLegacy(const cbSCALING& leg, const TranslationContext& ctx); +::cbFILTDESC fromLegacy(const cbFILTDESC& leg, const TranslationContext& ctx); +::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg, const TranslationContext& ctx); +::cbHOOP fromLegacy(const cbHOOP& leg, const TranslationContext& ctx); +::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg, const TranslationContext& ctx); +::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg, const TranslationContext& ctx); +::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg, const TranslationContext& ctx); +::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg, const TranslationContext& ctx); +::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg, const TranslationContext& ctx); +::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg, const TranslationContext& ctx); +::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg, const TranslationContext& ctx); +::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg, const TranslationContext& ctx); +::cbproto::SpikeSorting fromLegacy(const cbproto::SpikeSorting& leg, const TranslationContext& ctx); +::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg, const TranslationContext& ctx); +::cbWaveformData fromLegacy(const cbWaveformData& leg, const TranslationContext& ctx); +::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg, const TranslationContext& ctx); +::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg, const TranslationContext& ctx); +::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg, const TranslationContext& ctx); +::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg, const TranslationContext& ctx); +::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg, const TranslationContext& ctx); +::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg, const TranslationContext& ctx); +NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg, const TranslationContext& ctx); +NativeNSPStatus fromLegacy(const NSPStatus& leg, const TranslationContext& ctx); +::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg, const TranslationContext& ctx); +NativePCStatus fromLegacy(const cbPcStatus& leg, const TranslationContext& ctx); +NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg, const TranslationContext& ctx); +NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg, const TranslationContext& ctx); +NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg, const TranslationContext& ctx); -cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur); -cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur); -cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur); -cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur); -cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur); -cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur); -cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur); -cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur); -cbSCALING toLegacy(const ::cbSCALING& cur); -cbFILTDESC toLegacy(const ::cbFILTDESC& cur); -cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur); -cbHOOP toLegacy(const ::cbHOOP& cur); -cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur); -cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur); -cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur); -cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur); -cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur); -cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur); -cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur); -cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur); -cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur); -cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur); -cbWaveformData toLegacy(const ::cbWaveformData& cur); -cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur); -cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur); -cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur); -cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur); -cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur); -cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur); +cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur, const TranslationContext& ctx); +cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur, const TranslationContext& ctx); +cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur, const TranslationContext& ctx); +cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur, const TranslationContext& ctx); +cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur, const TranslationContext& ctx); +cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur, const TranslationContext& ctx); +cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur, const TranslationContext& ctx); +cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur, const TranslationContext& ctx); +cbSCALING toLegacy(const ::cbSCALING& cur, const TranslationContext& ctx); +cbFILTDESC toLegacy(const ::cbFILTDESC& cur, const TranslationContext& ctx); +cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur, const TranslationContext& ctx); +cbHOOP toLegacy(const ::cbHOOP& cur, const TranslationContext& ctx); +cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur, const TranslationContext& ctx); +cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur, const TranslationContext& ctx); +cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur, const TranslationContext& ctx); +cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur, const TranslationContext& ctx); +cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur, const TranslationContext& ctx); +cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur, const TranslationContext& ctx); +cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur, const TranslationContext& ctx); +cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur, const TranslationContext& ctx); +cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur, const TranslationContext& ctx); +cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur, const TranslationContext& ctx); +cbWaveformData toLegacy(const ::cbWaveformData& cur, const TranslationContext& ctx); +cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur, const TranslationContext& ctx); +cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur, const TranslationContext& ctx); +cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur, const TranslationContext& ctx); +cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur, const TranslationContext& ctx); +cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur, const TranslationContext& ctx); +cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur, const TranslationContext& ctx); +// cbCFGBUFF -> NativeConfigBuffer is a lossy translation and cannot be reversed +NSPStatus toLegacy(const NativeNSPStatus& cur, const TranslationContext& ctx); +cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur, const TranslationContext& ctx); +cbPcStatus toLegacy(const NativePCStatus& cur, const TranslationContext& ctx); +cbRECBUFF toLegacy(const NativeReceiveBuffer& cur, const TranslationContext& ctx); +cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur, const TranslationContext& ctx); +cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur, const TranslationContext& ctx); } // namespace central_v4_2 namespace central_v4_1 { -::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg); -::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg); -::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg); -::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg); -::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg); -::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg); -::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg); -::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg); -::cbSCALING fromLegacy(const cbSCALING& leg); -::cbFILTDESC fromLegacy(const cbFILTDESC& leg); -::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg); -::cbHOOP fromLegacy(const cbHOOP& leg); -::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg); -::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg); -::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg); -::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg); -::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg); -::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg); -::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg); -::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg); -::cbproto::SpikeSorting fromLegacy(const cbproto::SpikeSorting& leg); -::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg); -::cbWaveformData fromLegacy(const cbWaveformData& leg); -::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg); -::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg); -::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg); -::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg); -::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg); -::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg); +::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg, const TranslationContext& ctx); +::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg, const TranslationContext& ctx); +::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg, const TranslationContext& ctx); +::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg, const TranslationContext& ctx); +::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg, const TranslationContext& ctx); +::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg, const TranslationContext& ctx); +::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg, const TranslationContext& ctx); +::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg, const TranslationContext& ctx); +::cbSCALING fromLegacy(const cbSCALING& leg, const TranslationContext& ctx); +::cbFILTDESC fromLegacy(const cbFILTDESC& leg, const TranslationContext& ctx); +::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg, const TranslationContext& ctx); +::cbHOOP fromLegacy(const cbHOOP& leg, const TranslationContext& ctx); +::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg, const TranslationContext& ctx); +::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg, const TranslationContext& ctx); +::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg, const TranslationContext& ctx); +::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg, const TranslationContext& ctx); +::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg, const TranslationContext& ctx); +::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg, const TranslationContext& ctx); +::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg, const TranslationContext& ctx); +::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg, const TranslationContext& ctx); +::cbproto::SpikeSorting fromLegacy(const cbproto::SpikeSorting& leg, const TranslationContext& ctx); +::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg, const TranslationContext& ctx); +::cbWaveformData fromLegacy(const cbWaveformData& leg, const TranslationContext& ctx); +::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg, const TranslationContext& ctx); +::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg, const TranslationContext& ctx); +::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg, const TranslationContext& ctx); +::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg, const TranslationContext& ctx); +::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg, const TranslationContext& ctx); +::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg, const TranslationContext& ctx); +NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg, const TranslationContext& ctx); +NativeNSPStatus fromLegacy(const NSPStatus& leg, const TranslationContext& ctx); +::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg, const TranslationContext& ctx); +NativePCStatus fromLegacy(const cbPcStatus& leg, const TranslationContext& ctx); +NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg, const TranslationContext& ctx); +NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg, const TranslationContext& ctx); +NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg, const TranslationContext& ctx); -cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur); -cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur); -cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur); -cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur); -cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur); -cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur); -cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur); -cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur); -cbSCALING toLegacy(const ::cbSCALING& cur); -cbFILTDESC toLegacy(const ::cbFILTDESC& cur); -cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur); -cbHOOP toLegacy(const ::cbHOOP& cur); -cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur); -cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur); -cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur); -cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur); -cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur); -cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur); -cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur); -cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur); -cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur); -cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur); -cbWaveformData toLegacy(const ::cbWaveformData& cur); -cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur); -cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur); -cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur); -cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur); -cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur); -cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur); +cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur, const TranslationContext& ctx); +cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur, const TranslationContext& ctx); +cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur, const TranslationContext& ctx); +cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur, const TranslationContext& ctx); +cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur, const TranslationContext& ctx); +cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur, const TranslationContext& ctx); +cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur, const TranslationContext& ctx); +cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur, const TranslationContext& ctx); +cbSCALING toLegacy(const ::cbSCALING& cur, const TranslationContext& ctx); +cbFILTDESC toLegacy(const ::cbFILTDESC& cur, const TranslationContext& ctx); +cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur, const TranslationContext& ctx); +cbHOOP toLegacy(const ::cbHOOP& cur, const TranslationContext& ctx); +cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur, const TranslationContext& ctx); +cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur, const TranslationContext& ctx); +cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur, const TranslationContext& ctx); +cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur, const TranslationContext& ctx); +cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur, const TranslationContext& ctx); +cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur, const TranslationContext& ctx); +cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur, const TranslationContext& ctx); +cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur, const TranslationContext& ctx); +cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur, const TranslationContext& ctx); +cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur, const TranslationContext& ctx); +cbWaveformData toLegacy(const ::cbWaveformData& cur, const TranslationContext& ctx); +cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur, const TranslationContext& ctx); +cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur, const TranslationContext& ctx); +cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur, const TranslationContext& ctx); +cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur, const TranslationContext& ctx); +cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur, const TranslationContext& ctx); +cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur, const TranslationContext& ctx); +// cbCFGBUFF -> NativeConfigBuffer is a lossy translation and cannot be reversed +NSPStatus toLegacy(const NativeNSPStatus& cur, const TranslationContext& ctx); +cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur, const TranslationContext& ctx); +cbPcStatus toLegacy(const NativePCStatus& cur, const TranslationContext& ctx); +cbRECBUFF toLegacy(const NativeReceiveBuffer& cur, const TranslationContext& ctx); +cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur, const TranslationContext& ctx); +cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur, const TranslationContext& ctx); } // namespace central_v4_1 namespace central_v4_0 { -::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg); -::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg); -::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg); -::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg); -::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg); -::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg); -::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg); -::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg); -::cbSCALING fromLegacy(const cbSCALING& leg); -::cbFILTDESC fromLegacy(const cbFILTDESC& leg); -::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg); -::cbHOOP fromLegacy(const cbHOOP& leg); -::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg); -::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg); -::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg); -::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg); -::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg); -::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg); -::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg); -::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg); -::cbproto::SpikeSorting fromLegacy(const cbproto::SpikeSorting& leg); -::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg); -::cbWaveformData fromLegacy(const cbWaveformData& leg); -::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg); -::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg); -::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg); -::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg); -::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg); -::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg); +::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg, const TranslationContext& ctx); +::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg, const TranslationContext& ctx); +::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg, const TranslationContext& ctx); +::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg, const TranslationContext& ctx); +::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg, const TranslationContext& ctx); +::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg, const TranslationContext& ctx); +::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg, const TranslationContext& ctx); +::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg, const TranslationContext& ctx); +::cbSCALING fromLegacy(const cbSCALING& leg, const TranslationContext& ctx); +::cbFILTDESC fromLegacy(const cbFILTDESC& leg, const TranslationContext& ctx); +::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg, const TranslationContext& ctx); +::cbHOOP fromLegacy(const cbHOOP& leg, const TranslationContext& ctx); +::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg, const TranslationContext& ctx); +::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg, const TranslationContext& ctx); +::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg, const TranslationContext& ctx); +::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg, const TranslationContext& ctx); +::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg, const TranslationContext& ctx); +::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg, const TranslationContext& ctx); +::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg, const TranslationContext& ctx); +::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg, const TranslationContext& ctx); +::cbproto::SpikeSorting fromLegacy(const cbproto::SpikeSorting& leg, const TranslationContext& ctx); +::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg, const TranslationContext& ctx); +::cbWaveformData fromLegacy(const cbWaveformData& leg, const TranslationContext& ctx); +::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg, const TranslationContext& ctx); +::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg, const TranslationContext& ctx); +::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg, const TranslationContext& ctx); +::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg, const TranslationContext& ctx); +::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg, const TranslationContext& ctx); +::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg, const TranslationContext& ctx); +NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg, const TranslationContext& ctx); +NativeNSPStatus fromLegacy(const NSPStatus& leg, const TranslationContext& ctx); +::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg, const TranslationContext& ctx); +NativePCStatus fromLegacy(const cbPcStatus& leg, const TranslationContext& ctx); +NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg, const TranslationContext& ctx); +NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg, const TranslationContext& ctx); +NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg, const TranslationContext& ctx); -cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur); -cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur); -cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur); -cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur); -cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur); -cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur); -cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur); -cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur); -cbSCALING toLegacy(const ::cbSCALING& cur); -cbFILTDESC toLegacy(const ::cbFILTDESC& cur); -cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur); -cbHOOP toLegacy(const ::cbHOOP& cur); -cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur); -cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur); -cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur); -cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur); -cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur); -cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur); -cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur); -cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur); -cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur); -cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur); -cbWaveformData toLegacy(const ::cbWaveformData& cur); -cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur); -cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur); -cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur); -cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur); -cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur); -cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur); +cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur, const TranslationContext& ctx); +cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur, const TranslationContext& ctx); +cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur, const TranslationContext& ctx); +cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur, const TranslationContext& ctx); +cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur, const TranslationContext& ctx); +cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur, const TranslationContext& ctx); +cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur, const TranslationContext& ctx); +cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur, const TranslationContext& ctx); +cbSCALING toLegacy(const ::cbSCALING& cur, const TranslationContext& ctx); +cbFILTDESC toLegacy(const ::cbFILTDESC& cur, const TranslationContext& ctx); +cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur, const TranslationContext& ctx); +cbHOOP toLegacy(const ::cbHOOP& cur, const TranslationContext& ctx); +cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur, const TranslationContext& ctx); +cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur, const TranslationContext& ctx); +cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur, const TranslationContext& ctx); +cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur, const TranslationContext& ctx); +cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur, const TranslationContext& ctx); +cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur, const TranslationContext& ctx); +cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur, const TranslationContext& ctx); +cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur, const TranslationContext& ctx); +cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur, const TranslationContext& ctx); +cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur, const TranslationContext& ctx); +cbWaveformData toLegacy(const ::cbWaveformData& cur, const TranslationContext& ctx); +cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur, const TranslationContext& ctx); +cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur, const TranslationContext& ctx); +cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur, const TranslationContext& ctx); +cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur, const TranslationContext& ctx); +cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur, const TranslationContext& ctx); +cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur, const TranslationContext& ctx); +// cbCFGBUFF -> NativeConfigBuffer is a lossy translation and cannot be reversed +NSPStatus toLegacy(const NativeNSPStatus& cur, const TranslationContext& ctx); +cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur, const TranslationContext& ctx); +cbPcStatus toLegacy(const NativePCStatus& cur, const TranslationContext& ctx); +cbRECBUFF toLegacy(const NativeReceiveBuffer& cur, const TranslationContext& ctx); +cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur, const TranslationContext& ctx); +cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur, const TranslationContext& ctx); } // namespace central_v4_0 namespace central_v3_11 { -::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg); -::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg); -::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg); -::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg); -::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg); -::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg); -::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg); -::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg); -::cbSCALING fromLegacy(const cbSCALING& leg); -::cbFILTDESC fromLegacy(const cbFILTDESC& leg); -::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg); -::cbHOOP fromLegacy(const cbHOOP& leg); -::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg); -::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg); -::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg); -::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg); -::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg); -::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg); -::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg); -::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg); -::cbproto::SpikeSorting fromLegacy(const cbproto::SpikeSorting& leg); -::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg); -::cbWaveformData fromLegacy(const cbWaveformData& leg); -::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg); -::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg); -::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg); -::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg); -::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg); -::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg); +::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg, const TranslationContext& ctx); +::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg, const TranslationContext& ctx); +::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg, const TranslationContext& ctx); +::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg, const TranslationContext& ctx); +::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg, const TranslationContext& ctx); +::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg, const TranslationContext& ctx); +::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg, const TranslationContext& ctx); +::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg, const TranslationContext& ctx); +::cbSCALING fromLegacy(const cbSCALING& leg, const TranslationContext& ctx); +::cbFILTDESC fromLegacy(const cbFILTDESC& leg, const TranslationContext& ctx); +::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg, const TranslationContext& ctx); +::cbHOOP fromLegacy(const cbHOOP& leg, const TranslationContext& ctx); +::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg, const TranslationContext& ctx); +::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg, const TranslationContext& ctx); +::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg, const TranslationContext& ctx); +::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg, const TranslationContext& ctx); +::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg, const TranslationContext& ctx); +::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg, const TranslationContext& ctx); +::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg, const TranslationContext& ctx); +::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg, const TranslationContext& ctx); +::cbproto::SpikeSorting fromLegacy(const cbproto::SpikeSorting& leg, const TranslationContext& ctx); +::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg, const TranslationContext& ctx); +::cbWaveformData fromLegacy(const cbWaveformData& leg, const TranslationContext& ctx); +::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg, const TranslationContext& ctx); +::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg, const TranslationContext& ctx); +::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg, const TranslationContext& ctx); +::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg, const TranslationContext& ctx); +::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg, const TranslationContext& ctx); +::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg, const TranslationContext& ctx); +NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg, const TranslationContext& ctx); +NativeNSPStatus fromLegacy(const NSPStatus& leg, const TranslationContext& ctx); +::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg, const TranslationContext& ctx); +NativePCStatus fromLegacy(const cbPcStatus& leg, const TranslationContext& ctx); +NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg, const TranslationContext& ctx); +NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg, const TranslationContext& ctx); +NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg, const TranslationContext& ctx); -cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur); -cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur); -cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur); -cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur); -cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur); -cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur); -cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur); -cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur); -cbSCALING toLegacy(const ::cbSCALING& cur); -cbFILTDESC toLegacy(const ::cbFILTDESC& cur); -cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur); -cbHOOP toLegacy(const ::cbHOOP& cur); -cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur); -cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur); -cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur); -cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur); -cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur); -cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur); -cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur); -cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur); -cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur); -cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur); -cbWaveformData toLegacy(const ::cbWaveformData& cur); -cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur); -cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur); -cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur); -cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur); -cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur); -cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur); +cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur, const TranslationContext& ctx); +cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur, const TranslationContext& ctx); +cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur, const TranslationContext& ctx); +cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur, const TranslationContext& ctx); +cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur, const TranslationContext& ctx); +cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur, const TranslationContext& ctx); +cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur, const TranslationContext& ctx); +cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur, const TranslationContext& ctx); +cbSCALING toLegacy(const ::cbSCALING& cur, const TranslationContext& ctx); +cbFILTDESC toLegacy(const ::cbFILTDESC& cur, const TranslationContext& ctx); +cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur, const TranslationContext& ctx); +cbHOOP toLegacy(const ::cbHOOP& cur, const TranslationContext& ctx); +cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur, const TranslationContext& ctx); +cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur, const TranslationContext& ctx); +cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur, const TranslationContext& ctx); +cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur, const TranslationContext& ctx); +cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur, const TranslationContext& ctx); +cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur, const TranslationContext& ctx); +cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur, const TranslationContext& ctx); +cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur, const TranslationContext& ctx); +cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur, const TranslationContext& ctx); +cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur, const TranslationContext& ctx); +cbWaveformData toLegacy(const ::cbWaveformData& cur, const TranslationContext& ctx); +cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur, const TranslationContext& ctx); +cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur, const TranslationContext& ctx); +cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur, const TranslationContext& ctx); +cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur, const TranslationContext& ctx); +cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur, const TranslationContext& ctx); +cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur, const TranslationContext& ctx); +// cbCFGBUFF -> NativeConfigBuffer is a lossy translation and cannot be reversed +NSPStatus toLegacy(const NativeNSPStatus& cur, const TranslationContext& ctx); +cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur, const TranslationContext& ctx); +cbPcStatus toLegacy(const NativePCStatus& cur, const TranslationContext& ctx); +cbRECBUFF toLegacy(const NativeReceiveBuffer& cur, const TranslationContext& ctx); +cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur, const TranslationContext& ctx); +cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur, const TranslationContext& ctx); } // namespace central_v3_11 diff --git a/src/cbshm/src/central_adapters/v3_11.cpp b/src/cbshm/src/central_adapters/v3_11.cpp index 44058f4c..3a54b14b 100644 --- a/src/cbshm/src/central_adapters/v3_11.cpp +++ b/src/cbshm/src/central_adapters/v3_11.cpp @@ -15,14 +15,120 @@ namespace cbshm { namespace central_v3_11 { -Adapter::Adapter(void* cfg_ptr) : cfg(static_cast(cfg_ptr)) { +size_t BootstrapAdapter::getConfigBufferSize() const { + return sizeof(cbCFGBUFF); +} + +size_t BootstrapAdapter::getReceiveBufferSize() const { + return sizeof(cbRECBUFF); +} + +size_t BootstrapAdapter::getTransmitBufferSize() const { + return sizeof(cbXMTBUFF); +} + +size_t BootstrapAdapter::getTransmitBufferLocalSize() const { + return sizeof(cbXMTBUFFLOCAL); +} + +size_t BootstrapAdapter::getStatusBufferSize() const { + return sizeof(cbPcStatus); +} + +size_t BootstrapAdapter::getSpikeBufferSize() const { + return sizeof(cbSPKBUFF); +} + +size_t BootstrapAdapter::getReceiveBufferLen() const { + return sizeof(cbRECBUFFLEN); +} + +Adapter::Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) + : cfg(static_cast(cfg_ptr)) + , rec(static_cast(rec_ptr)) + , xmt(static_cast(xmt_ptr)) + , xmt_local(static_cast(xmt_local_ptr)) + , status(static_cast(status_ptr)) + , spike(static_cast(spike_ptr)) +{} + +uint32_t& Adapter::getRecReceived() { + return rec->received; +} + +uint64_t Adapter::getRecLasttime() { + return rec->lasttime; +} + +void Adapter::setRecLasttime(uint64_t lasttime) { + rec->lasttime = lasttime; +} + +uint32_t& Adapter::getRecHeadwrapPtr() { + return rec->headwrap; +} + +uint32_t& Adapter::getRecHeadindexPtr() { + return rec->headindex; +} + +uint32_t* Adapter::getRecBufferPtr() { + return rec->buffer; +} + +uint32_t& Adapter::getXmtTransmittedPtr() { + return xmt->transmitted; +} + +uint32_t& Adapter::getXmtHeadindexPtr() { + return xmt->headindex; +} + +uint32_t& Adapter::getXmtTailindexPtr() { + return xmt->tailindex; +} + +uint32_t& Adapter::getXmtLastValidIndexPtr() { + return xmt->last_valid_index; +} + +uint32_t& Adapter::getXmtBufferlenPtr() { + return xmt->bufferlen; +} + +uint32_t* Adapter::getXmtBufferPtr() { + return xmt->buffer; +} + +uint32_t& Adapter::getLocalXmtTransmittedPtr() { + return xmt->transmitted; +} + +uint32_t& Adapter::getLocalXmtHeadindexPtr() { + return xmt->headindex; +} + +uint32_t& Adapter::getLocalXmtTailindexPtr() { + return xmt->tailindex; +} + +uint32_t& Adapter::getLocalXmtLastValidIndexPtr() { + return xmt->last_valid_index; +} + +uint32_t& Adapter::getLocalXmtBufferlenPtr() { + return xmt->bufferlen; +} + +uint32_t* Adapter::getLocalXmtBufferPtr() { + return xmt->buffer; } Result<::cbPKT_PROCINFO> Adapter::getProcInfo(uint8_t instrument_idx) const { if (instrument_idx >= std::size(cfg->procinfo)) { return Result<::cbPKT_PROCINFO>::error("Instrument index out of range"); } - return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx])); + return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx], {})); } Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const { @@ -33,7 +139,7 @@ Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t b if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result<::cbPKT_BANKINFO>::error("Bank number out of range"); } - return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx])); + return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx], {})); } Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const { @@ -44,18 +150,18 @@ Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result<::cbPKT_FILTINFO>::error("Filter number out of range"); } - return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx])); + return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx], {})); } Result<::cbPKT_CHANINFO> Adapter::getChanInfo(uint32_t channel_idx) const { if (channel_idx >= std::size(cfg->chaninfo)) { return Result<::cbPKT_CHANINFO>::error("Channel number out of range"); } - return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx])); + return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx], {})); } Result<::cbPKT_SYSINFO> Adapter::getSysInfo() const { - return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo)); + return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo, {})); } Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const { @@ -65,14 +171,28 @@ Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint8_t instrument_idx, uint32_t if (group_idx >= std::size(cfg->groupinfo[0])) { return Result<::cbPKT_GROUPINFO>::error("Group index out of range"); } - return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx])); + return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx], {})); +} + +Result Adapter::getConfigBuffer(uint8_t instrument_idx) const { + if (instrument_idx >= std::size(cfg->procinfo)) { + return Result::error("Instrument index out of range"); + } + return Result::ok(fromLegacy(*cfg, { .instrument_idx = instrument_idx })); +} + +Result Adapter::getPcStatus(uint8_t instrument_idx) const { + if (instrument_idx >= std::size(status->isSelection)) { + return Result::error("Instrument index out of range"); + } + return Result::ok(fromLegacy(*status, { .instrument_idx = instrument_idx })); } Result Adapter::setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) { if (instrument_idx >= std::size(cfg->procinfo)) { return Result::error("Instrument index out of range"); } - cfg->procinfo[instrument_idx] = toLegacy(info); + cfg->procinfo[instrument_idx] = toLegacy(info, {}); return Result::ok(); } @@ -84,7 +204,7 @@ Result Adapter::setBankInfo(uint8_t instrument_idx, uint32_t bank_num, con if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result::error("Bank number out of range"); } - cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info); + cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info, {}); return Result::ok(); } @@ -96,7 +216,7 @@ Result Adapter::setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result::error("Filter number out of range"); } - cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info); + cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info, {}); return Result::ok(); } @@ -104,12 +224,12 @@ Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& if (channel_idx >= std::size(cfg->chaninfo)) { return Result::error("Channel number out of range"); } - cfg->chaninfo[channel_idx] = toLegacy(info); + cfg->chaninfo[channel_idx] = toLegacy(info, {}); return Result::ok(); } Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { - cfg->sysinfo = toLegacy(info); + cfg->sysinfo = toLegacy(info, {}); return Result::ok(); } @@ -120,7 +240,15 @@ Result Adapter::setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, c if (group_idx >= std::size(cfg->groupinfo[0])) { return Result::error("Group index out of range"); } - cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info); + cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info, {}); + return Result::ok(); +} + +Result Adapter::setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const { + if (instrument_idx >= std::size(this->status->isSelection)) { + return Result::error("Instrument index out of range"); + } + *(this->status) = toLegacy(status, { .instrument_idx = instrument_idx }); return Result::ok(); } diff --git a/src/cbshm/src/central_adapters/v4_0.cpp b/src/cbshm/src/central_adapters/v4_0.cpp index 9c66bb16..5d2da5b3 100644 --- a/src/cbshm/src/central_adapters/v4_0.cpp +++ b/src/cbshm/src/central_adapters/v4_0.cpp @@ -15,14 +15,120 @@ namespace cbshm { namespace central_v4_0 { -Adapter::Adapter(void* cfg_ptr) : cfg(static_cast(cfg_ptr)) { +size_t BootstrapAdapter::getConfigBufferSize() const { + return sizeof(cbCFGBUFF); +} + +size_t BootstrapAdapter::getReceiveBufferSize() const { + return sizeof(cbRECBUFF); +} + +size_t BootstrapAdapter::getTransmitBufferSize() const { + return sizeof(cbXMTBUFF); +} + +size_t BootstrapAdapter::getTransmitBufferLocalSize() const { + return sizeof(cbXMTBUFFLOCAL); +} + +size_t BootstrapAdapter::getStatusBufferSize() const { + return sizeof(cbPcStatus); +} + +size_t BootstrapAdapter::getSpikeBufferSize() const { + return sizeof(cbSPKBUFF); +} + +size_t BootstrapAdapter::getReceiveBufferLen() const { + return sizeof(cbRECBUFFLEN); +} + +Adapter::Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) + : cfg(static_cast(cfg_ptr)) + , rec(static_cast(rec_ptr)) + , xmt(static_cast(xmt_ptr)) + , xmt_local(static_cast(xmt_local_ptr)) + , status(static_cast(status_ptr)) + , spike(static_cast(spike_ptr)) +{} + +uint32_t& Adapter::getRecReceived() { + return rec->received; +} + +uint64_t Adapter::getRecLasttime() { + return rec->lasttime; +} + +void Adapter::setRecLasttime(uint64_t lasttime) { + rec->lasttime = lasttime; +} + +uint32_t& Adapter::getRecHeadwrapPtr() { + return rec->headwrap; +} + +uint32_t& Adapter::getRecHeadindexPtr() { + return rec->headindex; +} + +uint32_t* Adapter::getRecBufferPtr() { + return rec->buffer; +} + +uint32_t& Adapter::getXmtTransmittedPtr() { + return xmt->transmitted; +} + +uint32_t& Adapter::getXmtHeadindexPtr() { + return xmt->headindex; +} + +uint32_t& Adapter::getXmtTailindexPtr() { + return xmt->tailindex; +} + +uint32_t& Adapter::getXmtLastValidIndexPtr() { + return xmt->last_valid_index; +} + +uint32_t& Adapter::getXmtBufferlenPtr() { + return xmt->bufferlen; +} + +uint32_t* Adapter::getXmtBufferPtr() { + return xmt->buffer; +} + +uint32_t& Adapter::getLocalXmtTransmittedPtr() { + return xmt->transmitted; +} + +uint32_t& Adapter::getLocalXmtHeadindexPtr() { + return xmt->headindex; +} + +uint32_t& Adapter::getLocalXmtTailindexPtr() { + return xmt->tailindex; +} + +uint32_t& Adapter::getLocalXmtLastValidIndexPtr() { + return xmt->last_valid_index; +} + +uint32_t& Adapter::getLocalXmtBufferlenPtr() { + return xmt->bufferlen; +} + +uint32_t* Adapter::getLocalXmtBufferPtr() { + return xmt->buffer; } Result<::cbPKT_PROCINFO> Adapter::getProcInfo(uint8_t instrument_idx) const { if (instrument_idx >= std::size(cfg->procinfo)) { return Result<::cbPKT_PROCINFO>::error("Instrument index out of range"); } - return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx])); + return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx], {})); } Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const { @@ -33,7 +139,7 @@ Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t b if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result<::cbPKT_BANKINFO>::error("Bank number out of range"); } - return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx])); + return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx], {})); } Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const { @@ -44,18 +150,18 @@ Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result<::cbPKT_FILTINFO>::error("Filter number out of range"); } - return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx])); + return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx], {})); } Result<::cbPKT_CHANINFO> Adapter::getChanInfo(uint32_t channel_idx) const { if (channel_idx >= std::size(cfg->chaninfo)) { return Result<::cbPKT_CHANINFO>::error("Channel number out of range"); } - return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx])); + return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx], {})); } Result<::cbPKT_SYSINFO> Adapter::getSysInfo() const { - return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo)); + return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo, {})); } Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const { @@ -65,14 +171,28 @@ Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint8_t instrument_idx, uint32_t if (group_idx >= std::size(cfg->groupinfo[0])) { return Result<::cbPKT_GROUPINFO>::error("Group index out of range"); } - return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx])); + return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx], {})); +} + +Result Adapter::getConfigBuffer(uint8_t instrument_idx) const { + if (instrument_idx >= std::size(cfg->procinfo)) { + return Result::error("Instrument index out of range"); + } + return Result::ok(fromLegacy(*cfg, { .instrument_idx = instrument_idx })); +} + +Result Adapter::getPcStatus(uint8_t instrument_idx) const { + if (instrument_idx >= std::size(status->isSelection)) { + return Result::error("Instrument index out of range"); + } + return Result::ok(fromLegacy(*status, { .instrument_idx = instrument_idx })); } Result Adapter::setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) { if (instrument_idx >= std::size(cfg->procinfo)) { return Result::error("Instrument index out of range"); } - cfg->procinfo[instrument_idx] = toLegacy(info); + cfg->procinfo[instrument_idx] = toLegacy(info, {}); return Result::ok(); } @@ -84,7 +204,7 @@ Result Adapter::setBankInfo(uint8_t instrument_idx, uint32_t bank_num, con if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result::error("Bank number out of range"); } - cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info); + cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info, {}); return Result::ok(); } @@ -96,7 +216,7 @@ Result Adapter::setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result::error("Filter number out of range"); } - cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info); + cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info, {}); return Result::ok(); } @@ -104,12 +224,12 @@ Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& if (channel_idx >= std::size(cfg->chaninfo)) { return Result::error("Channel number out of range"); } - cfg->chaninfo[channel_idx] = toLegacy(info); + cfg->chaninfo[channel_idx] = toLegacy(info, {}); return Result::ok(); } Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { - cfg->sysinfo = toLegacy(info); + cfg->sysinfo = toLegacy(info, {}); return Result::ok(); } @@ -120,7 +240,15 @@ Result Adapter::setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, c if (group_idx >= std::size(cfg->groupinfo[0])) { return Result::error("Group index out of range"); } - cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info); + cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info, {}); + return Result::ok(); +} + +Result Adapter::setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const { + if (instrument_idx >= std::size(this->status->isSelection)) { + return Result::error("Instrument index out of range"); + } + *(this->status) = toLegacy(status, { .instrument_idx = instrument_idx }); return Result::ok(); } diff --git a/src/cbshm/src/central_adapters/v4_1.cpp b/src/cbshm/src/central_adapters/v4_1.cpp index c040623d..89634dc8 100644 --- a/src/cbshm/src/central_adapters/v4_1.cpp +++ b/src/cbshm/src/central_adapters/v4_1.cpp @@ -15,14 +15,120 @@ namespace cbshm { namespace central_v4_1 { -Adapter::Adapter(void* cfg_ptr) : cfg(static_cast(cfg_ptr)) { +size_t BootstrapAdapter::getConfigBufferSize() const { + return sizeof(cbCFGBUFF); +} + +size_t BootstrapAdapter::getReceiveBufferSize() const { + return sizeof(cbRECBUFF); +} + +size_t BootstrapAdapter::getTransmitBufferSize() const { + return sizeof(cbXMTBUFF); +} + +size_t BootstrapAdapter::getTransmitBufferLocalSize() const { + return sizeof(cbXMTBUFFLOCAL); +} + +size_t BootstrapAdapter::getStatusBufferSize() const { + return sizeof(cbPcStatus); +} + +size_t BootstrapAdapter::getSpikeBufferSize() const { + return sizeof(cbSPKBUFF); +} + +size_t BootstrapAdapter::getReceiveBufferLen() const { + return sizeof(cbRECBUFFLEN); +} + +Adapter::Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) + : cfg(static_cast(cfg_ptr)) + , rec(static_cast(rec_ptr)) + , xmt(static_cast(xmt_ptr)) + , xmt_local(static_cast(xmt_local_ptr)) + , status(static_cast(status_ptr)) + , spike(static_cast(spike_ptr)) +{} + +uint32_t& Adapter::getRecReceived() { + return rec->received; +} + +uint64_t Adapter::getRecLasttime() { + return rec->lasttime; +} + +void Adapter::setRecLasttime(uint64_t lasttime) { + rec->lasttime = lasttime; +} + +uint32_t& Adapter::getRecHeadwrapPtr() { + return rec->headwrap; +} + +uint32_t& Adapter::getRecHeadindexPtr() { + return rec->headindex; +} + +uint32_t* Adapter::getRecBufferPtr() { + return rec->buffer; +} + +uint32_t& Adapter::getXmtTransmittedPtr() { + return xmt->transmitted; +} + +uint32_t& Adapter::getXmtHeadindexPtr() { + return xmt->headindex; +} + +uint32_t& Adapter::getXmtTailindexPtr() { + return xmt->tailindex; +} + +uint32_t& Adapter::getXmtLastValidIndexPtr() { + return xmt->last_valid_index; +} + +uint32_t& Adapter::getXmtBufferlenPtr() { + return xmt->bufferlen; +} + +uint32_t* Adapter::getXmtBufferPtr() { + return xmt->buffer; +} + +uint32_t& Adapter::getLocalXmtTransmittedPtr() { + return xmt->transmitted; +} + +uint32_t& Adapter::getLocalXmtHeadindexPtr() { + return xmt->headindex; +} + +uint32_t& Adapter::getLocalXmtTailindexPtr() { + return xmt->tailindex; +} + +uint32_t& Adapter::getLocalXmtLastValidIndexPtr() { + return xmt->last_valid_index; +} + +uint32_t& Adapter::getLocalXmtBufferlenPtr() { + return xmt->bufferlen; +} + +uint32_t* Adapter::getLocalXmtBufferPtr() { + return xmt->buffer; } Result<::cbPKT_PROCINFO> Adapter::getProcInfo(uint8_t instrument_idx) const { if (instrument_idx >= std::size(cfg->procinfo)) { return Result<::cbPKT_PROCINFO>::error("Instrument index out of range"); } - return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx])); + return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx], {})); } Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const { @@ -33,7 +139,7 @@ Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t b if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result<::cbPKT_BANKINFO>::error("Bank number out of range"); } - return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx])); + return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx], {})); } Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const { @@ -44,18 +150,18 @@ Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result<::cbPKT_FILTINFO>::error("Filter number out of range"); } - return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx])); + return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx], {})); } Result<::cbPKT_CHANINFO> Adapter::getChanInfo(uint32_t channel_idx) const { if (channel_idx >= std::size(cfg->chaninfo)) { return Result<::cbPKT_CHANINFO>::error("Channel number out of range"); } - return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx])); + return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx], {})); } Result<::cbPKT_SYSINFO> Adapter::getSysInfo() const { - return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo)); + return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo, {})); } Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const { @@ -65,14 +171,28 @@ Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint8_t instrument_idx, uint32_t if (group_idx >= std::size(cfg->groupinfo[0])) { return Result<::cbPKT_GROUPINFO>::error("Group index out of range"); } - return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx])); + return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx], {})); +} + +Result Adapter::getConfigBuffer(uint8_t instrument_idx) const { + if (instrument_idx >= std::size(cfg->procinfo)) { + return Result::error("Instrument index out of range"); + } + return Result::ok(fromLegacy(*cfg, { .instrument_idx = instrument_idx })); +} + +Result Adapter::getPcStatus(uint8_t instrument_idx) const { + if (instrument_idx >= std::size(status->isSelection)) { + return Result::error("Instrument index out of range"); + } + return Result::ok(fromLegacy(*status, { .instrument_idx = instrument_idx })); } Result Adapter::setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) { if (instrument_idx >= std::size(cfg->procinfo)) { return Result::error("Instrument index out of range"); } - cfg->procinfo[instrument_idx] = toLegacy(info); + cfg->procinfo[instrument_idx] = toLegacy(info, {}); return Result::ok(); } @@ -84,7 +204,7 @@ Result Adapter::setBankInfo(uint8_t instrument_idx, uint32_t bank_num, con if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result::error("Bank number out of range"); } - cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info); + cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info, {}); return Result::ok(); } @@ -96,7 +216,7 @@ Result Adapter::setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result::error("Filter number out of range"); } - cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info); + cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info, {}); return Result::ok(); } @@ -104,12 +224,12 @@ Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& if (channel_idx >= std::size(cfg->chaninfo)) { return Result::error("Channel number out of range"); } - cfg->chaninfo[channel_idx] = toLegacy(info); + cfg->chaninfo[channel_idx] = toLegacy(info, {}); return Result::ok(); } Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { - cfg->sysinfo = toLegacy(info); + cfg->sysinfo = toLegacy(info, {}); return Result::ok(); } @@ -120,7 +240,15 @@ Result Adapter::setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, c if (group_idx >= std::size(cfg->groupinfo[0])) { return Result::error("Group index out of range"); } - cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info); + cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info, {}); + return Result::ok(); +} + +Result Adapter::setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const { + if (instrument_idx >= std::size(this->status->isSelection)) { + return Result::error("Instrument index out of range"); + } + *(this->status) = toLegacy(status, { .instrument_idx = instrument_idx }); return Result::ok(); } diff --git a/src/cbshm/src/central_adapters/v4_2.cpp b/src/cbshm/src/central_adapters/v4_2.cpp index 01e5ea00..414cc09c 100644 --- a/src/cbshm/src/central_adapters/v4_2.cpp +++ b/src/cbshm/src/central_adapters/v4_2.cpp @@ -15,14 +15,120 @@ namespace cbshm { namespace central_v4_2 { -Adapter::Adapter(void* cfg_ptr) : cfg(static_cast(cfg_ptr)) { +size_t BootstrapAdapter::getConfigBufferSize() const { + return sizeof(cbCFGBUFF); +} + +size_t BootstrapAdapter::getReceiveBufferSize() const { + return sizeof(cbRECBUFF); +} + +size_t BootstrapAdapter::getTransmitBufferSize() const { + return sizeof(cbXMTBUFF); +} + +size_t BootstrapAdapter::getTransmitBufferLocalSize() const { + return sizeof(cbXMTBUFFLOCAL); +} + +size_t BootstrapAdapter::getStatusBufferSize() const { + return sizeof(cbPcStatus); +} + +size_t BootstrapAdapter::getSpikeBufferSize() const { + return sizeof(cbSPKBUFF); +} + +size_t BootstrapAdapter::getReceiveBufferLen() const { + return sizeof(cbRECBUFFLEN); +} + +Adapter::Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) + : cfg(static_cast(cfg_ptr)) + , rec(static_cast(rec_ptr)) + , xmt(static_cast(xmt_ptr)) + , xmt_local(static_cast(xmt_local_ptr)) + , status(static_cast(status_ptr)) + , spike(static_cast(spike_ptr)) +{} + +uint32_t& Adapter::getRecReceived() { + return rec->received; +} + +uint64_t Adapter::getRecLasttime() { + return rec->lasttime; +} + +void Adapter::setRecLasttime(uint64_t lasttime) { + rec->lasttime = lasttime; +} + +uint32_t& Adapter::getRecHeadwrapPtr() { + return rec->headwrap; +} + +uint32_t& Adapter::getRecHeadindexPtr() { + return rec->headindex; +} + +uint32_t* Adapter::getRecBufferPtr() { + return rec->buffer; +} + +uint32_t& Adapter::getXmtTransmittedPtr() { + return xmt->transmitted; +} + +uint32_t& Adapter::getXmtHeadindexPtr() { + return xmt->headindex; +} + +uint32_t& Adapter::getXmtTailindexPtr() { + return xmt->tailindex; +} + +uint32_t& Adapter::getXmtLastValidIndexPtr() { + return xmt->last_valid_index; +} + +uint32_t& Adapter::getXmtBufferlenPtr() { + return xmt->bufferlen; +} + +uint32_t* Adapter::getXmtBufferPtr() { + return xmt->buffer; +} + +uint32_t& Adapter::getLocalXmtTransmittedPtr() { + return xmt->transmitted; +} + +uint32_t& Adapter::getLocalXmtHeadindexPtr() { + return xmt->headindex; +} + +uint32_t& Adapter::getLocalXmtTailindexPtr() { + return xmt->tailindex; +} + +uint32_t& Adapter::getLocalXmtLastValidIndexPtr() { + return xmt->last_valid_index; +} + +uint32_t& Adapter::getLocalXmtBufferlenPtr() { + return xmt->bufferlen; +} + +uint32_t* Adapter::getLocalXmtBufferPtr() { + return xmt->buffer; } Result<::cbPKT_PROCINFO> Adapter::getProcInfo(uint8_t instrument_idx) const { if (instrument_idx >= std::size(cfg->procinfo)) { return Result<::cbPKT_PROCINFO>::error("Instrument index out of range"); } - return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx])); + return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx], { .instrument_idx = instrument_idx })); } Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const { @@ -33,7 +139,7 @@ Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t b if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result<::cbPKT_BANKINFO>::error("Bank number out of range"); } - return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx])); + return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx], {})); } Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const { @@ -44,18 +150,18 @@ Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result<::cbPKT_FILTINFO>::error("Filter number out of range"); } - return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx])); + return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx], {})); } Result<::cbPKT_CHANINFO> Adapter::getChanInfo(uint32_t channel_idx) const { if (channel_idx >= std::size(cfg->chaninfo)) { return Result<::cbPKT_CHANINFO>::error("Channel number out of range"); } - return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx])); + return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx], {})); } Result<::cbPKT_SYSINFO> Adapter::getSysInfo() const { - return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo)); + return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo, {})); } Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const { @@ -65,14 +171,28 @@ Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint8_t instrument_idx, uint32_t if (group_idx >= std::size(cfg->groupinfo[0])) { return Result<::cbPKT_GROUPINFO>::error("Group index out of range"); } - return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx])); + return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx], {})); +} + +Result Adapter::getConfigBuffer(uint8_t instrument_idx) const { + if (instrument_idx >= std::size(cfg->procinfo)) { + return Result::error("Instrument index out of range"); + } + return Result::ok(fromLegacy(*cfg, { .instrument_idx = instrument_idx })); +} + +Result Adapter::getPcStatus(uint8_t instrument_idx) const { + if (instrument_idx >= std::size(status->isSelection)) { + return Result::error("Instrument index out of range"); + } + return Result::ok(fromLegacy(*status, { .instrument_idx = instrument_idx })); } Result Adapter::setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) { if (instrument_idx >= std::size(cfg->procinfo)) { return Result::error("Instrument index out of range"); } - cfg->procinfo[instrument_idx] = toLegacy(info); + cfg->procinfo[instrument_idx] = toLegacy(info, {}); return Result::ok(); } @@ -84,7 +204,7 @@ Result Adapter::setBankInfo(uint8_t instrument_idx, uint32_t bank_num, con if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result::error("Bank number out of range"); } - cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info); + cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info, {}); return Result::ok(); } @@ -96,7 +216,7 @@ Result Adapter::setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result::error("Filter number out of range"); } - cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info); + cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info, {}); return Result::ok(); } @@ -104,12 +224,12 @@ Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& if (channel_idx >= std::size(cfg->chaninfo)) { return Result::error("Channel number out of range"); } - cfg->chaninfo[channel_idx] = toLegacy(info); + cfg->chaninfo[channel_idx] = toLegacy(info, {}); return Result::ok(); } Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { - cfg->sysinfo = toLegacy(info); + cfg->sysinfo = toLegacy(info, {}); return Result::ok(); } @@ -120,7 +240,15 @@ Result Adapter::setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, c if (group_idx >= std::size(cfg->groupinfo[0])) { return Result::error("Group index out of range"); } - cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info); + cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info, {}); + return Result::ok(); +} + +Result Adapter::setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const { + if (instrument_idx >= std::size(this->status->isSelection)) { + return Result::error("Instrument index out of range"); + } + *(this->status) = toLegacy(status, { .instrument_idx = instrument_idx }); return Result::ok(); } diff --git a/src/cbshm/src/central_translators/v3_11.cpp b/src/cbshm/src/central_translators/v3_11.cpp index 9c0751b8..a6025b2f 100644 --- a/src/cbshm/src/central_translators/v3_11.cpp +++ b/src/cbshm/src/central_translators/v3_11.cpp @@ -15,20 +15,20 @@ namespace cbshm { namespace central_v3_11 { -::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) { +::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg, const TranslationContext& ctx) { ::cbPKT_HEADER cur{}; cur.time = leg.time; // TODO: explicit or implicit conversion here (?) (and for all PROCTIME) cur.chid = leg.chid; cur.type = static_cast(leg.type); cur.dlen = static_cast(leg.dlen); - cur.instrument = 0; // TODO: VERIFY + cur.instrument = 0; cur.reserved = 0; return cur; } -::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) { +::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg, const TranslationContext& ctx) { ::cbPKT_SYSINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.sysfreq = leg.sysfreq; cur.spikelen = leg.spikelen; cur.spikepre = leg.spikepre; @@ -38,9 +38,9 @@ ::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) { return cur; } -::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) { +::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg, const TranslationContext& ctx) { ::cbPKT_PROCINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.proc = leg.proc; cur.idcode = leg.idcode; cur.idcode = leg.idcode; @@ -58,9 +58,9 @@ ::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) { return cur; } -::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) { +::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg, const TranslationContext& ctx) { ::cbPKT_BANKINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.proc = leg.proc; cur.bank = leg.bank; cur.idcode = leg.idcode; @@ -71,9 +71,9 @@ ::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) { return cur; } -::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) { +::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg, const TranslationContext& ctx) { ::cbPKT_GROUPINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.proc = leg.proc; cur.group = leg.group; copyArr(cur.label, leg.label); @@ -83,9 +83,9 @@ ::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) { return cur; } -::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) { +::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg, const TranslationContext& ctx) { ::cbPKT_FILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.proc = leg.proc; cur.filt = leg.filt; copyArr(cur.label, leg.label); @@ -107,9 +107,9 @@ ::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) { return cur; } -::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) { +::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg, const TranslationContext& ctx) { ::cbPKT_ADAPTFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.nMode = leg.nMode; cur.dLearningRate = leg.dLearningRate; @@ -118,16 +118,16 @@ ::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) { return cur; } -::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg) { +::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg, const TranslationContext& ctx) { ::cbPKT_REFELECFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.nMode = leg.nMode; cur.nRefChan = leg.nRefChan; return cur; } -::cbSCALING fromLegacy(const cbSCALING& leg) { +::cbSCALING fromLegacy(const cbSCALING& leg, const TranslationContext& ctx) { ::cbSCALING cur{}; cur.digmin = leg.digmin; cur.digmax = leg.digmax; @@ -138,7 +138,7 @@ ::cbSCALING fromLegacy(const cbSCALING& leg) { return cur; } -::cbFILTDESC fromLegacy(const cbFILTDESC& leg) { +::cbFILTDESC fromLegacy(const cbFILTDESC& leg, const TranslationContext& ctx) { ::cbFILTDESC cur{}; cur.hpfreq = leg.hpfreq; cur.hporder = leg.hporder; @@ -149,7 +149,7 @@ ::cbFILTDESC fromLegacy(const cbFILTDESC& leg) { return cur; } -::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) { +::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg, const TranslationContext& ctx) { ::cbMANUALUNITMAPPING cur{}; cur.nOverride = leg.nOverride; copyArr(cur.afOrigin, leg.afOrigin); @@ -159,7 +159,7 @@ ::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) { return cur; } -::cbHOOP fromLegacy(const cbHOOP& leg) { +::cbHOOP fromLegacy(const cbHOOP& leg, const TranslationContext& ctx) { ::cbHOOP cur{}; cur.valid = leg.valid; cur.time = leg.time; @@ -168,9 +168,9 @@ ::cbHOOP fromLegacy(const cbHOOP& leg) { return cur; } -::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) { +::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg, const TranslationContext& ctx) { ::cbPKT_CHANINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.proc = leg.proc; cur.bank = leg.bank; @@ -181,15 +181,15 @@ ::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) { cur.aoutcaps = leg.aoutcaps; cur.ainpcaps = leg.ainpcaps; cur.spkcaps = leg.spkcaps; - cur.physcalin = fromLegacy(leg.physcalin); - cur.phyfiltin = fromLegacy(leg.phyfiltin); - cur.physcalout = fromLegacy(leg.physcalout); - cur.phyfiltout = fromLegacy(leg.phyfiltout); + cur.physcalin = fromLegacy(leg.physcalin, ctx); + cur.phyfiltin = fromLegacy(leg.phyfiltin, ctx); + cur.physcalout = fromLegacy(leg.physcalout, ctx); + cur.phyfiltout = fromLegacy(leg.phyfiltout, ctx); copyArr(cur.label, leg.label); cur.userflags = leg.userflags; copyArr(cur.position, leg.position); - cur.scalin = fromLegacy(leg.scalin); - cur.scalout = fromLegacy(leg.scalout); + cur.scalin = fromLegacy(leg.scalin, ctx); + cur.scalout = fromLegacy(leg.scalout, ctx); cur.doutopts = leg.doutopts; cur.dinpopts = leg.dinpopts; cur.aoutopts = leg.aoutopts; @@ -218,14 +218,14 @@ ::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) { cur.amplrejpos = leg.amplrejpos; cur.amplrejneg = leg.amplrejneg; cur.refelecchan = leg.refelecchan; - copyArr(cur.unitmapping, leg.unitmapping, fromLegacy); - copyArr2D(cur.spkhoops, leg.spkhoops, fromLegacy); + copyArr(cur.unitmapping, leg.unitmapping, fromLegacy, ctx); + copyArr2D(cur.spkhoops, leg.spkhoops, fromLegacy, ctx); return cur; } -::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) { +::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg, const TranslationContext& ctx) { ::cbPKT_FS_BASIS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.mode = leg.mode; cur.fs = leg.fs; @@ -233,9 +233,9 @@ ::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) { return cur; } -::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) { +::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg, const TranslationContext& ctx) { ::cbPKT_SS_MODELSET cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.unit_number = leg.unit_number; cur.valid = leg.valid; @@ -253,34 +253,34 @@ ::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) { return cur; } -::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg) { +::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg, const TranslationContext& ctx) { ::cbPKT_SS_DETECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.fThreshold = leg.fThreshold; cur.fMultiplier = leg.fMultiplier; return cur; } -::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) { +::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg, const TranslationContext& ctx) { ::cbPKT_SS_ARTIF_REJECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.nMaxSimulChans = leg.nMaxSimulChans; cur.nRefractoryCount = leg.nRefractoryCount; return cur; } -::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) { +::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg, const TranslationContext& ctx) { ::cbPKT_SS_NOISE_BOUNDARY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; copyArr(cur.afc, leg.afc); copyArr2D(cur.afS, leg.afS); return cur; } -::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) { +::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg, const TranslationContext& ctx) { ::cbPKT_SS_STATISTICS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.nUpdateSpikes = leg.nUpdateSpikes; cur.nAutoalg = leg.nAutoalg; cur.nMode = leg.nMode; @@ -296,7 +296,7 @@ ::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) { return cur; } -::cbAdaptControl fromLegacy(const cbAdaptControl& leg) { +::cbAdaptControl fromLegacy(const cbAdaptControl& leg, const TranslationContext& ctx) { ::cbAdaptControl cur{}; cur.nMode = leg.nMode; cur.fTimeOutMinutes = leg.fTimeOutMinutes; @@ -304,39 +304,39 @@ ::cbAdaptControl fromLegacy(const cbAdaptControl& leg) { return cur; } -::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg) { +::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg, const TranslationContext& ctx) { ::cbPKT_SS_STATUS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); - cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats); - cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); + cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats, ctx); + cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits, ctx); return cur; } -::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg) { +::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg, const TranslationContext& ctx) { ::cbproto::SpikeSorting cur{}; - copyArr(cur.basis, leg.asBasis, fromLegacy); - copyArr2D(cur.models, leg.asSortModel, fromLegacy); - cur.detect = fromLegacy(leg.pktDetect); - cur.artifact_reject = fromLegacy(leg.pktArtifReject); - copyArr(cur.noise_boundary, leg.pktNoiseBoundary, fromLegacy); - cur.statistics = fromLegacy(leg.pktStatistics); - cur.status = fromLegacy(leg.pktStatus); + copyArr(cur.basis, leg.asBasis, fromLegacy, ctx); + copyArr2D(cur.models, leg.asSortModel, fromLegacy, ctx); + cur.detect = fromLegacy(leg.pktDetect, ctx); + cur.artifact_reject = fromLegacy(leg.pktArtifReject, ctx); + copyArr(cur.noise_boundary, leg.pktNoiseBoundary, fromLegacy, ctx); + cur.statistics = fromLegacy(leg.pktStatistics, ctx); + cur.status = fromLegacy(leg.pktStatus, ctx); return cur; } -::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg) { +::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg, const TranslationContext& ctx) { ::cbPKT_NTRODEINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.ntrode = leg.ntrode; copyArr(cur.label, leg.label); - copyArr2D(cur.ellipses, leg.ellipses, fromLegacy); + copyArr2D(cur.ellipses, leg.ellipses, fromLegacy, ctx); cur.nSite = leg.nSite; cur.fs = leg.fs; copyArr(cur.nChan, leg.nChan); return cur; } -::cbWaveformData fromLegacy(const cbWaveformData& leg) { +::cbWaveformData fromLegacy(const cbWaveformData& leg, const TranslationContext& ctx) { ::cbWaveformData cur{}; cur.offset = leg.offset; // aka sineFrequency cur.seq = leg.seq; // aka sineAmplitude @@ -347,9 +347,9 @@ ::cbWaveformData fromLegacy(const cbWaveformData& leg) { return cur; } -::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) { +::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg, const TranslationContext& ctx) { ::cbPKT_AOUT_WAVEFORM cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.mode = leg.mode; cur.repeats = leg.repeats; @@ -359,22 +359,22 @@ ::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) { cur.trigValue = leg.trigValue; cur.trigNum = leg.trigNum; cur.active = leg.active; - cur.wave = fromLegacy(leg.wave); + cur.wave = fromLegacy(leg.wave, ctx); return cur; } -::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg) { +::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg, const TranslationContext& ctx) { ::cbPKT_LNC cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.lncFreq = leg.lncFreq; cur.lncRefChan = leg.lncRefChan; cur.lncGlobalMode = leg.lncGlobalMode; return cur; } -::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) { +::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg, const TranslationContext& ctx) { ::cbPKT_NPLAY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.ftime = leg.ftime; // aka opt cur.stime = leg.stime; cur.etime = leg.etime; @@ -386,14 +386,14 @@ ::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) { return cur; } -::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg) { +::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg, const TranslationContext& ctx) { ::cbVIDEOSOURCE cur{}; copyArr(cur.name, leg.name); cur.fps = leg.fps; return cur; } -::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) { +::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg, const TranslationContext& ctx) { ::cbTRACKOBJ cur{}; copyArr(cur.name, leg.name); cur.type = leg.type; @@ -401,9 +401,9 @@ ::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) { return cur; } -::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) { +::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg, const TranslationContext& ctx) { ::cbPKT_FILECFG cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.options = leg.options; cur.duration = leg.duration; cur.recording = leg.recording; @@ -414,7 +414,118 @@ ::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) { return cur; } -cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) { +NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg, const TranslationContext& ctx) { + // TODO: VERIFY that each list that's assumed to be instrument-independent is in fact independent from any particular instrument. + NativeConfigBuffer cur{}; + cur.version = leg.version; + cur.sysflags = leg.sysflags; + cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); + cur.sysinfo = fromLegacy(leg.sysinfo, ctx); + cur.procinfo = fromLegacy(leg.procinfo[ctx.instrument_idx], ctx); + copyArr(cur.bankinfo, leg.bankinfo[ctx.instrument_idx], fromLegacy, ctx); + copyArr(cur.groupinfo, leg.groupinfo[ctx.instrument_idx], fromLegacy, ctx); + copyArr(cur.filtinfo, leg.filtinfo[ctx.instrument_idx], fromLegacy, ctx); + cur.adaptinfo = fromLegacy(leg.adaptinfo[ctx.instrument_idx], ctx); + cur.refelecinfo = fromLegacy(leg.refelecinfo[ctx.instrument_idx], ctx); + copyArr(cur.chaninfo, leg.chaninfo, fromLegacy, ctx); + copyArr(cur.asBasis, leg.isSortingOptions.asBasis, fromLegacy, ctx); + copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, fromLegacy, ctx); + // TODO: Move native isSortingOptions fields into a struct + cur.pktDetect = fromLegacy(leg.isSortingOptions.pktDetect, ctx); + cur.pktArtifReject = fromLegacy(leg.isSortingOptions.pktArtifReject, ctx); + copyArr(cur.pktNoiseBoundary, leg.isSortingOptions.pktNoiseBoundary, fromLegacy, ctx); + cur.pktStatistics = fromLegacy(leg.isSortingOptions.pktStatistics, ctx); + cur.pktStatus = fromLegacy(leg.isSortingOptions.pktStatus, ctx); + copyArr(cur.isNTrodeInfo, leg.isNTrodeInfo, fromLegacy, ctx); + copyArr2D(cur.isWaveform, leg.isWaveform, fromLegacy, ctx); + cur.isLnc = fromLegacy(leg.isLnc[ctx.instrument_idx], ctx); + cur.isNPlay = fromLegacy(leg.isNPlay, ctx); + copyArr(cur.isVideoSource, leg.isVideoSource, fromLegacy, ctx); + copyArr(cur.isTrackObj, leg.isTrackObj, fromLegacy, ctx); + cur.fileinfo = fromLegacy(leg.fileinfo, ctx); + + return cur; +} + +NativeNSPStatus fromLegacy(const NSPStatus& leg, const TranslationContext& ctx) { + switch(leg) { + case NSPStatus::NSP_INIT: + return NativeNSPStatus::NSP_INIT; + case NSPStatus::NSP_NOIPADDR: + return NativeNSPStatus::NSP_NOIPADDR; + case NSPStatus::NSP_NOREPLY: + return NativeNSPStatus::NSP_NOREPLY; + case NSPStatus::NSP_FOUND: + return NativeNSPStatus::NSP_FOUND; + case NSPStatus::NSP_INVALID: + default: + return NativeNSPStatus::NSP_INVALID; + } +} + +::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg, const TranslationContext& ctx) { + ::cbPKT_UNIT_SELECTION cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); + cur.lastchan = leg.lastchan; + copyArr(cur.abyUnitSelections, leg.abyUnitSelections); + return cur; +} + +NativePCStatus fromLegacy(const cbPcStatus& leg, const TranslationContext& ctx) { + NativePCStatus cur{}; + cur.isSelection = fromLegacy(leg.isSelection[ctx.instrument_idx], ctx); + cur.m_iBlockRecording = leg.m_iBlockRecording; + cur.m_nPCStatusFlags = leg.m_nPCStatusFlags; + cur.m_nNumFEChans = leg.m_nNumFEChans; + cur.m_nNumAnainChans = leg.m_nNumAnainChans; + cur.m_nNumAnalogChans = leg.m_nNumAnalogChans; + cur.m_nNumAoutChans = leg.m_nNumAoutChans; + cur.m_nNumAudioChans = leg.m_nNumAudioChans; + cur.m_nNumAnalogoutChans = leg.m_nNumAnalogoutChans; + cur.m_nNumDiginChans = leg.m_nNumDiginChans; + cur.m_nNumSerialChans = leg.m_nNumSerialChans; + cur.m_nNumDigoutChans = leg.m_nNumDigoutChans; + cur.m_nNumTotalChans = leg.m_nNumTotalChans; + cur.m_nNspStatus = NativeNSPStatus::NSP_FOUND; // TODO: VERIFY + cur.m_nNumNTrodesPerInstrument = cbMAXNTRODES; // TODO: VERIFY + cur.m_nGeminiSystem = 1; // TODO: VERIFY + // ignore APP_WORKSPACE + return cur; +} + +NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg, const TranslationContext& ctx) { + NativeReceiveBuffer cur{}; + cur.received = leg.received; + cur.lasttime = leg.lasttime; + cur.headwrap = leg.headwrap; + cur.headindex = leg.headindex; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg, const TranslationContext& ctx) { + NativeTransmitBuffer cur{}; + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg, const TranslationContext& ctx) { + NativeTransmitBufferLocal cur{}; + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur, const TranslationContext& ctx) { cbPKT_HEADER leg{}; leg.time = cur.time; leg.chid = cur.chid; @@ -423,9 +534,9 @@ cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) { return leg; } -cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) { +cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur, const TranslationContext& ctx) { cbPKT_SYSINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.sysfreq = cur.sysfreq; leg.spikelen = cur.spikelen; leg.spikepre = cur.spikepre; @@ -435,9 +546,9 @@ cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) { return leg; } -cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) { +cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur, const TranslationContext& ctx) { cbPKT_PROCINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.proc = cur.proc; leg.idcode = cur.idcode; leg.idcode = cur.idcode; @@ -455,9 +566,9 @@ cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) { return leg; } -cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) { +cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur, const TranslationContext& ctx) { cbPKT_BANKINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.proc = cur.proc; leg.bank = cur.bank; leg.idcode = cur.idcode; @@ -468,9 +579,9 @@ cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) { return leg; } -cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) { +cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur, const TranslationContext& ctx) { cbPKT_GROUPINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.proc = cur.proc; leg.group = cur.group; copyArr(leg.label, cur.label); @@ -480,9 +591,9 @@ cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) { return leg; } -cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) { +cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur, const TranslationContext& ctx) { cbPKT_FILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.proc = cur.proc; leg.filt = cur.filt; copyArr(leg.label, cur.label); @@ -504,9 +615,9 @@ cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) { return leg; } -cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) { +cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur, const TranslationContext& ctx) { cbPKT_ADAPTFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.nMode = cur.nMode; leg.dLearningRate = cur.dLearningRate; @@ -515,16 +626,16 @@ cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) { return leg; } -cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur) { +cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur, const TranslationContext& ctx) { cbPKT_REFELECFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.nMode = cur.nMode; leg.nRefChan = cur.nRefChan; return leg; } -cbSCALING toLegacy(const ::cbSCALING& cur) { +cbSCALING toLegacy(const ::cbSCALING& cur, const TranslationContext& ctx) { cbSCALING leg{}; leg.digmin = cur.digmin; leg.digmax = cur.digmax; @@ -535,7 +646,7 @@ cbSCALING toLegacy(const ::cbSCALING& cur) { return leg; } -cbFILTDESC toLegacy(const ::cbFILTDESC& cur) { +cbFILTDESC toLegacy(const ::cbFILTDESC& cur, const TranslationContext& ctx) { cbFILTDESC leg{}; leg.hpfreq = cur.hpfreq; leg.hporder = cur.hporder; @@ -546,7 +657,7 @@ cbFILTDESC toLegacy(const ::cbFILTDESC& cur) { return leg; } -cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) { +cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur, const TranslationContext& ctx) { cbMANUALUNITMAPPING leg{}; leg.nOverride = cur.nOverride; copyArr(leg.afOrigin, cur.afOrigin); @@ -556,7 +667,7 @@ cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) { return leg; } -cbHOOP toLegacy(const ::cbHOOP& cur) { +cbHOOP toLegacy(const ::cbHOOP& cur, const TranslationContext& ctx) { cbHOOP leg{}; leg.valid = cur.valid; leg.time = cur.time; @@ -565,9 +676,9 @@ cbHOOP toLegacy(const ::cbHOOP& cur) { return leg; } -cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) { +cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur, const TranslationContext& ctx) { cbPKT_CHANINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.proc = cur.proc; leg.bank = cur.bank; @@ -578,15 +689,15 @@ cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) { leg.aoutcaps = cur.aoutcaps; leg.ainpcaps = cur.ainpcaps; leg.spkcaps = cur.spkcaps; - leg.physcalin = toLegacy(cur.physcalin); - leg.phyfiltin = toLegacy(cur.phyfiltin); - leg.physcalout = toLegacy(cur.physcalout); - leg.phyfiltout = toLegacy(cur.phyfiltout); + leg.physcalin = toLegacy(cur.physcalin, ctx); + leg.phyfiltin = toLegacy(cur.phyfiltin, ctx); + leg.physcalout = toLegacy(cur.physcalout, ctx); + leg.phyfiltout = toLegacy(cur.phyfiltout, ctx); copyArr(leg.label, cur.label); leg.userflags = cur.userflags; copyArr(leg.position, cur.position); - leg.scalin = toLegacy(cur.scalin); - leg.scalout = toLegacy(cur.scalout); + leg.scalin = toLegacy(cur.scalin, ctx); + leg.scalout = toLegacy(cur.scalout, ctx); leg.doutopts = cur.doutopts; leg.dinpopts = cur.dinpopts; leg.aoutopts = cur.aoutopts; @@ -612,14 +723,14 @@ cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) { leg.amplrejpos = cur.amplrejpos; leg.amplrejneg = cur.amplrejneg; leg.refelecchan = cur.refelecchan; - copyArr(leg.unitmapping, cur.unitmapping, toLegacy); - copyArr2D(leg.spkhoops, cur.spkhoops, toLegacy); + copyArr(leg.unitmapping, cur.unitmapping, toLegacy, ctx); + copyArr2D(leg.spkhoops, cur.spkhoops, toLegacy, ctx); return leg; } -cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) { +cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur, const TranslationContext& ctx) { cbPKT_FS_BASIS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.mode = cur.mode; leg.fs = cur.fs; @@ -627,9 +738,9 @@ cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) { return leg; } -cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) { +cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur, const TranslationContext& ctx) { cbPKT_SS_MODELSET leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.unit_number = cur.unit_number; leg.valid = cur.valid; @@ -647,34 +758,34 @@ cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) { return leg; } -cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur) { +cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur, const TranslationContext& ctx) { cbPKT_SS_DETECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.fThreshold = cur.fThreshold; leg.fMultiplier = cur.fMultiplier; return leg; } -cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) { +cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur, const TranslationContext& ctx) { cbPKT_SS_ARTIF_REJECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.nMaxSimulChans = cur.nMaxSimulChans; leg.nRefractoryCount = cur.nRefractoryCount; return leg; } -cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) { +cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur, const TranslationContext& ctx) { cbPKT_SS_NOISE_BOUNDARY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; copyArr(leg.afc, cur.afc); copyArr2D(leg.afS, cur.afS); return leg; } -cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) { +cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur, const TranslationContext& ctx) { cbPKT_SS_STATISTICS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.nUpdateSpikes = cur.nUpdateSpikes; leg.nAutoalg = cur.nAutoalg; leg.nMode = cur.nMode; @@ -690,7 +801,7 @@ cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) { return leg; } -cbAdaptControl toLegacy(const ::cbAdaptControl& cur) { +cbAdaptControl toLegacy(const ::cbAdaptControl& cur, const TranslationContext& ctx) { cbAdaptControl leg{}; leg.nMode = cur.nMode; leg.fTimeOutMinutes = cur.fTimeOutMinutes; @@ -698,39 +809,39 @@ cbAdaptControl toLegacy(const ::cbAdaptControl& cur) { return leg; } -cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur) { +cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur, const TranslationContext& ctx) { cbPKT_SS_STATUS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); - leg.cntlUnitStats = toLegacy(cur.cntlUnitStats); - leg.cntlNumUnits = toLegacy(cur.cntlNumUnits); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); + leg.cntlUnitStats = toLegacy(cur.cntlUnitStats, ctx); + leg.cntlNumUnits = toLegacy(cur.cntlNumUnits, ctx); return leg; } -cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur) { +cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur, const TranslationContext& ctx) { cbSPIKE_SORTING leg{}; - copyArr(leg.asBasis, cur.basis, toLegacy); - copyArr2D(leg.asSortModel, cur.models, toLegacy); - leg.pktDetect = toLegacy(cur.detect); - leg.pktArtifReject = toLegacy(cur.artifact_reject); - copyArr(leg.pktNoiseBoundary, cur.noise_boundary, toLegacy); - leg.pktStatistics = toLegacy(cur.statistics); - leg.pktStatus = toLegacy(cur.status); + copyArr(leg.asBasis, cur.basis, toLegacy, ctx); + copyArr2D(leg.asSortModel, cur.models, toLegacy, ctx); + leg.pktDetect = toLegacy(cur.detect, ctx); + leg.pktArtifReject = toLegacy(cur.artifact_reject, ctx); + copyArr(leg.pktNoiseBoundary, cur.noise_boundary, toLegacy, ctx); + leg.pktStatistics = toLegacy(cur.statistics, ctx); + leg.pktStatus = toLegacy(cur.status, ctx); return leg; } -cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur) { +cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur, const TranslationContext& ctx) { cbPKT_NTRODEINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.ntrode = cur.ntrode; copyArr(leg.label, cur.label); - copyArr2D(leg.ellipses, cur.ellipses, toLegacy); + copyArr2D(leg.ellipses, cur.ellipses, toLegacy, ctx); leg.nSite = cur.nSite; leg.fs = cur.fs; copyArr(leg.nChan, cur.nChan); return leg; } -cbWaveformData toLegacy(const ::cbWaveformData& cur) { +cbWaveformData toLegacy(const ::cbWaveformData& cur, const TranslationContext& ctx) { cbWaveformData leg{}; leg.offset = cur.offset; // aka sineFrequency leg.seq = cur.seq; // aka sineAmplitude @@ -741,9 +852,9 @@ cbWaveformData toLegacy(const ::cbWaveformData& cur) { return leg; } -cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) { +cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur, const TranslationContext& ctx) { cbPKT_AOUT_WAVEFORM leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.mode = cur.mode; leg.repeats = cur.repeats; @@ -752,22 +863,22 @@ cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) { leg.trigValue = cur.trigValue; leg.trigNum = cur.trigNum; leg.active = cur.active; - leg.wave = toLegacy(cur.wave); + leg.wave = toLegacy(cur.wave, ctx); return leg; } -cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur) { +cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur, const TranslationContext& ctx) { cbPKT_LNC leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.lncFreq = cur.lncFreq; leg.lncRefChan = cur.lncRefChan; leg.lncGlobalMode = cur.lncGlobalMode; return leg; } -cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) { +cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur, const TranslationContext& ctx) { cbPKT_NPLAY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.ftime = cur.ftime; // aka opt leg.stime = cur.stime; leg.etime = cur.etime; @@ -779,14 +890,14 @@ cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) { return leg; } -cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) { +cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur, const TranslationContext& ctx) { cbVIDEOSOURCE leg{}; copyArr(leg.name, cur.name); leg.fps = cur.fps; return leg; } -cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) { +cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur, const TranslationContext& ctx) { cbTRACKOBJ leg{}; copyArr(leg.name, cur.name); leg.type = cur.type; @@ -794,9 +905,9 @@ cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) { return leg; } -cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) { +cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur, const TranslationContext& ctx) { cbPKT_FILECFG leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.options = cur.options; leg.duration = cur.duration; leg.recording = cur.recording; @@ -807,6 +918,81 @@ cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) { return leg; } +NSPStatus toLegacy(const NativeNSPStatus& cur, const TranslationContext& ctx) { + switch(cur) { + case NativeNSPStatus::NSP_INIT: + return NSPStatus::NSP_INIT; + case NativeNSPStatus::NSP_NOIPADDR: + return NSPStatus::NSP_NOIPADDR; + case NativeNSPStatus::NSP_NOREPLY: + return NSPStatus::NSP_NOREPLY; + case NativeNSPStatus::NSP_FOUND: + return NSPStatus::NSP_FOUND; + case NativeNSPStatus::NSP_INVALID: + default: + return NSPStatus::NSP_INVALID; + } +} + +cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur, const TranslationContext& ctx) { + cbPKT_UNIT_SELECTION leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); + leg.lastchan = cur.lastchan; + copyArr(leg.abyUnitSelections, cur.abyUnitSelections); + return leg; +} + +cbPcStatus toLegacy(const NativePCStatus& cur, const TranslationContext& ctx) { + cbPcStatus leg{}; + leg.isSelection[ctx.instrument_idx] = toLegacy(cur.isSelection, ctx); + leg.m_iBlockRecording = cur.m_iBlockRecording; + leg.m_nPCStatusFlags = cur.m_nPCStatusFlags; + leg.m_nNumFEChans = cur.m_nNumFEChans; + leg.m_nNumAnainChans = cur.m_nNumAnainChans; + leg.m_nNumAnalogChans = cur.m_nNumAnalogChans; + leg.m_nNumAoutChans = cur.m_nNumAoutChans; + leg.m_nNumAudioChans = cur.m_nNumAudioChans; + leg.m_nNumAnalogoutChans = cur.m_nNumAnalogoutChans; + leg.m_nNumDiginChans = cur.m_nNumDiginChans; + leg.m_nNumSerialChans = cur.m_nNumSerialChans; + leg.m_nNumDigoutChans = cur.m_nNumDigoutChans; + leg.m_nNumTotalChans = cur.m_nNumTotalChans; + // ignore APP_WORKSPACE + return leg; +} + +cbRECBUFF toLegacy(const NativeReceiveBuffer& cur, const TranslationContext& ctx) { + cbRECBUFF leg{}; + leg.received = cur.received; + leg.lasttime = cur.lasttime; + leg.headwrap = cur.headwrap; + leg.headindex = cur.headindex; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur, const TranslationContext& ctx) { + cbXMTBUFF leg{}; + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur, const TranslationContext& ctx) { + cbXMTBUFFLOCAL leg{}; + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); + return leg; +} + } // namespace central_v3_11 } // namespace cbshm diff --git a/src/cbshm/src/central_translators/v4_0.cpp b/src/cbshm/src/central_translators/v4_0.cpp index 82491e3a..7867dc11 100644 --- a/src/cbshm/src/central_translators/v4_0.cpp +++ b/src/cbshm/src/central_translators/v4_0.cpp @@ -15,7 +15,7 @@ namespace cbshm { namespace central_v4_0 { -::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) { +::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg, const TranslationContext& ctx) { ::cbPKT_HEADER cur{}; cur.time = leg.time; cur.chid = leg.chid; @@ -26,9 +26,9 @@ ::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) { return cur; } -::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) { +::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg, const TranslationContext& ctx) { ::cbPKT_SYSINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.sysfreq = leg.sysfreq; cur.spikelen = leg.spikelen; cur.spikepre = leg.spikepre; @@ -38,9 +38,9 @@ ::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) { return cur; } -::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) { +::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg, const TranslationContext& ctx) { ::cbPKT_PROCINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.proc = leg.proc; cur.idcode = leg.idcode; cur.idcode = leg.idcode; @@ -58,9 +58,9 @@ ::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) { return cur; } -::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) { +::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg, const TranslationContext& ctx) { ::cbPKT_BANKINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.proc = leg.proc; cur.bank = leg.bank; cur.idcode = leg.idcode; @@ -71,9 +71,9 @@ ::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) { return cur; } -::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) { +::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg, const TranslationContext& ctx) { ::cbPKT_GROUPINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.proc = leg.proc; cur.group = leg.group; copyArr(cur.label, leg.label); @@ -83,9 +83,9 @@ ::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) { return cur; } -::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) { +::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg, const TranslationContext& ctx) { ::cbPKT_FILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.proc = leg.proc; cur.filt = leg.filt; copyArr(cur.label, leg.label); @@ -107,9 +107,9 @@ ::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) { return cur; } -::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) { +::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg, const TranslationContext& ctx) { ::cbPKT_ADAPTFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.nMode = leg.nMode; cur.dLearningRate = leg.dLearningRate; @@ -118,16 +118,16 @@ ::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) { return cur; } -::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg) { +::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg, const TranslationContext& ctx) { ::cbPKT_REFELECFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.nMode = leg.nMode; cur.nRefChan = leg.nRefChan; return cur; } -::cbSCALING fromLegacy(const cbSCALING& leg) { +::cbSCALING fromLegacy(const cbSCALING& leg, const TranslationContext& ctx) { ::cbSCALING cur{}; cur.digmin = leg.digmin; cur.digmax = leg.digmax; @@ -138,7 +138,7 @@ ::cbSCALING fromLegacy(const cbSCALING& leg) { return cur; } -::cbFILTDESC fromLegacy(const cbFILTDESC& leg) { +::cbFILTDESC fromLegacy(const cbFILTDESC& leg, const TranslationContext& ctx) { ::cbFILTDESC cur{}; cur.hpfreq = leg.hpfreq; cur.hporder = leg.hporder; @@ -149,7 +149,7 @@ ::cbFILTDESC fromLegacy(const cbFILTDESC& leg) { return cur; } -::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) { +::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg, const TranslationContext& ctx) { ::cbMANUALUNITMAPPING cur{}; cur.nOverride = leg.nOverride; copyArr(cur.afOrigin, leg.afOrigin); @@ -159,7 +159,7 @@ ::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) { return cur; } -::cbHOOP fromLegacy(const cbHOOP& leg) { +::cbHOOP fromLegacy(const cbHOOP& leg, const TranslationContext& ctx) { ::cbHOOP cur{}; cur.valid = leg.valid; cur.time = leg.time; @@ -168,9 +168,9 @@ ::cbHOOP fromLegacy(const cbHOOP& leg) { return cur; } -::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) { +::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg, const TranslationContext& ctx) { ::cbPKT_CHANINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.proc = leg.proc; cur.bank = leg.bank; @@ -181,15 +181,15 @@ ::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) { cur.aoutcaps = leg.aoutcaps; cur.ainpcaps = leg.ainpcaps; cur.spkcaps = leg.spkcaps; - cur.physcalin = fromLegacy(leg.physcalin); - cur.phyfiltin = fromLegacy(leg.phyfiltin); - cur.physcalout = fromLegacy(leg.physcalout); - cur.phyfiltout = fromLegacy(leg.phyfiltout); + cur.physcalin = fromLegacy(leg.physcalin, ctx); + cur.phyfiltin = fromLegacy(leg.phyfiltin, ctx); + cur.physcalout = fromLegacy(leg.physcalout, ctx); + cur.phyfiltout = fromLegacy(leg.phyfiltout, ctx); copyArr(cur.label, leg.label); cur.userflags = leg.userflags; copyArr(cur.position, leg.position); - cur.scalin = fromLegacy(leg.scalin); - cur.scalout = fromLegacy(leg.scalout); + cur.scalin = fromLegacy(leg.scalin, ctx); + cur.scalout = fromLegacy(leg.scalout, ctx); cur.doutopts = leg.doutopts; cur.dinpopts = leg.dinpopts; cur.aoutopts = leg.aoutopts; @@ -218,14 +218,14 @@ ::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) { cur.amplrejpos = leg.amplrejpos; cur.amplrejneg = leg.amplrejneg; cur.refelecchan = leg.refelecchan; - copyArr(cur.unitmapping, leg.unitmapping, fromLegacy); - copyArr2D(cur.spkhoops, leg.spkhoops, fromLegacy); + copyArr(cur.unitmapping, leg.unitmapping, fromLegacy, ctx); + copyArr2D(cur.spkhoops, leg.spkhoops, fromLegacy, ctx); return cur; } -::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) { +::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg, const TranslationContext& ctx) { ::cbPKT_FS_BASIS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.mode = leg.mode; cur.fs = leg.fs; @@ -233,9 +233,9 @@ ::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) { return cur; } -::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) { +::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg, const TranslationContext& ctx) { ::cbPKT_SS_MODELSET cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.unit_number = leg.unit_number; cur.valid = leg.valid; @@ -253,34 +253,34 @@ ::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) { return cur; } -::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg) { +::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg, const TranslationContext& ctx) { ::cbPKT_SS_DETECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.fThreshold = leg.fThreshold; cur.fMultiplier = leg.fMultiplier; return cur; } -::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) { +::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg, const TranslationContext& ctx) { ::cbPKT_SS_ARTIF_REJECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.nMaxSimulChans = leg.nMaxSimulChans; cur.nRefractoryCount = leg.nRefractoryCount; return cur; } -::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) { +::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg, const TranslationContext& ctx) { ::cbPKT_SS_NOISE_BOUNDARY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; copyArr(cur.afc, leg.afc); copyArr2D(cur.afS, leg.afS); return cur; } -::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) { +::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg, const TranslationContext& ctx) { ::cbPKT_SS_STATISTICS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.nUpdateSpikes = leg.nUpdateSpikes; cur.nAutoalg = leg.nAutoalg; cur.nMode = leg.nMode; @@ -296,7 +296,7 @@ ::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) { return cur; } -::cbAdaptControl fromLegacy(const cbAdaptControl& leg) { +::cbAdaptControl fromLegacy(const cbAdaptControl& leg, const TranslationContext& ctx) { ::cbAdaptControl cur{}; cur.nMode = leg.nMode; cur.fTimeOutMinutes = leg.fTimeOutMinutes; @@ -304,39 +304,39 @@ ::cbAdaptControl fromLegacy(const cbAdaptControl& leg) { return cur; } -::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg) { +::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg, const TranslationContext& ctx) { ::cbPKT_SS_STATUS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); - cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats); - cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); + cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats, ctx); + cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits, ctx); return cur; } -::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg) { +::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg, const TranslationContext& ctx) { ::cbproto::SpikeSorting cur{}; - copyArr(cur.basis, leg.asBasis, fromLegacy); - copyArr2D(cur.models, leg.asSortModel, fromLegacy); - cur.detect = fromLegacy(leg.pktDetect); - cur.artifact_reject = fromLegacy(leg.pktArtifReject); - copyArr(cur.noise_boundary, leg.pktNoiseBoundary, fromLegacy); - cur.statistics = fromLegacy(leg.pktStatistics); - cur.status = fromLegacy(leg.pktStatus); + copyArr(cur.basis, leg.asBasis, fromLegacy, ctx); + copyArr2D(cur.models, leg.asSortModel, fromLegacy, ctx); + cur.detect = fromLegacy(leg.pktDetect, ctx); + cur.artifact_reject = fromLegacy(leg.pktArtifReject, ctx); + copyArr(cur.noise_boundary, leg.pktNoiseBoundary, fromLegacy, ctx); + cur.statistics = fromLegacy(leg.pktStatistics, ctx); + cur.status = fromLegacy(leg.pktStatus, ctx); return cur; } -::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg) { +::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg, const TranslationContext& ctx) { ::cbPKT_NTRODEINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.ntrode = leg.ntrode; copyArr(cur.label, leg.label); - copyArr2D(cur.ellipses, leg.ellipses, fromLegacy); + copyArr2D(cur.ellipses, leg.ellipses, fromLegacy, ctx); cur.nSite = leg.nSite; cur.fs = leg.fs; copyArr(cur.nChan, leg.nChan); return cur; } -::cbWaveformData fromLegacy(const cbWaveformData& leg) { +::cbWaveformData fromLegacy(const cbWaveformData& leg, const TranslationContext& ctx) { ::cbWaveformData cur{}; cur.offset = leg.offset; // aka sineFrequency cur.seq = leg.seq; // aka sineAmplitude @@ -347,9 +347,9 @@ ::cbWaveformData fromLegacy(const cbWaveformData& leg) { return cur; } -::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) { +::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg, const TranslationContext& ctx) { ::cbPKT_AOUT_WAVEFORM cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.mode = leg.mode; cur.repeats = leg.repeats; @@ -359,22 +359,22 @@ ::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) { cur.trigValue = leg.trigValue; cur.trigNum = leg.trigNum; cur.active = leg.active; - cur.wave = fromLegacy(leg.wave); + cur.wave = fromLegacy(leg.wave, ctx); return cur; } -::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg) { +::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg, const TranslationContext& ctx) { ::cbPKT_LNC cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.lncFreq = leg.lncFreq; cur.lncRefChan = leg.lncRefChan; cur.lncGlobalMode = leg.lncGlobalMode; return cur; } -::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) { +::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg, const TranslationContext& ctx) { ::cbPKT_NPLAY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.ftime = leg.ftime; // aka opt cur.stime = leg.stime; cur.etime = leg.etime; @@ -386,14 +386,14 @@ ::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) { return cur; } -::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg) { +::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg, const TranslationContext& ctx) { ::cbVIDEOSOURCE cur{}; copyArr(cur.name, leg.name); cur.fps = leg.fps; return cur; } -::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) { +::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg, const TranslationContext& ctx) { ::cbTRACKOBJ cur{}; copyArr(cur.name, leg.name); cur.type = leg.type; @@ -401,9 +401,9 @@ ::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) { return cur; } -::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) { +::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg, const TranslationContext& ctx) { ::cbPKT_FILECFG cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.options = leg.options; cur.duration = leg.duration; cur.recording = leg.recording; @@ -414,7 +414,118 @@ ::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) { return cur; } -cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) { +NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg, const TranslationContext& ctx) { + // TODO: VERIFY that each list that's assumed to be instrument-independent is in fact independent from any particular instrument. + NativeConfigBuffer cur{}; + cur.version = leg.version; + cur.sysflags = leg.sysflags; + cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); + cur.sysinfo = fromLegacy(leg.sysinfo, ctx); + cur.procinfo = fromLegacy(leg.procinfo[ctx.instrument_idx], ctx); + copyArr(cur.bankinfo, leg.bankinfo[ctx.instrument_idx], fromLegacy, ctx); + copyArr(cur.groupinfo, leg.groupinfo[ctx.instrument_idx], fromLegacy, ctx); + copyArr(cur.filtinfo, leg.filtinfo[ctx.instrument_idx], fromLegacy, ctx); + cur.adaptinfo = fromLegacy(leg.adaptinfo[ctx.instrument_idx], ctx); + cur.refelecinfo = fromLegacy(leg.refelecinfo[ctx.instrument_idx], ctx); + copyArr(cur.chaninfo, leg.chaninfo, fromLegacy, ctx); + copyArr(cur.asBasis, leg.isSortingOptions.asBasis, fromLegacy, ctx); + copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, fromLegacy, ctx); + // TODO: Move native isSortingOptions fields into a struct + cur.pktDetect = fromLegacy(leg.isSortingOptions.pktDetect, ctx); + cur.pktArtifReject = fromLegacy(leg.isSortingOptions.pktArtifReject, ctx); + copyArr(cur.pktNoiseBoundary, leg.isSortingOptions.pktNoiseBoundary, fromLegacy, ctx); + cur.pktStatistics = fromLegacy(leg.isSortingOptions.pktStatistics, ctx); + cur.pktStatus = fromLegacy(leg.isSortingOptions.pktStatus, ctx); + copyArr(cur.isNTrodeInfo, leg.isNTrodeInfo, fromLegacy, ctx); + copyArr2D(cur.isWaveform, leg.isWaveform, fromLegacy, ctx); + cur.isLnc = fromLegacy(leg.isLnc[ctx.instrument_idx], ctx); + cur.isNPlay = fromLegacy(leg.isNPlay, ctx); + copyArr(cur.isVideoSource, leg.isVideoSource, fromLegacy, ctx); + copyArr(cur.isTrackObj, leg.isTrackObj, fromLegacy, ctx); + cur.fileinfo = fromLegacy(leg.fileinfo, ctx); + + return cur; +} + +NativeNSPStatus fromLegacy(const NSPStatus& leg, const TranslationContext& ctx) { + switch(leg) { + case NSPStatus::NSP_INIT: + return NativeNSPStatus::NSP_INIT; + case NSPStatus::NSP_NOIPADDR: + return NativeNSPStatus::NSP_NOIPADDR; + case NSPStatus::NSP_NOREPLY: + return NativeNSPStatus::NSP_NOREPLY; + case NSPStatus::NSP_FOUND: + return NativeNSPStatus::NSP_FOUND; + case NSPStatus::NSP_INVALID: + default: + return NativeNSPStatus::NSP_INVALID; + } +} + +::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg, const TranslationContext& ctx) { + ::cbPKT_UNIT_SELECTION cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); + cur.lastchan = leg.lastchan; + copyArr(cur.abyUnitSelections, leg.abyUnitSelections); + return cur; +} + +NativePCStatus fromLegacy(const cbPcStatus& leg, const TranslationContext& ctx) { + NativePCStatus cur{}; + cur.isSelection = fromLegacy(leg.isSelection[ctx.instrument_idx], ctx); + cur.m_iBlockRecording = leg.m_iBlockRecording; + cur.m_nPCStatusFlags = leg.m_nPCStatusFlags; + cur.m_nNumFEChans = leg.m_nNumFEChans; + cur.m_nNumAnainChans = leg.m_nNumAnainChans; + cur.m_nNumAnalogChans = leg.m_nNumAnalogChans; + cur.m_nNumAoutChans = leg.m_nNumAoutChans; + cur.m_nNumAudioChans = leg.m_nNumAudioChans; + cur.m_nNumAnalogoutChans = leg.m_nNumAnalogoutChans; + cur.m_nNumDiginChans = leg.m_nNumDiginChans; + cur.m_nNumSerialChans = leg.m_nNumSerialChans; + cur.m_nNumDigoutChans = leg.m_nNumDigoutChans; + cur.m_nNumTotalChans = leg.m_nNumTotalChans; + cur.m_nNspStatus = fromLegacy(leg.m_nNspStatus[ctx.instrument_idx], ctx); + cur.m_nNumNTrodesPerInstrument = leg.m_nNumNTrodesPerInstrument[ctx.instrument_idx]; + cur.m_nGeminiSystem = leg.m_nGeminiSystem; + // ignore APP_WORKSPACE + return cur; +} + +NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg, const TranslationContext& ctx) { + NativeReceiveBuffer cur{}; + cur.received = leg.received; + cur.lasttime = leg.lasttime; + cur.headwrap = leg.headwrap; + cur.headindex = leg.headindex; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg, const TranslationContext& ctx) { + NativeTransmitBuffer cur{}; + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg, const TranslationContext& ctx) { + NativeTransmitBufferLocal cur{}; + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur, const TranslationContext& ctx) { cbPKT_HEADER leg{}; leg.time = cur.time; leg.chid = cur.chid; @@ -425,9 +536,9 @@ cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) { return leg; } -cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) { +cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur, const TranslationContext& ctx) { cbPKT_SYSINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.sysfreq = cur.sysfreq; leg.spikelen = cur.spikelen; leg.spikepre = cur.spikepre; @@ -437,9 +548,9 @@ cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) { return leg; } -cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) { +cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur, const TranslationContext& ctx) { cbPKT_PROCINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.proc = cur.proc; leg.idcode = cur.idcode; leg.idcode = cur.idcode; @@ -457,9 +568,9 @@ cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) { return leg; } -cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) { +cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur, const TranslationContext& ctx) { cbPKT_BANKINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.proc = cur.proc; leg.bank = cur.bank; leg.idcode = cur.idcode; @@ -470,9 +581,9 @@ cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) { return leg; } -cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) { +cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur, const TranslationContext& ctx) { cbPKT_GROUPINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.proc = cur.proc; leg.group = cur.group; copyArr(leg.label, cur.label); @@ -482,9 +593,9 @@ cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) { return leg; } -cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) { +cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur, const TranslationContext& ctx) { cbPKT_FILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.proc = cur.proc; leg.filt = cur.filt; copyArr(leg.label, cur.label); @@ -506,9 +617,9 @@ cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) { return leg; } -cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) { +cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur, const TranslationContext& ctx) { cbPKT_ADAPTFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.nMode = cur.nMode; leg.dLearningRate = cur.dLearningRate; @@ -517,16 +628,16 @@ cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) { return leg; } -cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur) { +cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur, const TranslationContext& ctx) { cbPKT_REFELECFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.nMode = cur.nMode; leg.nRefChan = cur.nRefChan; return leg; } -cbSCALING toLegacy(const ::cbSCALING& cur) { +cbSCALING toLegacy(const ::cbSCALING& cur, const TranslationContext& ctx) { cbSCALING leg{}; leg.digmin = cur.digmin; leg.digmax = cur.digmax; @@ -537,7 +648,7 @@ cbSCALING toLegacy(const ::cbSCALING& cur) { return leg; } -cbFILTDESC toLegacy(const ::cbFILTDESC& cur) { +cbFILTDESC toLegacy(const ::cbFILTDESC& cur, const TranslationContext& ctx) { cbFILTDESC leg{}; leg.hpfreq = cur.hpfreq; leg.hporder = cur.hporder; @@ -548,7 +659,7 @@ cbFILTDESC toLegacy(const ::cbFILTDESC& cur) { return leg; } -cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) { +cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur, const TranslationContext& ctx) { cbMANUALUNITMAPPING leg{}; leg.nOverride = cur.nOverride; copyArr(leg.afOrigin, cur.afOrigin); @@ -558,7 +669,7 @@ cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) { return leg; } -cbHOOP toLegacy(const ::cbHOOP& cur) { +cbHOOP toLegacy(const ::cbHOOP& cur, const TranslationContext& ctx) { cbHOOP leg{}; leg.valid = cur.valid; leg.time = cur.time; @@ -567,9 +678,9 @@ cbHOOP toLegacy(const ::cbHOOP& cur) { return leg; } -cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) { +cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur, const TranslationContext& ctx) { cbPKT_CHANINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.proc = cur.proc; leg.bank = cur.bank; @@ -580,15 +691,15 @@ cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) { leg.aoutcaps = cur.aoutcaps; leg.ainpcaps = cur.ainpcaps; leg.spkcaps = cur.spkcaps; - leg.physcalin = toLegacy(cur.physcalin); - leg.phyfiltin = toLegacy(cur.phyfiltin); - leg.physcalout = toLegacy(cur.physcalout); - leg.phyfiltout = toLegacy(cur.phyfiltout); + leg.physcalin = toLegacy(cur.physcalin, ctx); + leg.phyfiltin = toLegacy(cur.phyfiltin, ctx); + leg.physcalout = toLegacy(cur.physcalout, ctx); + leg.phyfiltout = toLegacy(cur.phyfiltout, ctx); copyArr(leg.label, cur.label); leg.userflags = cur.userflags; copyArr(leg.position, cur.position); - leg.scalin = toLegacy(cur.scalin); - leg.scalout = toLegacy(cur.scalout); + leg.scalin = toLegacy(cur.scalin, ctx); + leg.scalout = toLegacy(cur.scalout, ctx); leg.doutopts = cur.doutopts; leg.dinpopts = cur.dinpopts; leg.aoutopts = cur.aoutopts; @@ -614,14 +725,14 @@ cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) { leg.amplrejpos = cur.amplrejpos; leg.amplrejneg = cur.amplrejneg; leg.refelecchan = cur.refelecchan; - copyArr(leg.unitmapping, cur.unitmapping, toLegacy); - copyArr2D(leg.spkhoops, cur.spkhoops, toLegacy); + copyArr(leg.unitmapping, cur.unitmapping, toLegacy, ctx); + copyArr2D(leg.spkhoops, cur.spkhoops, toLegacy, ctx); return leg; } -cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) { +cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur, const TranslationContext& ctx) { cbPKT_FS_BASIS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.mode = cur.mode; leg.fs = cur.fs; @@ -629,9 +740,9 @@ cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) { return leg; } -cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) { +cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur, const TranslationContext& ctx) { cbPKT_SS_MODELSET leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.unit_number = cur.unit_number; leg.valid = cur.valid; @@ -649,34 +760,34 @@ cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) { return leg; } -cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur) { +cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur, const TranslationContext& ctx) { cbPKT_SS_DETECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.fThreshold = cur.fThreshold; leg.fMultiplier = cur.fMultiplier; return leg; } -cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) { +cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur, const TranslationContext& ctx) { cbPKT_SS_ARTIF_REJECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.nMaxSimulChans = cur.nMaxSimulChans; leg.nRefractoryCount = cur.nRefractoryCount; return leg; } -cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) { +cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur, const TranslationContext& ctx) { cbPKT_SS_NOISE_BOUNDARY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; copyArr(leg.afc, cur.afc); copyArr2D(leg.afS, cur.afS); return leg; } -cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) { +cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur, const TranslationContext& ctx) { cbPKT_SS_STATISTICS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.nUpdateSpikes = cur.nUpdateSpikes; leg.nAutoalg = cur.nAutoalg; leg.nMode = cur.nMode; @@ -692,7 +803,7 @@ cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) { return leg; } -cbAdaptControl toLegacy(const ::cbAdaptControl& cur) { +cbAdaptControl toLegacy(const ::cbAdaptControl& cur, const TranslationContext& ctx) { cbAdaptControl leg{}; leg.nMode = cur.nMode; leg.fTimeOutMinutes = cur.fTimeOutMinutes; @@ -700,39 +811,39 @@ cbAdaptControl toLegacy(const ::cbAdaptControl& cur) { return leg; } -cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur) { +cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur, const TranslationContext& ctx) { cbPKT_SS_STATUS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); - leg.cntlUnitStats = toLegacy(cur.cntlUnitStats); - leg.cntlNumUnits = toLegacy(cur.cntlNumUnits); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); + leg.cntlUnitStats = toLegacy(cur.cntlUnitStats, ctx); + leg.cntlNumUnits = toLegacy(cur.cntlNumUnits, ctx); return leg; } -cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur) { +cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur, const TranslationContext& ctx) { cbSPIKE_SORTING leg{}; - copyArr(leg.asBasis, cur.basis, toLegacy); - copyArr2D(leg.asSortModel, cur.models, toLegacy); - leg.pktDetect = toLegacy(cur.detect); - leg.pktArtifReject = toLegacy(cur.artifact_reject); - copyArr(leg.pktNoiseBoundary, cur.noise_boundary, toLegacy); - leg.pktStatistics = toLegacy(cur.statistics); - leg.pktStatus = toLegacy(cur.status); + copyArr(leg.asBasis, cur.basis, toLegacy, ctx); + copyArr2D(leg.asSortModel, cur.models, toLegacy, ctx); + leg.pktDetect = toLegacy(cur.detect, ctx); + leg.pktArtifReject = toLegacy(cur.artifact_reject, ctx); + copyArr(leg.pktNoiseBoundary, cur.noise_boundary, toLegacy, ctx); + leg.pktStatistics = toLegacy(cur.statistics, ctx); + leg.pktStatus = toLegacy(cur.status, ctx); return leg; } -cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur) { +cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur, const TranslationContext& ctx) { cbPKT_NTRODEINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.ntrode = cur.ntrode; copyArr(leg.label, cur.label); - copyArr2D(leg.ellipses, cur.ellipses, toLegacy); + copyArr2D(leg.ellipses, cur.ellipses, toLegacy, ctx); leg.nSite = cur.nSite; leg.fs = cur.fs; copyArr(leg.nChan, cur.nChan); return leg; } -cbWaveformData toLegacy(const ::cbWaveformData& cur) { +cbWaveformData toLegacy(const ::cbWaveformData& cur, const TranslationContext& ctx) { cbWaveformData leg{}; leg.offset = cur.offset; // aka sineFrequency leg.seq = cur.seq; // aka sineAmplitude @@ -743,9 +854,9 @@ cbWaveformData toLegacy(const ::cbWaveformData& cur) { return leg; } -cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) { +cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur, const TranslationContext& ctx) { cbPKT_AOUT_WAVEFORM leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.mode = cur.mode; leg.repeats = cur.repeats; @@ -754,22 +865,22 @@ cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) { leg.trigValue = cur.trigValue; leg.trigNum = cur.trigNum; leg.active = cur.active; - leg.wave = toLegacy(cur.wave); + leg.wave = toLegacy(cur.wave, ctx); return leg; } -cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur) { +cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur, const TranslationContext& ctx) { cbPKT_LNC leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.lncFreq = cur.lncFreq; leg.lncRefChan = cur.lncRefChan; leg.lncGlobalMode = cur.lncGlobalMode; return leg; } -cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) { +cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur, const TranslationContext& ctx) { cbPKT_NPLAY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.ftime = cur.ftime; // aka opt leg.stime = cur.stime; leg.etime = cur.etime; @@ -781,14 +892,14 @@ cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) { return leg; } -cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) { +cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur, const TranslationContext& ctx) { cbVIDEOSOURCE leg{}; copyArr(leg.name, cur.name); leg.fps = cur.fps; return leg; } -cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) { +cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur, const TranslationContext& ctx) { cbTRACKOBJ leg{}; copyArr(leg.name, cur.name); leg.type = cur.type; @@ -796,9 +907,9 @@ cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) { return leg; } -cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) { +cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur, const TranslationContext& ctx) { cbPKT_FILECFG leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.options = cur.options; leg.duration = cur.duration; leg.recording = cur.recording; @@ -809,6 +920,84 @@ cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) { return leg; } +NSPStatus toLegacy(const NativeNSPStatus& cur, const TranslationContext& ctx) { + switch(cur) { + case NativeNSPStatus::NSP_INIT: + return NSPStatus::NSP_INIT; + case NativeNSPStatus::NSP_NOIPADDR: + return NSPStatus::NSP_NOIPADDR; + case NativeNSPStatus::NSP_NOREPLY: + return NSPStatus::NSP_NOREPLY; + case NativeNSPStatus::NSP_FOUND: + return NSPStatus::NSP_FOUND; + case NativeNSPStatus::NSP_INVALID: + default: + return NSPStatus::NSP_INVALID; + } +} + +cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur, const TranslationContext& ctx) { + cbPKT_UNIT_SELECTION leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); + leg.lastchan = cur.lastchan; + copyArr(leg.abyUnitSelections, cur.abyUnitSelections); + return leg; +} + +cbPcStatus toLegacy(const NativePCStatus& cur, const TranslationContext& ctx) { + cbPcStatus leg{}; + leg.isSelection[ctx.instrument_idx] = toLegacy(cur.isSelection, ctx); + leg.m_iBlockRecording = cur.m_iBlockRecording; + leg.m_nPCStatusFlags = cur.m_nPCStatusFlags; + leg.m_nNumFEChans = cur.m_nNumFEChans; + leg.m_nNumAnainChans = cur.m_nNumAnainChans; + leg.m_nNumAnalogChans = cur.m_nNumAnalogChans; + leg.m_nNumAoutChans = cur.m_nNumAoutChans; + leg.m_nNumAudioChans = cur.m_nNumAudioChans; + leg.m_nNumAnalogoutChans = cur.m_nNumAnalogoutChans; + leg.m_nNumDiginChans = cur.m_nNumDiginChans; + leg.m_nNumSerialChans = cur.m_nNumSerialChans; + leg.m_nNumDigoutChans = cur.m_nNumDigoutChans; + leg.m_nNumTotalChans = cur.m_nNumTotalChans; + leg.m_nNspStatus[ctx.instrument_idx] = toLegacy(cur.m_nNspStatus, ctx); + leg.m_nNumNTrodesPerInstrument[ctx.instrument_idx] = cur.m_nNumNTrodesPerInstrument; + leg.m_nGeminiSystem = cur.m_nGeminiSystem; + // ignore APP_WORKSPACE + return leg; +} + +cbRECBUFF toLegacy(const NativeReceiveBuffer& cur, const TranslationContext& ctx) { + cbRECBUFF leg{}; + leg.received = cur.received; + leg.lasttime = cur.lasttime; + leg.headwrap = cur.headwrap; + leg.headindex = cur.headindex; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur, const TranslationContext& ctx) { + cbXMTBUFF leg{}; + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur, const TranslationContext& ctx) { + cbXMTBUFFLOCAL leg{}; + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); + return leg; +} + } // namespace central_v4_0 } // namespace cbshm diff --git a/src/cbshm/src/central_translators/v4_1.cpp b/src/cbshm/src/central_translators/v4_1.cpp index f65b2077..fbd31ccf 100644 --- a/src/cbshm/src/central_translators/v4_1.cpp +++ b/src/cbshm/src/central_translators/v4_1.cpp @@ -15,7 +15,7 @@ namespace cbshm { namespace central_v4_1 { -::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) { +::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg, const TranslationContext& ctx) { ::cbPKT_HEADER cur{}; cur.time = leg.time; cur.chid = leg.chid; @@ -26,9 +26,9 @@ ::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) { return cur; } -::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) { +::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg, const TranslationContext& ctx) { ::cbPKT_SYSINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.sysfreq = leg.sysfreq; cur.spikelen = leg.spikelen; cur.spikepre = leg.spikepre; @@ -38,9 +38,9 @@ ::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) { return cur; } -::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) { +::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg, const TranslationContext& ctx) { ::cbPKT_PROCINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.proc = leg.proc; cur.idcode = leg.idcode; cur.idcode = leg.idcode; @@ -58,9 +58,9 @@ ::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) { return cur; } -::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) { +::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg, const TranslationContext& ctx) { ::cbPKT_BANKINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.proc = leg.proc; cur.bank = leg.bank; cur.idcode = leg.idcode; @@ -71,9 +71,9 @@ ::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) { return cur; } -::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) { +::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg, const TranslationContext& ctx) { ::cbPKT_GROUPINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.proc = leg.proc; cur.group = leg.group; copyArr(cur.label, leg.label); @@ -83,9 +83,9 @@ ::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) { return cur; } -::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) { +::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg, const TranslationContext& ctx) { ::cbPKT_FILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.proc = leg.proc; cur.filt = leg.filt; copyArr(cur.label, leg.label); @@ -107,9 +107,9 @@ ::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) { return cur; } -::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) { +::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg, const TranslationContext& ctx) { ::cbPKT_ADAPTFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.nMode = leg.nMode; cur.dLearningRate = leg.dLearningRate; @@ -118,16 +118,16 @@ ::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) { return cur; } -::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg) { +::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg, const TranslationContext& ctx) { ::cbPKT_REFELECFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.nMode = leg.nMode; cur.nRefChan = leg.nRefChan; return cur; } -::cbSCALING fromLegacy(const cbSCALING& leg) { +::cbSCALING fromLegacy(const cbSCALING& leg, const TranslationContext& ctx) { ::cbSCALING cur{}; cur.digmin = leg.digmin; cur.digmax = leg.digmax; @@ -138,7 +138,7 @@ ::cbSCALING fromLegacy(const cbSCALING& leg) { return cur; } -::cbFILTDESC fromLegacy(const cbFILTDESC& leg) { +::cbFILTDESC fromLegacy(const cbFILTDESC& leg, const TranslationContext& ctx) { ::cbFILTDESC cur{}; cur.hpfreq = leg.hpfreq; cur.hporder = leg.hporder; @@ -149,7 +149,7 @@ ::cbFILTDESC fromLegacy(const cbFILTDESC& leg) { return cur; } -::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) { +::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg, const TranslationContext& ctx) { ::cbMANUALUNITMAPPING cur{}; cur.nOverride = leg.nOverride; copyArr(cur.afOrigin, leg.afOrigin); @@ -159,7 +159,7 @@ ::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) { return cur; } -::cbHOOP fromLegacy(const cbHOOP& leg) { +::cbHOOP fromLegacy(const cbHOOP& leg, const TranslationContext& ctx) { ::cbHOOP cur{}; cur.valid = leg.valid; cur.time = leg.time; @@ -168,9 +168,9 @@ ::cbHOOP fromLegacy(const cbHOOP& leg) { return cur; } -::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) { +::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg, const TranslationContext& ctx) { ::cbPKT_CHANINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.proc = leg.proc; cur.bank = leg.bank; @@ -181,15 +181,15 @@ ::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) { cur.aoutcaps = leg.aoutcaps; cur.ainpcaps = leg.ainpcaps; cur.spkcaps = leg.spkcaps; - cur.physcalin = fromLegacy(leg.physcalin); - cur.phyfiltin = fromLegacy(leg.phyfiltin); - cur.physcalout = fromLegacy(leg.physcalout); - cur.phyfiltout = fromLegacy(leg.phyfiltout); + cur.physcalin = fromLegacy(leg.physcalin, ctx); + cur.phyfiltin = fromLegacy(leg.phyfiltin, ctx); + cur.physcalout = fromLegacy(leg.physcalout, ctx); + cur.phyfiltout = fromLegacy(leg.phyfiltout, ctx); copyArr(cur.label, leg.label); cur.userflags = leg.userflags; copyArr(cur.position, leg.position); - cur.scalin = fromLegacy(leg.scalin); - cur.scalout = fromLegacy(leg.scalout); + cur.scalin = fromLegacy(leg.scalin, ctx); + cur.scalout = fromLegacy(leg.scalout, ctx); cur.doutopts = leg.doutopts; cur.dinpopts = leg.dinpopts; cur.aoutopts = leg.aoutopts; @@ -218,14 +218,14 @@ ::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) { cur.amplrejpos = leg.amplrejpos; cur.amplrejneg = leg.amplrejneg; cur.refelecchan = leg.refelecchan; - copyArr(cur.unitmapping, leg.unitmapping, fromLegacy); - copyArr2D(cur.spkhoops, leg.spkhoops, fromLegacy); + copyArr(cur.unitmapping, leg.unitmapping, fromLegacy, ctx); + copyArr2D(cur.spkhoops, leg.spkhoops, fromLegacy, ctx); return cur; } -::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) { +::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg, const TranslationContext& ctx) { ::cbPKT_FS_BASIS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.mode = leg.mode; cur.fs = leg.fs; @@ -233,9 +233,9 @@ ::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) { return cur; } -::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) { +::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg, const TranslationContext& ctx) { ::cbPKT_SS_MODELSET cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.unit_number = leg.unit_number; cur.valid = leg.valid; @@ -253,34 +253,34 @@ ::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) { return cur; } -::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg) { +::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg, const TranslationContext& ctx) { ::cbPKT_SS_DETECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.fThreshold = leg.fThreshold; cur.fMultiplier = leg.fMultiplier; return cur; } -::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) { +::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg, const TranslationContext& ctx) { ::cbPKT_SS_ARTIF_REJECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.nMaxSimulChans = leg.nMaxSimulChans; cur.nRefractoryCount = leg.nRefractoryCount; return cur; } -::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) { +::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg, const TranslationContext& ctx) { ::cbPKT_SS_NOISE_BOUNDARY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; copyArr(cur.afc, leg.afc); copyArr2D(cur.afS, leg.afS); return cur; } -::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) { +::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg, const TranslationContext& ctx) { ::cbPKT_SS_STATISTICS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.nUpdateSpikes = leg.nUpdateSpikes; cur.nAutoalg = leg.nAutoalg; cur.nMode = leg.nMode; @@ -296,7 +296,7 @@ ::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) { return cur; } -::cbAdaptControl fromLegacy(const cbAdaptControl& leg) { +::cbAdaptControl fromLegacy(const cbAdaptControl& leg, const TranslationContext& ctx) { ::cbAdaptControl cur{}; cur.nMode = leg.nMode; cur.fTimeOutMinutes = leg.fTimeOutMinutes; @@ -304,39 +304,39 @@ ::cbAdaptControl fromLegacy(const cbAdaptControl& leg) { return cur; } -::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg) { +::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg, const TranslationContext& ctx) { ::cbPKT_SS_STATUS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); - cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats); - cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); + cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats, ctx); + cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits, ctx); return cur; } -::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg) { +::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg, const TranslationContext& ctx) { ::cbproto::SpikeSorting cur{}; - copyArr(cur.basis, leg.asBasis, fromLegacy); - copyArr2D(cur.models, leg.asSortModel, fromLegacy); - cur.detect = fromLegacy(leg.pktDetect); - cur.artifact_reject = fromLegacy(leg.pktArtifReject); - copyArr(cur.noise_boundary, leg.pktNoiseBoundary, fromLegacy); - cur.statistics = fromLegacy(leg.pktStatistics); - cur.status = fromLegacy(leg.pktStatus); + copyArr(cur.basis, leg.asBasis, fromLegacy, ctx); + copyArr2D(cur.models, leg.asSortModel, fromLegacy, ctx); + cur.detect = fromLegacy(leg.pktDetect, ctx); + cur.artifact_reject = fromLegacy(leg.pktArtifReject, ctx); + copyArr(cur.noise_boundary, leg.pktNoiseBoundary, fromLegacy, ctx); + cur.statistics = fromLegacy(leg.pktStatistics, ctx); + cur.status = fromLegacy(leg.pktStatus, ctx); return cur; } -::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg) { +::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg, const TranslationContext& ctx) { ::cbPKT_NTRODEINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.ntrode = leg.ntrode; copyArr(cur.label, leg.label); - copyArr2D(cur.ellipses, leg.ellipses, fromLegacy); + copyArr2D(cur.ellipses, leg.ellipses, fromLegacy, ctx); cur.nSite = leg.nSite; cur.fs = leg.fs; copyArr(cur.nChan, leg.nChan); return cur; } -::cbWaveformData fromLegacy(const cbWaveformData& leg) { +::cbWaveformData fromLegacy(const cbWaveformData& leg, const TranslationContext& ctx) { ::cbWaveformData cur{}; cur.offset = leg.offset; // aka sineFrequency cur.seq = leg.seq; // aka sineAmplitude @@ -347,9 +347,9 @@ ::cbWaveformData fromLegacy(const cbWaveformData& leg) { return cur; } -::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) { +::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg, const TranslationContext& ctx) { ::cbPKT_AOUT_WAVEFORM cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.mode = leg.mode; cur.repeats = leg.repeats; @@ -359,22 +359,22 @@ ::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) { cur.trigValue = leg.trigValue; cur.trigNum = leg.trigNum; cur.active = leg.active; - cur.wave = fromLegacy(leg.wave); + cur.wave = fromLegacy(leg.wave, ctx); return cur; } -::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg) { +::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg, const TranslationContext& ctx) { ::cbPKT_LNC cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.lncFreq = leg.lncFreq; cur.lncRefChan = leg.lncRefChan; cur.lncGlobalMode = leg.lncGlobalMode; return cur; } -::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) { +::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg, const TranslationContext& ctx) { ::cbPKT_NPLAY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.ftime = leg.ftime; // aka opt cur.stime = leg.stime; cur.etime = leg.etime; @@ -386,14 +386,14 @@ ::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) { return cur; } -::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg) { +::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg, const TranslationContext& ctx) { ::cbVIDEOSOURCE cur{}; copyArr(cur.name, leg.name); cur.fps = leg.fps; return cur; } -::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) { +::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg, const TranslationContext& ctx) { ::cbTRACKOBJ cur{}; copyArr(cur.name, leg.name); cur.type = leg.type; @@ -401,9 +401,9 @@ ::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) { return cur; } -::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) { +::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg, const TranslationContext& ctx) { ::cbPKT_FILECFG cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.options = leg.options; cur.duration = leg.duration; cur.recording = leg.recording; @@ -414,7 +414,118 @@ ::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) { return cur; } -cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) { +NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg, const TranslationContext& ctx) { + // TODO: VERIFY that each list that's assumed to be instrument-independent is in fact independent from any particular instrument. + NativeConfigBuffer cur{}; + cur.version = leg.version; + cur.sysflags = leg.sysflags; + cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); + cur.sysinfo = fromLegacy(leg.sysinfo, ctx); + cur.procinfo = fromLegacy(leg.procinfo[ctx.instrument_idx], ctx); + copyArr(cur.bankinfo, leg.bankinfo[ctx.instrument_idx], fromLegacy, ctx); + copyArr(cur.groupinfo, leg.groupinfo[ctx.instrument_idx], fromLegacy, ctx); + copyArr(cur.filtinfo, leg.filtinfo[ctx.instrument_idx], fromLegacy, ctx); + cur.adaptinfo = fromLegacy(leg.adaptinfo[ctx.instrument_idx], ctx); + cur.refelecinfo = fromLegacy(leg.refelecinfo[ctx.instrument_idx], ctx); + copyArr(cur.chaninfo, leg.chaninfo, fromLegacy, ctx); + copyArr(cur.asBasis, leg.isSortingOptions.asBasis, fromLegacy, ctx); + copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, fromLegacy, ctx); + // TODO: Move native isSortingOptions fields into a struct + cur.pktDetect = fromLegacy(leg.isSortingOptions.pktDetect, ctx); + cur.pktArtifReject = fromLegacy(leg.isSortingOptions.pktArtifReject, ctx); + copyArr(cur.pktNoiseBoundary, leg.isSortingOptions.pktNoiseBoundary, fromLegacy, ctx); + cur.pktStatistics = fromLegacy(leg.isSortingOptions.pktStatistics, ctx); + cur.pktStatus = fromLegacy(leg.isSortingOptions.pktStatus, ctx); + copyArr(cur.isNTrodeInfo, leg.isNTrodeInfo, fromLegacy, ctx); + copyArr2D(cur.isWaveform, leg.isWaveform, fromLegacy, ctx); + cur.isLnc = fromLegacy(leg.isLnc[ctx.instrument_idx], ctx); + cur.isNPlay = fromLegacy(leg.isNPlay, ctx); + copyArr(cur.isVideoSource, leg.isVideoSource, fromLegacy, ctx); + copyArr(cur.isTrackObj, leg.isTrackObj, fromLegacy, ctx); + cur.fileinfo = fromLegacy(leg.fileinfo, ctx); + + return cur; +} + +NativeNSPStatus fromLegacy(const NSPStatus& leg, const TranslationContext& ctx) { + switch(leg) { + case NSPStatus::NSP_INIT: + return NativeNSPStatus::NSP_INIT; + case NSPStatus::NSP_NOIPADDR: + return NativeNSPStatus::NSP_NOIPADDR; + case NSPStatus::NSP_NOREPLY: + return NativeNSPStatus::NSP_NOREPLY; + case NSPStatus::NSP_FOUND: + return NativeNSPStatus::NSP_FOUND; + case NSPStatus::NSP_INVALID: + default: + return NativeNSPStatus::NSP_INVALID; + } +} + +::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg, const TranslationContext& ctx) { + ::cbPKT_UNIT_SELECTION cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); + cur.lastchan = leg.lastchan; + copyArr(cur.abyUnitSelections, leg.abyUnitSelections); + return cur; +} + +NativePCStatus fromLegacy(const cbPcStatus& leg, const TranslationContext& ctx) { + NativePCStatus cur{}; + cur.isSelection = fromLegacy(leg.isSelection[ctx.instrument_idx], ctx); + cur.m_iBlockRecording = leg.m_iBlockRecording; + cur.m_nPCStatusFlags = leg.m_nPCStatusFlags; + cur.m_nNumFEChans = leg.m_nNumFEChans; + cur.m_nNumAnainChans = leg.m_nNumAnainChans; + cur.m_nNumAnalogChans = leg.m_nNumAnalogChans; + cur.m_nNumAoutChans = leg.m_nNumAoutChans; + cur.m_nNumAudioChans = leg.m_nNumAudioChans; + cur.m_nNumAnalogoutChans = leg.m_nNumAnalogoutChans; + cur.m_nNumDiginChans = leg.m_nNumDiginChans; + cur.m_nNumSerialChans = leg.m_nNumSerialChans; + cur.m_nNumDigoutChans = leg.m_nNumDigoutChans; + cur.m_nNumTotalChans = leg.m_nNumTotalChans; + cur.m_nNspStatus = fromLegacy(leg.m_nNspStatus[ctx.instrument_idx], ctx); + cur.m_nNumNTrodesPerInstrument = leg.m_nNumNTrodesPerInstrument[ctx.instrument_idx]; + cur.m_nGeminiSystem = leg.m_nGeminiSystem; + // ignore APP_WORKSPACE + return cur; +} + +NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg, const TranslationContext& ctx) { + NativeReceiveBuffer cur{}; + cur.received = leg.received; + cur.lasttime = leg.lasttime; + cur.headwrap = leg.headwrap; + cur.headindex = leg.headindex; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg, const TranslationContext& ctx) { + NativeTransmitBuffer cur{}; + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg, const TranslationContext& ctx) { + NativeTransmitBufferLocal cur{}; + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur, const TranslationContext& ctx) { cbPKT_HEADER leg{}; leg.time = cur.time; leg.chid = cur.chid; @@ -425,9 +536,9 @@ cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) { return leg; } -cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) { +cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur, const TranslationContext& ctx) { cbPKT_SYSINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.sysfreq = cur.sysfreq; leg.spikelen = cur.spikelen; leg.spikepre = cur.spikepre; @@ -437,9 +548,9 @@ cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) { return leg; } -cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) { +cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur, const TranslationContext& ctx) { cbPKT_PROCINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.proc = cur.proc; leg.idcode = cur.idcode; leg.idcode = cur.idcode; @@ -457,9 +568,9 @@ cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) { return leg; } -cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) { +cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur, const TranslationContext& ctx) { cbPKT_BANKINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.proc = cur.proc; leg.bank = cur.bank; leg.idcode = cur.idcode; @@ -470,9 +581,9 @@ cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) { return leg; } -cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) { +cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur, const TranslationContext& ctx) { cbPKT_GROUPINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.proc = cur.proc; leg.group = cur.group; copyArr(leg.label, cur.label); @@ -482,9 +593,9 @@ cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) { return leg; } -cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) { +cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur, const TranslationContext& ctx) { cbPKT_FILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.proc = cur.proc; leg.filt = cur.filt; copyArr(leg.label, cur.label); @@ -506,9 +617,9 @@ cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) { return leg; } -cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) { +cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur, const TranslationContext& ctx) { cbPKT_ADAPTFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.nMode = cur.nMode; leg.dLearningRate = cur.dLearningRate; @@ -517,16 +628,16 @@ cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) { return leg; } -cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur) { +cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur, const TranslationContext& ctx) { cbPKT_REFELECFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.nMode = cur.nMode; leg.nRefChan = cur.nRefChan; return leg; } -cbSCALING toLegacy(const ::cbSCALING& cur) { +cbSCALING toLegacy(const ::cbSCALING& cur, const TranslationContext& ctx) { cbSCALING leg{}; leg.digmin = cur.digmin; leg.digmax = cur.digmax; @@ -537,7 +648,7 @@ cbSCALING toLegacy(const ::cbSCALING& cur) { return leg; } -cbFILTDESC toLegacy(const ::cbFILTDESC& cur) { +cbFILTDESC toLegacy(const ::cbFILTDESC& cur, const TranslationContext& ctx) { cbFILTDESC leg{}; leg.hpfreq = cur.hpfreq; leg.hporder = cur.hporder; @@ -548,7 +659,7 @@ cbFILTDESC toLegacy(const ::cbFILTDESC& cur) { return leg; } -cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) { +cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur, const TranslationContext& ctx) { cbMANUALUNITMAPPING leg{}; leg.nOverride = cur.nOverride; copyArr(leg.afOrigin, cur.afOrigin); @@ -558,7 +669,7 @@ cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) { return leg; } -cbHOOP toLegacy(const ::cbHOOP& cur) { +cbHOOP toLegacy(const ::cbHOOP& cur, const TranslationContext& ctx) { cbHOOP leg{}; leg.valid = cur.valid; leg.time = cur.time; @@ -567,9 +678,9 @@ cbHOOP toLegacy(const ::cbHOOP& cur) { return leg; } -cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) { +cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur, const TranslationContext& ctx) { cbPKT_CHANINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.proc = cur.proc; leg.bank = cur.bank; @@ -580,15 +691,15 @@ cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) { leg.aoutcaps = cur.aoutcaps; leg.ainpcaps = cur.ainpcaps; leg.spkcaps = cur.spkcaps; - leg.physcalin = toLegacy(cur.physcalin); - leg.phyfiltin = toLegacy(cur.phyfiltin); - leg.physcalout = toLegacy(cur.physcalout); - leg.phyfiltout = toLegacy(cur.phyfiltout); + leg.physcalin = toLegacy(cur.physcalin, ctx); + leg.phyfiltin = toLegacy(cur.phyfiltin, ctx); + leg.physcalout = toLegacy(cur.physcalout, ctx); + leg.phyfiltout = toLegacy(cur.phyfiltout, ctx); copyArr(leg.label, cur.label); leg.userflags = cur.userflags; copyArr(leg.position, cur.position); - leg.scalin = toLegacy(cur.scalin); - leg.scalout = toLegacy(cur.scalout); + leg.scalin = toLegacy(cur.scalin, ctx); + leg.scalout = toLegacy(cur.scalout, ctx); leg.doutopts = cur.doutopts; leg.dinpopts = cur.dinpopts; leg.aoutopts = cur.aoutopts; @@ -617,14 +728,14 @@ cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) { leg.amplrejpos = cur.amplrejpos; leg.amplrejneg = cur.amplrejneg; leg.refelecchan = cur.refelecchan; - copyArr(leg.unitmapping, cur.unitmapping, toLegacy); - copyArr2D(leg.spkhoops, cur.spkhoops, toLegacy); + copyArr(leg.unitmapping, cur.unitmapping, toLegacy, ctx); + copyArr2D(leg.spkhoops, cur.spkhoops, toLegacy, ctx); return leg; } -cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) { +cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur, const TranslationContext& ctx) { cbPKT_FS_BASIS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.mode = cur.mode; leg.fs = cur.fs; @@ -632,9 +743,9 @@ cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) { return leg; } -cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) { +cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur, const TranslationContext& ctx) { cbPKT_SS_MODELSET leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.unit_number = cur.unit_number; leg.valid = cur.valid; @@ -652,34 +763,34 @@ cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) { return leg; } -cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur) { +cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur, const TranslationContext& ctx) { cbPKT_SS_DETECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.fThreshold = cur.fThreshold; leg.fMultiplier = cur.fMultiplier; return leg; } -cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) { +cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur, const TranslationContext& ctx) { cbPKT_SS_ARTIF_REJECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.nMaxSimulChans = cur.nMaxSimulChans; leg.nRefractoryCount = cur.nRefractoryCount; return leg; } -cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) { +cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur, const TranslationContext& ctx) { cbPKT_SS_NOISE_BOUNDARY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; copyArr(leg.afc, cur.afc); copyArr2D(leg.afS, cur.afS); return leg; } -cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) { +cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur, const TranslationContext& ctx) { cbPKT_SS_STATISTICS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.nUpdateSpikes = cur.nUpdateSpikes; leg.nAutoalg = cur.nAutoalg; leg.nMode = cur.nMode; @@ -695,7 +806,7 @@ cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) { return leg; } -cbAdaptControl toLegacy(const ::cbAdaptControl& cur) { +cbAdaptControl toLegacy(const ::cbAdaptControl& cur, const TranslationContext& ctx) { cbAdaptControl leg{}; leg.nMode = cur.nMode; leg.fTimeOutMinutes = cur.fTimeOutMinutes; @@ -703,39 +814,39 @@ cbAdaptControl toLegacy(const ::cbAdaptControl& cur) { return leg; } -cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur) { +cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur, const TranslationContext& ctx) { cbPKT_SS_STATUS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); - leg.cntlUnitStats = toLegacy(cur.cntlUnitStats); - leg.cntlNumUnits = toLegacy(cur.cntlNumUnits); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); + leg.cntlUnitStats = toLegacy(cur.cntlUnitStats, ctx); + leg.cntlNumUnits = toLegacy(cur.cntlNumUnits, ctx); return leg; } -cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur) { +cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur, const TranslationContext& ctx) { cbSPIKE_SORTING leg{}; - copyArr(leg.asBasis, cur.basis, toLegacy); - copyArr2D(leg.asSortModel, cur.models, toLegacy); - leg.pktDetect = toLegacy(cur.detect); - leg.pktArtifReject = toLegacy(cur.artifact_reject); - copyArr(leg.pktNoiseBoundary, cur.noise_boundary, toLegacy); - leg.pktStatistics = toLegacy(cur.statistics); - leg.pktStatus = toLegacy(cur.status); + copyArr(leg.asBasis, cur.basis, toLegacy, ctx); + copyArr2D(leg.asSortModel, cur.models, toLegacy, ctx); + leg.pktDetect = toLegacy(cur.detect, ctx); + leg.pktArtifReject = toLegacy(cur.artifact_reject, ctx); + copyArr(leg.pktNoiseBoundary, cur.noise_boundary, toLegacy, ctx); + leg.pktStatistics = toLegacy(cur.statistics, ctx); + leg.pktStatus = toLegacy(cur.status, ctx); return leg; } -cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur) { +cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur, const TranslationContext& ctx) { cbPKT_NTRODEINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.ntrode = cur.ntrode; copyArr(leg.label, cur.label); - copyArr2D(leg.ellipses, cur.ellipses, toLegacy); + copyArr2D(leg.ellipses, cur.ellipses, toLegacy, ctx); leg.nSite = cur.nSite; leg.fs = cur.fs; copyArr(leg.nChan, cur.nChan); return leg; } -cbWaveformData toLegacy(const ::cbWaveformData& cur) { +cbWaveformData toLegacy(const ::cbWaveformData& cur, const TranslationContext& ctx) { cbWaveformData leg{}; leg.offset = cur.offset; // aka sineFrequency leg.seq = cur.seq; // aka sineAmplitude @@ -746,9 +857,9 @@ cbWaveformData toLegacy(const ::cbWaveformData& cur) { return leg; } -cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) { +cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur, const TranslationContext& ctx) { cbPKT_AOUT_WAVEFORM leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.mode = cur.mode; leg.repeats = cur.repeats; @@ -758,22 +869,22 @@ cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) { leg.trigValue = cur.trigValue; leg.trigNum = cur.trigNum; leg.active = cur.active; - leg.wave = toLegacy(cur.wave); + leg.wave = toLegacy(cur.wave, ctx); return leg; } -cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur) { +cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur, const TranslationContext& ctx) { cbPKT_LNC leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.lncFreq = cur.lncFreq; leg.lncRefChan = cur.lncRefChan; leg.lncGlobalMode = cur.lncGlobalMode; return leg; } -cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) { +cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur, const TranslationContext& ctx) { cbPKT_NPLAY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.ftime = cur.ftime; // aka opt leg.stime = cur.stime; leg.etime = cur.etime; @@ -785,14 +896,14 @@ cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) { return leg; } -cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) { +cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur, const TranslationContext& ctx) { cbVIDEOSOURCE leg{}; copyArr(leg.name, cur.name); leg.fps = cur.fps; return leg; } -cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) { +cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur, const TranslationContext& ctx) { cbTRACKOBJ leg{}; copyArr(leg.name, cur.name); leg.type = cur.type; @@ -800,9 +911,9 @@ cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) { return leg; } -cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) { +cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur, const TranslationContext& ctx) { cbPKT_FILECFG leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.options = cur.options; leg.duration = cur.duration; leg.recording = cur.recording; @@ -813,6 +924,84 @@ cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) { return leg; } +NSPStatus toLegacy(const NativeNSPStatus& cur, const TranslationContext& ctx) { + switch(cur) { + case NativeNSPStatus::NSP_INIT: + return NSPStatus::NSP_INIT; + case NativeNSPStatus::NSP_NOIPADDR: + return NSPStatus::NSP_NOIPADDR; + case NativeNSPStatus::NSP_NOREPLY: + return NSPStatus::NSP_NOREPLY; + case NativeNSPStatus::NSP_FOUND: + return NSPStatus::NSP_FOUND; + case NativeNSPStatus::NSP_INVALID: + default: + return NSPStatus::NSP_INVALID; + } +} + +cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur, const TranslationContext& ctx) { + cbPKT_UNIT_SELECTION leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); + leg.lastchan = cur.lastchan; + copyArr(leg.abyUnitSelections, cur.abyUnitSelections); + return leg; +} + +cbPcStatus toLegacy(const NativePCStatus& cur, const TranslationContext& ctx) { + cbPcStatus leg{}; + leg.isSelection[ctx.instrument_idx] = toLegacy(cur.isSelection, ctx); + leg.m_iBlockRecording = cur.m_iBlockRecording; + leg.m_nPCStatusFlags = cur.m_nPCStatusFlags; + leg.m_nNumFEChans = cur.m_nNumFEChans; + leg.m_nNumAnainChans = cur.m_nNumAnainChans; + leg.m_nNumAnalogChans = cur.m_nNumAnalogChans; + leg.m_nNumAoutChans = cur.m_nNumAoutChans; + leg.m_nNumAudioChans = cur.m_nNumAudioChans; + leg.m_nNumAnalogoutChans = cur.m_nNumAnalogoutChans; + leg.m_nNumDiginChans = cur.m_nNumDiginChans; + leg.m_nNumSerialChans = cur.m_nNumSerialChans; + leg.m_nNumDigoutChans = cur.m_nNumDigoutChans; + leg.m_nNumTotalChans = cur.m_nNumTotalChans; + leg.m_nNspStatus[ctx.instrument_idx] = toLegacy(cur.m_nNspStatus, ctx); + leg.m_nNumNTrodesPerInstrument[ctx.instrument_idx] = cur.m_nNumNTrodesPerInstrument; + leg.m_nGeminiSystem = cur.m_nGeminiSystem; + // ignore APP_WORKSPACE + return leg; +} + +cbRECBUFF toLegacy(const NativeReceiveBuffer& cur, const TranslationContext& ctx) { + cbRECBUFF leg{}; + leg.received = cur.received; + leg.lasttime = cur.lasttime; + leg.headwrap = cur.headwrap; + leg.headindex = cur.headindex; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur, const TranslationContext& ctx) { + cbXMTBUFF leg{}; + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur, const TranslationContext& ctx) { + cbXMTBUFFLOCAL leg{}; + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); + return leg; +} + } // namespace central_v4_1 } // namespace cbshm diff --git a/src/cbshm/src/central_translators/v4_2.cpp b/src/cbshm/src/central_translators/v4_2.cpp index c2a18890..c6d2b911 100644 --- a/src/cbshm/src/central_translators/v4_2.cpp +++ b/src/cbshm/src/central_translators/v4_2.cpp @@ -15,7 +15,7 @@ namespace cbshm { namespace central_v4_2 { -::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) { +::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg, const TranslationContext& ctx) { ::cbPKT_HEADER cur{}; cur.time = leg.time; cur.chid = leg.chid; @@ -26,9 +26,9 @@ ::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) { return cur; } -::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) { +::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg, const TranslationContext& ctx) { ::cbPKT_SYSINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.sysfreq = leg.sysfreq; cur.spikelen = leg.spikelen; cur.spikepre = leg.spikepre; @@ -38,9 +38,9 @@ ::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) { return cur; } -::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) { +::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg, const TranslationContext& ctx) { ::cbPKT_PROCINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.proc = leg.proc; cur.idcode = leg.idcode; cur.idcode = leg.idcode; @@ -58,9 +58,9 @@ ::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) { return cur; } -::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) { +::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg, const TranslationContext& ctx) { ::cbPKT_BANKINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.proc = leg.proc; cur.bank = leg.bank; cur.idcode = leg.idcode; @@ -71,9 +71,9 @@ ::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) { return cur; } -::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) { +::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg, const TranslationContext& ctx) { ::cbPKT_GROUPINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.proc = leg.proc; cur.group = leg.group; copyArr(cur.label, leg.label); @@ -83,9 +83,9 @@ ::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) { return cur; } -::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) { +::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg, const TranslationContext& ctx) { ::cbPKT_FILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.proc = leg.proc; cur.filt = leg.filt; copyArr(cur.label, leg.label); @@ -107,9 +107,9 @@ ::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) { return cur; } -::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) { +::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg, const TranslationContext& ctx) { ::cbPKT_ADAPTFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.nMode = leg.nMode; cur.dLearningRate = leg.dLearningRate; @@ -118,16 +118,16 @@ ::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) { return cur; } -::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg) { +::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg, const TranslationContext& ctx) { ::cbPKT_REFELECFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.nMode = leg.nMode; cur.nRefChan = leg.nRefChan; return cur; } -::cbSCALING fromLegacy(const cbSCALING& leg) { +::cbSCALING fromLegacy(const cbSCALING& leg, const TranslationContext& ctx) { ::cbSCALING cur{}; cur.digmin = leg.digmin; cur.digmax = leg.digmax; @@ -138,7 +138,7 @@ ::cbSCALING fromLegacy(const cbSCALING& leg) { return cur; } -::cbFILTDESC fromLegacy(const cbFILTDESC& leg) { +::cbFILTDESC fromLegacy(const cbFILTDESC& leg, const TranslationContext& ctx) { ::cbFILTDESC cur{}; cur.hpfreq = leg.hpfreq; cur.hporder = leg.hporder; @@ -149,7 +149,7 @@ ::cbFILTDESC fromLegacy(const cbFILTDESC& leg) { return cur; } -::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) { +::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg, const TranslationContext& ctx) { ::cbMANUALUNITMAPPING cur{}; cur.nOverride = leg.nOverride; copyArr(cur.afOrigin, leg.afOrigin); @@ -159,7 +159,7 @@ ::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) { return cur; } -::cbHOOP fromLegacy(const cbHOOP& leg) { +::cbHOOP fromLegacy(const cbHOOP& leg, const TranslationContext& ctx) { ::cbHOOP cur{}; cur.valid = leg.valid; cur.time = leg.time; @@ -168,9 +168,9 @@ ::cbHOOP fromLegacy(const cbHOOP& leg) { return cur; } -::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) { +::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg, const TranslationContext& ctx) { ::cbPKT_CHANINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.proc = leg.proc; cur.bank = leg.bank; @@ -181,15 +181,15 @@ ::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) { cur.aoutcaps = leg.aoutcaps; cur.ainpcaps = leg.ainpcaps; cur.spkcaps = leg.spkcaps; - cur.physcalin = fromLegacy(leg.physcalin); - cur.phyfiltin = fromLegacy(leg.phyfiltin); - cur.physcalout = fromLegacy(leg.physcalout); - cur.phyfiltout = fromLegacy(leg.phyfiltout); + cur.physcalin = fromLegacy(leg.physcalin, ctx); + cur.phyfiltin = fromLegacy(leg.phyfiltin, ctx); + cur.physcalout = fromLegacy(leg.physcalout, ctx); + cur.phyfiltout = fromLegacy(leg.phyfiltout, ctx); copyArr(cur.label, leg.label); cur.userflags = leg.userflags; copyArr(cur.position, leg.position); - cur.scalin = fromLegacy(leg.scalin); - cur.scalout = fromLegacy(leg.scalout); + cur.scalin = fromLegacy(leg.scalin, ctx); + cur.scalout = fromLegacy(leg.scalout, ctx); cur.doutopts = leg.doutopts; cur.dinpopts = leg.dinpopts; cur.aoutopts = leg.aoutopts; @@ -218,14 +218,14 @@ ::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) { cur.amplrejpos = leg.amplrejpos; cur.amplrejneg = leg.amplrejneg; cur.refelecchan = leg.refelecchan; - copyArr(cur.unitmapping, leg.unitmapping, fromLegacy); - copyArr2D(cur.spkhoops, leg.spkhoops, fromLegacy); + copyArr(cur.unitmapping, leg.unitmapping, fromLegacy, ctx); + copyArr2D(cur.spkhoops, leg.spkhoops, fromLegacy, ctx); return cur; } -::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) { +::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg, const TranslationContext& ctx) { ::cbPKT_FS_BASIS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.mode = leg.mode; cur.fs = leg.fs; @@ -233,9 +233,9 @@ ::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) { return cur; } -::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) { +::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg, const TranslationContext& ctx) { ::cbPKT_SS_MODELSET cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.unit_number = leg.unit_number; cur.valid = leg.valid; @@ -253,34 +253,34 @@ ::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) { return cur; } -::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg) { +::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg, const TranslationContext& ctx) { ::cbPKT_SS_DETECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.fThreshold = leg.fThreshold; cur.fMultiplier = leg.fMultiplier; return cur; } -::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) { +::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg, const TranslationContext& ctx) { ::cbPKT_SS_ARTIF_REJECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.nMaxSimulChans = leg.nMaxSimulChans; cur.nRefractoryCount = leg.nRefractoryCount; return cur; } -::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) { +::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg, const TranslationContext& ctx) { ::cbPKT_SS_NOISE_BOUNDARY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; copyArr(cur.afc, leg.afc); copyArr2D(cur.afS, leg.afS); return cur; } -::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) { +::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg, const TranslationContext& ctx) { ::cbPKT_SS_STATISTICS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.nUpdateSpikes = leg.nUpdateSpikes; cur.nAutoalg = leg.nAutoalg; cur.nMode = leg.nMode; @@ -296,7 +296,7 @@ ::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) { return cur; } -::cbAdaptControl fromLegacy(const cbAdaptControl& leg) { +::cbAdaptControl fromLegacy(const cbAdaptControl& leg, const TranslationContext& ctx) { ::cbAdaptControl cur{}; cur.nMode = leg.nMode; cur.fTimeOutMinutes = leg.fTimeOutMinutes; @@ -304,39 +304,39 @@ ::cbAdaptControl fromLegacy(const cbAdaptControl& leg) { return cur; } -::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg) { +::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg, const TranslationContext& ctx) { ::cbPKT_SS_STATUS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); - cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats); - cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); + cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats, ctx); + cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits, ctx); return cur; } -::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg) { +::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg, const TranslationContext& ctx) { ::cbproto::SpikeSorting cur{}; - copyArr(cur.basis, leg.asBasis, fromLegacy); - copyArr2D(cur.models, leg.asSortModel, fromLegacy); - cur.detect = fromLegacy(leg.pktDetect); - cur.artifact_reject = fromLegacy(leg.pktArtifReject); - copyArr(cur.noise_boundary, leg.pktNoiseBoundary, fromLegacy); - cur.statistics = fromLegacy(leg.pktStatistics); - cur.status = fromLegacy(leg.pktStatus); + copyArr(cur.basis, leg.asBasis, fromLegacy, ctx); + copyArr2D(cur.models, leg.asSortModel, fromLegacy, ctx); + cur.detect = fromLegacy(leg.pktDetect, ctx); + cur.artifact_reject = fromLegacy(leg.pktArtifReject, ctx); + copyArr(cur.noise_boundary, leg.pktNoiseBoundary, fromLegacy, ctx); + cur.statistics = fromLegacy(leg.pktStatistics, ctx); + cur.status = fromLegacy(leg.pktStatus, ctx); return cur; } -::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg) { +::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg, const TranslationContext& ctx) { ::cbPKT_NTRODEINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.ntrode = leg.ntrode; copyArr(cur.label, leg.label); - copyArr2D(cur.ellipses, leg.ellipses, fromLegacy); + copyArr2D(cur.ellipses, leg.ellipses, fromLegacy, ctx); cur.nSite = leg.nSite; cur.fs = leg.fs; copyArr(cur.nChan, leg.nChan); return cur; } -::cbWaveformData fromLegacy(const cbWaveformData& leg) { +::cbWaveformData fromLegacy(const cbWaveformData& leg, const TranslationContext& ctx) { ::cbWaveformData cur{}; cur.offset = leg.offset; // aka sineFrequency cur.seq = leg.seq; // aka sineAmplitude @@ -347,9 +347,9 @@ ::cbWaveformData fromLegacy(const cbWaveformData& leg) { return cur; } -::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) { +::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg, const TranslationContext& ctx) { ::cbPKT_AOUT_WAVEFORM cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.chan = leg.chan; cur.mode = leg.mode; cur.repeats = leg.repeats; @@ -359,22 +359,22 @@ ::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) { cur.trigValue = leg.trigValue; cur.trigNum = leg.trigNum; cur.active = leg.active; - cur.wave = fromLegacy(leg.wave); + cur.wave = fromLegacy(leg.wave, ctx); return cur; } -::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg) { +::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg, const TranslationContext& ctx) { ::cbPKT_LNC cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.lncFreq = leg.lncFreq; cur.lncRefChan = leg.lncRefChan; cur.lncGlobalMode = leg.lncGlobalMode; return cur; } -::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) { +::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg, const TranslationContext& ctx) { ::cbPKT_NPLAY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.ftime = leg.ftime; // aka opt cur.stime = leg.stime; cur.etime = leg.etime; @@ -386,14 +386,14 @@ ::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) { return cur; } -::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg) { +::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg, const TranslationContext& ctx) { ::cbVIDEOSOURCE cur{}; copyArr(cur.name, leg.name); cur.fps = leg.fps; return cur; } -::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) { +::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg, const TranslationContext& ctx) { ::cbTRACKOBJ cur{}; copyArr(cur.name, leg.name); cur.type = leg.type; @@ -401,9 +401,9 @@ ::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) { return cur; } -::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) { +::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg, const TranslationContext& ctx) { ::cbPKT_FILECFG cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); cur.options = leg.options; cur.duration = leg.duration; cur.recording = leg.recording; @@ -414,7 +414,118 @@ ::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) { return cur; } -cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) { +NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg, const TranslationContext& ctx) { + // TODO: VERIFY that each list that's assumed to be instrument-independent is in fact independent from any particular instrument. + NativeConfigBuffer cur{}; + cur.version = leg.version; + cur.sysflags = leg.sysflags; + cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); + cur.sysinfo = fromLegacy(leg.sysinfo, ctx); + cur.procinfo = fromLegacy(leg.procinfo[ctx.instrument_idx], ctx); + copyArr(cur.bankinfo, leg.bankinfo[ctx.instrument_idx], fromLegacy, ctx); + copyArr(cur.groupinfo, leg.groupinfo[ctx.instrument_idx], fromLegacy, ctx); + copyArr(cur.filtinfo, leg.filtinfo[ctx.instrument_idx], fromLegacy, ctx); + cur.adaptinfo = fromLegacy(leg.adaptinfo[ctx.instrument_idx], ctx); + cur.refelecinfo = fromLegacy(leg.refelecinfo[ctx.instrument_idx], ctx); + copyArr(cur.chaninfo, leg.chaninfo, fromLegacy, ctx); + copyArr(cur.asBasis, leg.isSortingOptions.asBasis, fromLegacy, ctx); + copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, fromLegacy, ctx); + // TODO: Move native isSortingOptions fields into a struct + cur.pktDetect = fromLegacy(leg.isSortingOptions.pktDetect, ctx); + cur.pktArtifReject = fromLegacy(leg.isSortingOptions.pktArtifReject, ctx); + copyArr(cur.pktNoiseBoundary, leg.isSortingOptions.pktNoiseBoundary, fromLegacy, ctx); + cur.pktStatistics = fromLegacy(leg.isSortingOptions.pktStatistics, ctx); + cur.pktStatus = fromLegacy(leg.isSortingOptions.pktStatus, ctx); + copyArr(cur.isNTrodeInfo, leg.isNTrodeInfo, fromLegacy, ctx); + copyArr2D(cur.isWaveform, leg.isWaveform, fromLegacy, ctx); + cur.isLnc = fromLegacy(leg.isLnc[ctx.instrument_idx], ctx); + cur.isNPlay = fromLegacy(leg.isNPlay, ctx); + copyArr(cur.isVideoSource, leg.isVideoSource, fromLegacy, ctx); + copyArr(cur.isTrackObj, leg.isTrackObj, fromLegacy, ctx); + cur.fileinfo = fromLegacy(leg.fileinfo, ctx); + + return cur; +} + +NativeNSPStatus fromLegacy(const NSPStatus& leg, const TranslationContext& ctx) { + switch(leg) { + case NSPStatus::NSP_INIT: + return NativeNSPStatus::NSP_INIT; + case NSPStatus::NSP_NOIPADDR: + return NativeNSPStatus::NSP_NOIPADDR; + case NSPStatus::NSP_NOREPLY: + return NativeNSPStatus::NSP_NOREPLY; + case NSPStatus::NSP_FOUND: + return NativeNSPStatus::NSP_FOUND; + case NSPStatus::NSP_INVALID: + default: + return NativeNSPStatus::NSP_INVALID; + } +} + +::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg, const TranslationContext& ctx) { + ::cbPKT_UNIT_SELECTION cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); + cur.lastchan = leg.lastchan; + copyArr(cur.abyUnitSelections, leg.abyUnitSelections); + return cur; +} + +NativePCStatus fromLegacy(const cbPcStatus& leg, const TranslationContext& ctx) { + NativePCStatus cur{}; + cur.isSelection = fromLegacy(leg.isSelection[ctx.instrument_idx], ctx); + cur.m_iBlockRecording = leg.m_iBlockRecording; + cur.m_nPCStatusFlags = leg.m_nPCStatusFlags; + cur.m_nNumFEChans = leg.m_nNumFEChans; + cur.m_nNumAnainChans = leg.m_nNumAnainChans; + cur.m_nNumAnalogChans = leg.m_nNumAnalogChans; + cur.m_nNumAoutChans = leg.m_nNumAoutChans; + cur.m_nNumAudioChans = leg.m_nNumAudioChans; + cur.m_nNumAnalogoutChans = leg.m_nNumAnalogoutChans; + cur.m_nNumDiginChans = leg.m_nNumDiginChans; + cur.m_nNumSerialChans = leg.m_nNumSerialChans; + cur.m_nNumDigoutChans = leg.m_nNumDigoutChans; + cur.m_nNumTotalChans = leg.m_nNumTotalChans; + cur.m_nNspStatus = fromLegacy(leg.m_nNspStatus[ctx.instrument_idx], ctx); + cur.m_nNumNTrodesPerInstrument = leg.m_nNumNTrodesPerInstrument[ctx.instrument_idx]; + cur.m_nGeminiSystem = leg.m_nGeminiSystem; + // ignore APP_WORKSPACE + return cur; +} + +NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg, const TranslationContext& ctx) { + NativeReceiveBuffer cur{}; + cur.received = leg.received; + cur.lasttime = leg.lasttime; + cur.headwrap = leg.headwrap; + cur.headindex = leg.headindex; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg, const TranslationContext& ctx) { + NativeTransmitBuffer cur{}; + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg, const TranslationContext& ctx) { + NativeTransmitBufferLocal cur{}; + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur, const TranslationContext& ctx) { cbPKT_HEADER leg{}; leg.time = cur.time; leg.chid = cur.chid; @@ -425,9 +536,9 @@ cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) { return leg; } -cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) { +cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur, const TranslationContext& ctx) { cbPKT_SYSINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.sysfreq = cur.sysfreq; leg.spikelen = cur.spikelen; leg.spikepre = cur.spikepre; @@ -437,9 +548,9 @@ cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) { return leg; } -cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) { +cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur, const TranslationContext& ctx) { cbPKT_PROCINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.proc = cur.proc; leg.idcode = cur.idcode; leg.idcode = cur.idcode; @@ -457,9 +568,9 @@ cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) { return leg; } -cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) { +cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur, const TranslationContext& ctx) { cbPKT_BANKINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.proc = cur.proc; leg.bank = cur.bank; leg.idcode = cur.idcode; @@ -470,9 +581,9 @@ cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) { return leg; } -cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) { +cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur, const TranslationContext& ctx) { cbPKT_GROUPINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.proc = cur.proc; leg.group = cur.group; copyArr(leg.label, cur.label); @@ -482,9 +593,9 @@ cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) { return leg; } -cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) { +cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur, const TranslationContext& ctx) { cbPKT_FILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.proc = cur.proc; leg.filt = cur.filt; copyArr(leg.label, cur.label); @@ -506,9 +617,9 @@ cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) { return leg; } -cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) { +cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur, const TranslationContext& ctx) { cbPKT_ADAPTFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.nMode = cur.nMode; leg.dLearningRate = cur.dLearningRate; @@ -517,16 +628,16 @@ cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) { return leg; } -cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur) { +cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur, const TranslationContext& ctx) { cbPKT_REFELECFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.nMode = cur.nMode; leg.nRefChan = cur.nRefChan; return leg; } -cbSCALING toLegacy(const ::cbSCALING& cur) { +cbSCALING toLegacy(const ::cbSCALING& cur, const TranslationContext& ctx) { cbSCALING leg{}; leg.digmin = cur.digmin; leg.digmax = cur.digmax; @@ -537,7 +648,7 @@ cbSCALING toLegacy(const ::cbSCALING& cur) { return leg; } -cbFILTDESC toLegacy(const ::cbFILTDESC& cur) { +cbFILTDESC toLegacy(const ::cbFILTDESC& cur, const TranslationContext& ctx) { cbFILTDESC leg{}; leg.hpfreq = cur.hpfreq; leg.hporder = cur.hporder; @@ -548,7 +659,7 @@ cbFILTDESC toLegacy(const ::cbFILTDESC& cur) { return leg; } -cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) { +cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur, const TranslationContext& ctx) { cbMANUALUNITMAPPING leg{}; leg.nOverride = cur.nOverride; copyArr(leg.afOrigin, cur.afOrigin); @@ -558,7 +669,7 @@ cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) { return leg; } -cbHOOP toLegacy(const ::cbHOOP& cur) { +cbHOOP toLegacy(const ::cbHOOP& cur, const TranslationContext& ctx) { cbHOOP leg{}; leg.valid = cur.valid; leg.time = cur.time; @@ -567,9 +678,9 @@ cbHOOP toLegacy(const ::cbHOOP& cur) { return leg; } -cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) { +cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur, const TranslationContext& ctx) { cbPKT_CHANINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.proc = cur.proc; leg.bank = cur.bank; @@ -580,15 +691,15 @@ cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) { leg.aoutcaps = cur.aoutcaps; leg.ainpcaps = cur.ainpcaps; leg.spkcaps = cur.spkcaps; - leg.physcalin = toLegacy(cur.physcalin); - leg.phyfiltin = toLegacy(cur.phyfiltin); - leg.physcalout = toLegacy(cur.physcalout); - leg.phyfiltout = toLegacy(cur.phyfiltout); + leg.physcalin = toLegacy(cur.physcalin, ctx); + leg.phyfiltin = toLegacy(cur.phyfiltin, ctx); + leg.physcalout = toLegacy(cur.physcalout, ctx); + leg.phyfiltout = toLegacy(cur.phyfiltout, ctx); copyArr(leg.label, cur.label); leg.userflags = cur.userflags; copyArr(leg.position, cur.position); - leg.scalin = toLegacy(cur.scalin); - leg.scalout = toLegacy(cur.scalout); + leg.scalin = toLegacy(cur.scalin, ctx); + leg.scalout = toLegacy(cur.scalout, ctx); leg.doutopts = cur.doutopts; leg.dinpopts = cur.dinpopts; leg.aoutopts = cur.aoutopts; @@ -617,14 +728,14 @@ cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) { leg.amplrejpos = cur.amplrejpos; leg.amplrejneg = cur.amplrejneg; leg.refelecchan = cur.refelecchan; - copyArr(leg.unitmapping, cur.unitmapping, toLegacy); - copyArr2D(leg.spkhoops, cur.spkhoops, toLegacy); + copyArr(leg.unitmapping, cur.unitmapping, toLegacy, ctx); + copyArr2D(leg.spkhoops, cur.spkhoops, toLegacy, ctx); return leg; } -cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) { +cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur, const TranslationContext& ctx) { cbPKT_FS_BASIS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.mode = cur.mode; leg.fs = cur.fs; @@ -632,9 +743,9 @@ cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) { return leg; } -cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) { +cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur, const TranslationContext& ctx) { cbPKT_SS_MODELSET leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.unit_number = cur.unit_number; leg.valid = cur.valid; @@ -652,34 +763,34 @@ cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) { return leg; } -cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur) { +cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur, const TranslationContext& ctx) { cbPKT_SS_DETECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.fThreshold = cur.fThreshold; leg.fMultiplier = cur.fMultiplier; return leg; } -cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) { +cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur, const TranslationContext& ctx) { cbPKT_SS_ARTIF_REJECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.nMaxSimulChans = cur.nMaxSimulChans; leg.nRefractoryCount = cur.nRefractoryCount; return leg; } -cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) { +cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur, const TranslationContext& ctx) { cbPKT_SS_NOISE_BOUNDARY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; copyArr(leg.afc, cur.afc); copyArr2D(leg.afS, cur.afS); return leg; } -cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) { +cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur, const TranslationContext& ctx) { cbPKT_SS_STATISTICS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.nUpdateSpikes = cur.nUpdateSpikes; leg.nAutoalg = cur.nAutoalg; leg.nMode = cur.nMode; @@ -695,7 +806,7 @@ cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) { return leg; } -cbAdaptControl toLegacy(const ::cbAdaptControl& cur) { +cbAdaptControl toLegacy(const ::cbAdaptControl& cur, const TranslationContext& ctx) { cbAdaptControl leg{}; leg.nMode = cur.nMode; leg.fTimeOutMinutes = cur.fTimeOutMinutes; @@ -703,39 +814,39 @@ cbAdaptControl toLegacy(const ::cbAdaptControl& cur) { return leg; } -cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur) { +cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur, const TranslationContext& ctx) { cbPKT_SS_STATUS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); - leg.cntlUnitStats = toLegacy(cur.cntlUnitStats); - leg.cntlNumUnits = toLegacy(cur.cntlNumUnits); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); + leg.cntlUnitStats = toLegacy(cur.cntlUnitStats, ctx); + leg.cntlNumUnits = toLegacy(cur.cntlNumUnits, ctx); return leg; } -cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur) { +cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur, const TranslationContext& ctx) { cbSPIKE_SORTING leg{}; - copyArr(leg.asBasis, cur.basis, toLegacy); - copyArr2D(leg.asSortModel, cur.models, toLegacy); - leg.pktDetect = toLegacy(cur.detect); - leg.pktArtifReject = toLegacy(cur.artifact_reject); - copyArr(leg.pktNoiseBoundary, cur.noise_boundary, toLegacy); - leg.pktStatistics = toLegacy(cur.statistics); - leg.pktStatus = toLegacy(cur.status); + copyArr(leg.asBasis, cur.basis, toLegacy, ctx); + copyArr2D(leg.asSortModel, cur.models, toLegacy, ctx); + leg.pktDetect = toLegacy(cur.detect, ctx); + leg.pktArtifReject = toLegacy(cur.artifact_reject, ctx); + copyArr(leg.pktNoiseBoundary, cur.noise_boundary, toLegacy, ctx); + leg.pktStatistics = toLegacy(cur.statistics, ctx); + leg.pktStatus = toLegacy(cur.status, ctx); return leg; } -cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur) { +cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur, const TranslationContext& ctx) { cbPKT_NTRODEINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.ntrode = cur.ntrode; copyArr(leg.label, cur.label); - copyArr2D(leg.ellipses, cur.ellipses, toLegacy); + copyArr2D(leg.ellipses, cur.ellipses, toLegacy, ctx); leg.nSite = cur.nSite; leg.fs = cur.fs; copyArr(leg.nChan, cur.nChan); return leg; } -cbWaveformData toLegacy(const ::cbWaveformData& cur) { +cbWaveformData toLegacy(const ::cbWaveformData& cur, const TranslationContext& ctx) { cbWaveformData leg{}; leg.offset = cur.offset; // aka sineFrequency leg.seq = cur.seq; // aka sineAmplitude @@ -746,9 +857,9 @@ cbWaveformData toLegacy(const ::cbWaveformData& cur) { return leg; } -cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) { +cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur, const TranslationContext& ctx) { cbPKT_AOUT_WAVEFORM leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.chan = cur.chan; leg.mode = cur.mode; leg.repeats = cur.repeats; @@ -758,22 +869,22 @@ cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) { leg.trigValue = cur.trigValue; leg.trigNum = cur.trigNum; leg.active = cur.active; - leg.wave = toLegacy(cur.wave); + leg.wave = toLegacy(cur.wave, ctx); return leg; } -cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur) { +cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur, const TranslationContext& ctx) { cbPKT_LNC leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.lncFreq = cur.lncFreq; leg.lncRefChan = cur.lncRefChan; leg.lncGlobalMode = cur.lncGlobalMode; return leg; } -cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) { +cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur, const TranslationContext& ctx) { cbPKT_NPLAY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.ftime = cur.ftime; // aka opt leg.stime = cur.stime; leg.etime = cur.etime; @@ -785,14 +896,14 @@ cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) { return leg; } -cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) { +cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur, const TranslationContext& ctx) { cbVIDEOSOURCE leg{}; copyArr(leg.name, cur.name); leg.fps = cur.fps; return leg; } -cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) { +cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur, const TranslationContext& ctx) { cbTRACKOBJ leg{}; copyArr(leg.name, cur.name); leg.type = cur.type; @@ -800,9 +911,9 @@ cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) { return leg; } -cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) { +cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur, const TranslationContext& ctx) { cbPKT_FILECFG leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); leg.options = cur.options; leg.duration = cur.duration; leg.recording = cur.recording; @@ -813,6 +924,84 @@ cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) { return leg; } +NSPStatus toLegacy(const NativeNSPStatus& cur, const TranslationContext& ctx) { + switch(cur) { + case NativeNSPStatus::NSP_INIT: + return NSPStatus::NSP_INIT; + case NativeNSPStatus::NSP_NOIPADDR: + return NSPStatus::NSP_NOIPADDR; + case NativeNSPStatus::NSP_NOREPLY: + return NSPStatus::NSP_NOREPLY; + case NativeNSPStatus::NSP_FOUND: + return NSPStatus::NSP_FOUND; + case NativeNSPStatus::NSP_INVALID: + default: + return NSPStatus::NSP_INVALID; + } +} + +cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur, const TranslationContext& ctx) { + cbPKT_UNIT_SELECTION leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); + leg.lastchan = cur.lastchan; + copyArr(leg.abyUnitSelections, cur.abyUnitSelections); + return leg; +} + +cbPcStatus toLegacy(const NativePCStatus& cur, const TranslationContext& ctx) { + cbPcStatus leg{}; + leg.isSelection[ctx.instrument_idx] = toLegacy(cur.isSelection, ctx); + leg.m_iBlockRecording = cur.m_iBlockRecording; + leg.m_nPCStatusFlags = cur.m_nPCStatusFlags; + leg.m_nNumFEChans = cur.m_nNumFEChans; + leg.m_nNumAnainChans = cur.m_nNumAnainChans; + leg.m_nNumAnalogChans = cur.m_nNumAnalogChans; + leg.m_nNumAoutChans = cur.m_nNumAoutChans; + leg.m_nNumAudioChans = cur.m_nNumAudioChans; + leg.m_nNumAnalogoutChans = cur.m_nNumAnalogoutChans; + leg.m_nNumDiginChans = cur.m_nNumDiginChans; + leg.m_nNumSerialChans = cur.m_nNumSerialChans; + leg.m_nNumDigoutChans = cur.m_nNumDigoutChans; + leg.m_nNumTotalChans = cur.m_nNumTotalChans; + leg.m_nNspStatus[ctx.instrument_idx] = toLegacy(cur.m_nNspStatus, ctx); + leg.m_nNumNTrodesPerInstrument[ctx.instrument_idx] = cur.m_nNumNTrodesPerInstrument; + leg.m_nGeminiSystem = cur.m_nGeminiSystem; + // ignore APP_WORKSPACE + return leg; +} + +cbRECBUFF toLegacy(const NativeReceiveBuffer& cur, const TranslationContext& ctx) { + cbRECBUFF leg{}; + leg.received = cur.received; + leg.lasttime = cur.lasttime; + leg.headwrap = cur.headwrap; + leg.headindex = cur.headindex; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur, const TranslationContext& ctx) { + cbXMTBUFF leg{}; + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur, const TranslationContext& ctx) { + cbXMTBUFFLOCAL leg{}; + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); + return leg; +} + } // namespace central_v4_2 } // namespace cbshm From 4502eb1fc92f2067205928cf9a487fd4fb55fe3e Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Mon, 8 Jun 2026 11:15:56 -0600 Subject: [PATCH 17/62] Change call sites in cbsdk for the new ShmemSession API --- src/cbsdk/include/cbsdk/sdk_session.h | 8 +- src/cbsdk/src/cbsdk.cpp | 116 ++++++------ src/cbsdk/src/sdk_session.cpp | 252 ++++++++++++-------------- 3 files changed, 175 insertions(+), 201 deletions(-) diff --git a/src/cbsdk/include/cbsdk/sdk_session.h b/src/cbsdk/include/cbsdk/sdk_session.h index 089df375..630e3081 100644 --- a/src/cbsdk/include/cbsdk/sdk_session.h +++ b/src/cbsdk/include/cbsdk/sdk_session.h @@ -421,17 +421,17 @@ class SdkSession { /// Get system information /// @return Pointer to system info packet, or nullptr if not available - const cbPKT_SYSINFO* getSysInfo() const; + Result getSysInfo() const; /// Get channel information /// @param chan_id 1-based channel ID (1 to cbMAXCHANS) /// @return Pointer to channel info, or nullptr if invalid/unavailable - const cbPKT_CHANINFO* getChanInfo(uint32_t chan_id) const; + Result getChanInfo(uint32_t chan_id) const; /// Get sample group information /// @param group_id Group ID (1-6) /// @return Pointer to group info, or nullptr if invalid/unavailable - const cbPKT_GROUPINFO* getGroupInfo(uint32_t group_id) const; + Result getGroupInfo(uint32_t group_id) const; /// Compute the list of channel IDs belonging to a sample group by /// scanning individual chaninfo records. More reliable than getGroupInfo() @@ -446,7 +446,7 @@ class SdkSession { /// Get filter information /// @param filter_id Filter ID (0 to cbMAXFILTS-1) /// @return Pointer to filter info, or nullptr if invalid/unavailable - const cbPKT_FILTINFO* getFilterInfo(uint32_t filter_id) const; + Result getFilterInfo(uint32_t filter_id) const; /// Get current device run level /// @return Current run level (cbRUNLEVEL_*), or 0 if unknown diff --git a/src/cbsdk/src/cbsdk.cpp b/src/cbsdk/src/cbsdk.cpp index 99533dd5..325aac7a 100644 --- a/src/cbsdk/src/cbsdk.cpp +++ b/src/cbsdk/src/cbsdk.cpp @@ -699,8 +699,8 @@ const char* cbsdk_session_get_channel_label(cbsdk_session_t session, uint32_t ch return nullptr; } try { - const cbPKT_CHANINFO* info = session->cpp_session->getChanInfo(chan_id); - return info ? info->label : nullptr; + auto info = session->cpp_session->getChanInfo(chan_id); + return info.isOk() ? info.value().label : nullptr; } catch (...) { return nullptr; } @@ -711,8 +711,8 @@ uint32_t cbsdk_session_get_channel_smpgroup(cbsdk_session_t session, uint32_t ch return 0; } try { - const cbPKT_CHANINFO* info = session->cpp_session->getChanInfo(chan_id); - return info ? info->smpgroup : 0; + auto info = session->cpp_session->getChanInfo(chan_id); + return info.isOk() ? info.value().smpgroup : 0; } catch (...) { return 0; } @@ -723,8 +723,8 @@ uint32_t cbsdk_session_get_channel_chancaps(cbsdk_session_t session, uint32_t ch return 0; } try { - const cbPKT_CHANINFO* info = session->cpp_session->getChanInfo(chan_id); - return info ? info->chancaps : 0; + auto info = session->cpp_session->getChanInfo(chan_id); + return info.isOk() ? info.value().chancaps : 0; } catch (...) { return 0; } @@ -735,10 +735,11 @@ cbproto_channel_type_t cbsdk_session_get_channel_type(cbsdk_session_t session, u return static_cast(-1); } try { - const cbPKT_CHANINFO* info = session->cpp_session->getChanInfo(chan_id); - if (!info) return static_cast(-1); + auto info = session->cpp_session->getChanInfo(chan_id); + if (info.isError()) return static_cast(-1); + cbPKT_CHANINFO& ci = info.value(); - const uint32_t caps = info->chancaps; + const uint32_t caps = ci.chancaps; if ((cbCHAN_EXISTS | cbCHAN_CONNECTED) != (caps & (cbCHAN_EXISTS | cbCHAN_CONNECTED))) return static_cast(-1); @@ -747,12 +748,12 @@ cbproto_channel_type_t cbsdk_session_get_channel_type(cbsdk_session_t session, u if (cbCHAN_AINP == (caps & (cbCHAN_AINP | cbCHAN_ISOLATED))) return CBPROTO_CHANNEL_TYPE_ANALOG_IN; if (cbCHAN_AOUT == (caps & cbCHAN_AOUT)) { - if (cbAOUT_AUDIO == (info->aoutcaps & cbAOUT_AUDIO)) + if (cbAOUT_AUDIO == (ci.aoutcaps & cbAOUT_AUDIO)) return CBPROTO_CHANNEL_TYPE_AUDIO; return CBPROTO_CHANNEL_TYPE_ANALOG_OUT; } if (cbCHAN_DINP == (caps & cbCHAN_DINP)) { - if (info->dinpcaps & cbDINP_SERIALMASK) + if (ci.dinpcaps & cbDINP_SERIALMASK) return CBPROTO_CHANNEL_TYPE_SERIAL; return CBPROTO_CHANNEL_TYPE_DIGITAL_IN; } @@ -768,72 +769,72 @@ cbproto_channel_type_t cbsdk_session_get_channel_type(cbsdk_session_t session, u uint32_t cbsdk_session_get_channel_smpfilter(cbsdk_session_t session, uint32_t chan_id) { if (!session || !session->cpp_session) return 0; try { - const cbPKT_CHANINFO* info = session->cpp_session->getChanInfo(chan_id); - return info ? info->smpfilter : 0; + auto info = session->cpp_session->getChanInfo(chan_id); + return info.isOk() ? info.value().smpfilter : 0; } catch (...) { return 0; } } uint32_t cbsdk_session_get_channel_spkfilter(cbsdk_session_t session, uint32_t chan_id) { if (!session || !session->cpp_session) return 0; try { - const cbPKT_CHANINFO* info = session->cpp_session->getChanInfo(chan_id); - return info ? info->spkfilter : 0; + auto info = session->cpp_session->getChanInfo(chan_id); + return info.isOk() ? info.value().spkfilter : 0; } catch (...) { return 0; } } uint32_t cbsdk_session_get_channel_spkopts(cbsdk_session_t session, uint32_t chan_id) { if (!session || !session->cpp_session) return 0; try { - const cbPKT_CHANINFO* info = session->cpp_session->getChanInfo(chan_id); - return info ? info->spkopts : 0; + auto info = session->cpp_session->getChanInfo(chan_id); + return info.isOk() ? info.value().spkopts : 0; } catch (...) { return 0; } } int32_t cbsdk_session_get_channel_spkthrlevel(cbsdk_session_t session, uint32_t chan_id) { if (!session || !session->cpp_session) return 0; try { - const cbPKT_CHANINFO* info = session->cpp_session->getChanInfo(chan_id); - return info ? info->spkthrlevel : 0; + auto info = session->cpp_session->getChanInfo(chan_id); + return info.isOk() ? info.value().spkthrlevel : 0; } catch (...) { return 0; } } uint32_t cbsdk_session_get_channel_ainpopts(cbsdk_session_t session, uint32_t chan_id) { if (!session || !session->cpp_session) return 0; try { - const cbPKT_CHANINFO* info = session->cpp_session->getChanInfo(chan_id); - return info ? info->ainpopts : 0; + auto info = session->cpp_session->getChanInfo(chan_id); + return info.isOk() ? info.value().ainpopts : 0; } catch (...) { return 0; } } uint32_t cbsdk_session_get_channel_lncrate(cbsdk_session_t session, uint32_t chan_id) { if (!session || !session->cpp_session) return 0; try { - const cbPKT_CHANINFO* info = session->cpp_session->getChanInfo(chan_id); - return info ? info->lncrate : 0; + auto info = session->cpp_session->getChanInfo(chan_id); + return info.isOk() ? info.value().lncrate : 0; } catch (...) { return 0; } } uint32_t cbsdk_session_get_channel_refelecchan(cbsdk_session_t session, uint32_t chan_id) { if (!session || !session->cpp_session) return 0; try { - const cbPKT_CHANINFO* info = session->cpp_session->getChanInfo(chan_id); - return info ? info->refelecchan : 0; + auto info = session->cpp_session->getChanInfo(chan_id); + return info.isOk() ? info.value().refelecchan : 0; } catch (...) { return 0; } } int16_t cbsdk_session_get_channel_amplrejpos(cbsdk_session_t session, uint32_t chan_id) { if (!session || !session->cpp_session) return 0; try { - const cbPKT_CHANINFO* info = session->cpp_session->getChanInfo(chan_id); - return info ? info->amplrejpos : 0; + auto info = session->cpp_session->getChanInfo(chan_id); + return info.isOk() ? info.value().amplrejpos : 0; } catch (...) { return 0; } } int16_t cbsdk_session_get_channel_amplrejneg(cbsdk_session_t session, uint32_t chan_id) { if (!session || !session->cpp_session) return 0; try { - const cbPKT_CHANINFO* info = session->cpp_session->getChanInfo(chan_id); - return info ? info->amplrejneg : 0; + auto info = session->cpp_session->getChanInfo(chan_id); + return info.isOk() ? info.value().amplrejneg : 0; } catch (...) { return 0; } } @@ -843,14 +844,15 @@ cbsdk_result_t cbsdk_session_get_channel_scaling( return CBSDK_RESULT_INVALID_PARAMETER; } try { - const cbPKT_CHANINFO* info = session->cpp_session->getChanInfo(chan_id); - if (!info) return CBSDK_RESULT_INVALID_PARAMETER; - scaling->digmin = info->scalin.digmin; - scaling->digmax = info->scalin.digmax; - scaling->anamin = info->scalin.anamin; - scaling->anamax = info->scalin.anamax; - scaling->anagain = info->scalin.anagain; - std::memcpy(scaling->anaunit, info->scalin.anaunit, sizeof(scaling->anaunit)); + auto info = session->cpp_session->getChanInfo(chan_id); + if (info.isError()) return CBSDK_RESULT_INVALID_PARAMETER; + cbPKT_CHANINFO& ci = info.value(); + scaling->digmin = ci.scalin.digmin; + scaling->digmax = ci.scalin.digmax; + scaling->anamin = ci.scalin.anamin; + scaling->anamax = ci.scalin.anamax; + scaling->anagain = ci.scalin.anagain; + std::memcpy(scaling->anaunit, ci.scalin.anaunit, sizeof(scaling->anaunit)); return CBSDK_RESULT_SUCCESS; } catch (...) { std::memset(scaling, 0, sizeof(cbsdk_channel_scaling_t)); @@ -875,8 +877,8 @@ const char* cbsdk_session_get_group_label(cbsdk_session_t session, uint32_t grou return nullptr; } try { - const cbPKT_GROUPINFO* info = session->cpp_session->getGroupInfo(group_id); - return info ? info->label : nullptr; + auto info = session->cpp_session->getGroupInfo(group_id); + return info.isOk() ? info.value().label : nullptr; } catch (...) { return nullptr; } @@ -956,9 +958,9 @@ static cbsdk_result_t modify_and_send_chaninfo( auto sync_result = session->cpp_session->sync(5000); if (sync_result.isError()) return CBSDK_RESULT_INTERNAL_ERROR; } - const cbPKT_CHANINFO* info = session->cpp_session->getChanInfo(chan_id); - if (!info) return CBSDK_RESULT_INVALID_PARAMETER; - cbPKT_CHANINFO ci = *info; + auto info = session->cpp_session->getChanInfo(chan_id); + if (info.isError()) return CBSDK_RESULT_INVALID_PARAMETER; + cbPKT_CHANINFO& ci = info.value(); ci.chan = chan_id; ci.cbpkt_header.type = pkt_type; modify(ci); @@ -994,9 +996,9 @@ cbsdk_result_t cbsdk_session_set_channel_smpgroup( auto sync_result = session->cpp_session->sync(5000); if (sync_result.isError()) return CBSDK_RESULT_INTERNAL_ERROR; } - const cbPKT_CHANINFO* info = session->cpp_session->getChanInfo(chan_id); - if (!info) return CBSDK_RESULT_INVALID_PARAMETER; - cbPKT_CHANINFO ci = *info; + auto info = session->cpp_session->getChanInfo(chan_id); + if (info.isError()) return CBSDK_RESULT_INVALID_PARAMETER; + cbPKT_CHANINFO& ci = info.value(); ci.chan = chan_id; if (rate == 0) { @@ -1225,8 +1227,8 @@ cbsdk_result_t cbsdk_session_get_channels_positions( uint32_t cbsdk_session_get_sysfreq(cbsdk_session_t session) { if (!session || !session->cpp_session) return 0; try { - const cbPKT_SYSINFO* info = session->cpp_session->getSysInfo(); - return info ? info->sysfreq : 0; + auto info = session->cpp_session->getSysInfo(); + return info.isOk() ? info.value().sysfreq : 0; } catch (...) { return 0; } } @@ -1237,40 +1239,40 @@ uint32_t cbsdk_get_num_filters(void) { const char* cbsdk_session_get_filter_label(cbsdk_session_t session, uint32_t filter_id) { if (!session || !session->cpp_session) return nullptr; try { - const cbPKT_FILTINFO* info = session->cpp_session->getFilterInfo(filter_id); - return info ? info->label : nullptr; + auto info = session->cpp_session->getFilterInfo(filter_id); + return info.isOk() ? info.value().label : nullptr; } catch (...) { return nullptr; } } uint32_t cbsdk_session_get_filter_hpfreq(cbsdk_session_t session, uint32_t filter_id) { if (!session || !session->cpp_session) return 0; try { - const cbPKT_FILTINFO* info = session->cpp_session->getFilterInfo(filter_id); - return info ? info->hpfreq : 0; + auto info = session->cpp_session->getFilterInfo(filter_id); + return info.isOk() ? info.value().hpfreq : 0; } catch (...) { return 0; } } uint32_t cbsdk_session_get_filter_hporder(cbsdk_session_t session, uint32_t filter_id) { if (!session || !session->cpp_session) return 0; try { - const cbPKT_FILTINFO* info = session->cpp_session->getFilterInfo(filter_id); - return info ? info->hporder : 0; + auto info = session->cpp_session->getFilterInfo(filter_id); + return info.isOk() ? info.value().hporder : 0; } catch (...) { return 0; } } uint32_t cbsdk_session_get_filter_lpfreq(cbsdk_session_t session, uint32_t filter_id) { if (!session || !session->cpp_session) return 0; try { - const cbPKT_FILTINFO* info = session->cpp_session->getFilterInfo(filter_id); - return info ? info->lpfreq : 0; + auto info = session->cpp_session->getFilterInfo(filter_id); + return info.isOk() ? info.value().lpfreq : 0; } catch (...) { return 0; } } uint32_t cbsdk_session_get_filter_lporder(cbsdk_session_t session, uint32_t filter_id) { if (!session || !session->cpp_session) return 0; try { - const cbPKT_FILTINFO* info = session->cpp_session->getFilterInfo(filter_id); - return info ? info->lporder : 0; + auto info = session->cpp_session->getFilterInfo(filter_id); + return info.isOk() ? info.value().lporder : 0; } catch (...) { return 0; } } diff --git a/src/cbsdk/src/sdk_session.cpp b/src/cbsdk/src/sdk_session.cpp index 2e48e3ff..917d8605 100644 --- a/src/cbsdk/src/sdk_session.cpp +++ b/src/cbsdk/src/sdk_session.cpp @@ -288,15 +288,12 @@ struct SdkSession::Impl { void rebuildChannelTypeCache() { for (uint32_t ch = 0; ch < cbMAXCHANS; ++ch) { - const auto* ci = getChanInfoPtr(ch); - channel_type_cache[ch] = ci ? classifyChannelByCaps(*ci) : ChannelType::ANY; + auto ci = getChanInfo(ch + 1); + channel_type_cache[ch] = ci.isOk() ? classifyChannelByCaps(ci.value()) : ChannelType::ANY; } channel_cache_valid = true; } - /// Get chaninfo pointer for a 0-based channel index (works for both STANDALONE and CLIENT) - const cbPKT_CHANINFO* getChanInfoPtr(uint32_t idx) const; - // Clock sync periodic probing std::chrono::steady_clock::time_point last_clock_probe_time{}; @@ -369,6 +366,19 @@ struct SdkSession::Impl { // (e.g., during the handshake phase in start()). std::atomic shutting_down{false}; + Result getChanInfo(const uint32_t chan_id) const { + // Prefer shmem over device_config because CMP position overlays are + // written to shmem (device_config is owned by the receive thread and + // we avoid writing to it from other threads). + if (shmem_session && chan_id >= 1 && chan_id <= cbMAXCHANS) { + return shmem_session->getChanInfo(chan_id); + } + // Fallback to device_config (no shmem available) + if (device_session) + return Result::ok(*device_session->getChanInfo(chan_id)); + return Result::error("Channel information not available"); + } + /// Apply CMP overlay (position + label) to all existing chaninfo entries. /// Called after loading a CMP file. Writes the updated chaninfo to shmem. /// Label push to the device is done separately by SdkSession::loadChannelMap. @@ -386,7 +396,7 @@ struct SdkSession::Impl { const auto* p = device_session->getChanInfo(chan_id); if (p && p->chan > 0) { ci = *p; valid = true; } } else if (shmem_session) { - auto r = shmem_session->getChanInfo(chan_id - 1); + auto r = shmem_session->getChanInfo(chan_id); if (r.isOk() && r.value().chan > 0) { ci = r.value(); valid = true; } } if (!valid) continue; @@ -712,7 +722,7 @@ Result SdkSession::create(const SdkConfig& config) { auto shmem_result = cbshm::ShmemSession::create( central_cfg, central_rec, central_xmt, central_xmt_local, central_status, central_spk, central_signal, - cbshm::Mode::CLIENT, cbshm::ShmemLayout::CENTRAL_COMPAT); + cbshm::Mode::CLIENT, cbshm::ShmemLayout::CENTRAL); if (shmem_result.isOk()) { // Set instrument filter for CENTRAL_COMPAT mode (Central's receive buffer @@ -1391,57 +1401,39 @@ const SdkConfig& SdkSession::getConfig() const { return m_impl->config; } -const cbPKT_SYSINFO* SdkSession::getSysInfo() const { +Result SdkSession::getSysInfo() const { if (m_impl->device_session) - return &m_impl->device_session->getSysInfo(); - if (m_impl->shmem_session) { - const auto* native = m_impl->shmem_session->getNativeConfigBuffer(); - if (native) - return &native->sysinfo; - const auto* legacy = m_impl->shmem_session->getLegacyConfigBuffer(); - if (legacy) - return &legacy->sysinfo; - } - return nullptr; + return Result::ok(m_impl->device_session->getSysInfo()); + if (m_impl->shmem_session) + return m_impl->shmem_session->getSysInfo(); + return Result::error("System information not available"); } -const cbPKT_CHANINFO* SdkSession::getChanInfo(const uint32_t chan_id) const { +Result SdkSession::getChanInfo(const uint32_t chan_id) const { // Prefer shmem over device_config because CMP position overlays are // written to shmem (device_config is owned by the receive thread and // we avoid writing to it from other threads). if (m_impl->shmem_session && chan_id >= 1 && chan_id <= cbMAXCHANS) { - const auto* native = m_impl->shmem_session->getNativeConfigBuffer(); - if (native) - return &native->chaninfo[chan_id - 1]; - const auto* legacy = m_impl->shmem_session->getLegacyConfigBuffer(); - if (legacy) - return &legacy->chaninfo[chan_id - 1]; + return m_impl->shmem_session->getChanInfo(chan_id - 1); } // Fallback to device_config (no shmem available) if (m_impl->device_session) - return m_impl->device_session->getChanInfo(chan_id); - return nullptr; + return Result::ok(*m_impl->device_session->getChanInfo(chan_id - 1)); + return Result::error("Channel information not available"); } -const cbPKT_GROUPINFO* SdkSession::getGroupInfo(uint32_t group_id) const { +Result SdkSession::getGroupInfo(uint32_t group_id) const { if (group_id == 0 || group_id > cbMAXGROUPS) - return nullptr; + return Result::error("Invalid group ID"); if (m_impl->device_session) { const auto& config = m_impl->device_session->getDeviceConfig(); - return &config.groupinfo[group_id - 1]; + return Result::ok(config.groupinfo[group_id - 1]); } if (m_impl->shmem_session) { - const auto* native = m_impl->shmem_session->getNativeConfigBuffer(); - if (native) - return &native->groupinfo[group_id - 1]; - const auto* legacy = m_impl->shmem_session->getLegacyConfigBuffer(); - if (legacy) { - int32_t inst = getCentralInstrumentIndex(m_impl->config.device_type); - if (inst >= 0) - return &legacy->groupinfo[inst][group_id - 1]; - } + auto inst = cbproto::InstrumentId::fromIndex(getCentralInstrumentIndex(m_impl->config.device_type)); + return m_impl->shmem_session->getGroupInfo(inst, group_id); } - return nullptr; + return Result::error("Group information not available"); } uint32_t SdkSession::getGroupChannelList(uint32_t group_id, uint16_t* list, uint32_t max_count) const { @@ -1455,19 +1447,22 @@ uint32_t SdkSession::getGroupChannelList(uint32_t group_id, uint16_t* list, uint // Prefer device_config (updated in updateConfigFromBuffer before the // sendAndWait / SYSREP sync barrier fires). shmem chaninfo may lag // slightly because SDK callbacks run after the sync notification. - const cbPKT_CHANINFO* ci = nullptr; - if (m_impl->device_session) - ci = m_impl->device_session->getChanInfo(chan); - else - ci = getChanInfo(chan); - - if (!ci) continue; + const cbPKT_CHANINFO& ci{}; + if (m_impl->device_session) { + const auto* res = m_impl->device_session->getChanInfo(chan - 1); + if (!res) continue; + const auto& ci = *res; + } else { + auto res = getChanInfo(chan); + if (res.isError()) continue; + const auto& ci = res.value(); + } bool in_group; if (is_raw) - in_group = (ci->ainpopts & cbAINP_RAWSTREAM) != 0; + in_group = (ci.ainpopts & cbAINP_RAWSTREAM) != 0; else - in_group = (ci->smpgroup == group_id); + in_group = (ci.smpgroup == group_id); if (in_group) list[count++] = static_cast(chan); @@ -1475,25 +1470,18 @@ uint32_t SdkSession::getGroupChannelList(uint32_t group_id, uint16_t* list, uint return count; } -const cbPKT_FILTINFO* SdkSession::getFilterInfo(const uint32_t filter_id) const { +Result SdkSession::getFilterInfo(const uint32_t filter_id) const { if (filter_id >= cbMAXFILTS) - return nullptr; + return Result::error("Invalid filter ID"); if (m_impl->device_session) { const auto& config = m_impl->device_session->getDeviceConfig(); - return &config.filtinfo[filter_id]; + return Result::ok(config.filtinfo[filter_id]); } if (m_impl->shmem_session) { - const auto* native = m_impl->shmem_session->getNativeConfigBuffer(); - if (native) - return &native->filtinfo[filter_id]; - const auto* legacy = m_impl->shmem_session->getLegacyConfigBuffer(); - if (legacy) { - int32_t inst = getCentralInstrumentIndex(m_impl->config.device_type); - if (inst >= 0) - return &legacy->filtinfo[inst][filter_id]; - } + auto inst = cbproto::InstrumentId::fromIndex(getCentralInstrumentIndex(m_impl->config.device_type)); + return m_impl->shmem_session->getFilterInfo(inst, filter_id); } - return nullptr; + return Result::error("Filter information not available"); } uint32_t SdkSession::getRunLevel() const { @@ -1502,7 +1490,8 @@ uint32_t SdkSession::getRunLevel() const { // Fall back to the SYSINFO mirrored into shmem by the STANDALONE owner. // In CLIENT mode the device only emits SYSREP on runlevel-set commands, // so this session's receive ring may never see one in steady state. - if (const auto* si = getSysInfo()) return si->runlevel; + auto si = getSysInfo(); + if (si.isOk()) return si.value().runlevel; return 0; } @@ -1517,12 +1506,8 @@ uint32_t SdkSession::getProtocolVersion() const { const auto* native = m_impl->shmem_session->getNativeConfigBuffer(); if (native) return CBPROTO_PROTOCOL_CURRENT; // NATIVE layout always uses current protocol - const auto* legacy = m_impl->shmem_session->getLegacyConfigBuffer(); - if (legacy) { - int32_t inst = getCentralInstrumentIndex(m_impl->config.device_type); - if (inst >= 0) - return legacy->procinfo[inst].version; - } + else + return m_impl->shmem_session->getCompatProtocolVersion(); } return 0; } @@ -1535,35 +1520,38 @@ std::string SdkSession::getProcIdent() const { } if (m_impl->shmem_session) { const auto* native = m_impl->shmem_session->getNativeConfigBuffer(); - if (native) + if (native) { return std::string(native->procinfo.ident, strnlen(native->procinfo.ident, sizeof(native->procinfo.ident))); - const auto* legacy = m_impl->shmem_session->getLegacyConfigBuffer(); - if (legacy) { - int32_t inst = getCentralInstrumentIndex(m_impl->config.device_type); - if (inst >= 0) - return std::string(legacy->procinfo[inst].ident, - strnlen(legacy->procinfo[inst].ident, sizeof(legacy->procinfo[inst].ident))); + } else { + int32_t inst_idx = getCentralInstrumentIndex(m_impl->config.device_type); + auto inst = cbproto::InstrumentId::fromIndex(inst_idx); + // TODO: Check if inst >= 0? + auto procinfo = m_impl->shmem_session->getProcInfo(inst); + if (procinfo.isError()) { + return {}; + } + return std::string(procinfo.value().ident, strnlen(procinfo.value().ident, sizeof(procinfo.value().ident))); } } return {}; } uint32_t SdkSession::getSpikeLength() const { - const auto* si = getSysInfo(); - return si ? si->spikelen : 0; + auto si = getSysInfo(); + return si.isOk() ? si.value().spikelen : 0; } uint32_t SdkSession::getSpikePretrigger() const { - const auto* si = getSysInfo(); - return si ? si->spikepre : 0; + auto si = getSysInfo(); + return si.isOk() ? si.value().spikepre : 0; } Result SdkSession::setSpikeLength(uint32_t spikelen, uint32_t spikepre) { - const auto* si = getSysInfo(); - if (!si) - return Result::error("System info not available"); - cbPKT_SYSINFO pkt = *si; + auto si = getSysInfo(); + if (si.isError()) + return Result::error(si.error()); + cbPKT_SYSINFO pkt = si.value(); pkt.cbpkt_header.type = cbPKTTYPE_SYSSETSPKLEN; pkt.spikelen = spikelen; pkt.spikepre = spikepre; @@ -1608,29 +1596,13 @@ static int64_t extractChanInfoField(const cbPKT_CHANINFO& ci, ChanInfoField fiel } } -/// Helper: get chaninfo pointer for a 0-based channel index -const cbPKT_CHANINFO* SdkSession::Impl::getChanInfoPtr(uint32_t idx) const { - // Prefer shmem: CMP position overlays are written there. - // device_config is owned by the receive thread and doesn't have positions. - if (shmem_session) { - const auto* native = shmem_session->getNativeConfigBuffer(); - if (native) return &native->chaninfo[idx]; - const auto* legacy = shmem_session->getLegacyConfigBuffer(); - if (legacy) return &legacy->chaninfo[idx]; - } - if (device_session) { - return device_session->getChanInfo(idx + 1); - } - return nullptr; -} - Result SdkSession::getChannelField(uint32_t chanId, ChanInfoField field) const { if (chanId == 0 || chanId > cbMAXCHANS) return Result::error("Invalid channel ID"); - const auto* ci = m_impl->getChanInfoPtr(chanId - 1); - if (!ci) + auto ci = getChanInfo(chanId); + if (ci.isError()) return Result::error("Channel info unavailable"); - return Result::ok(extractChanInfoField(*ci, field)); + return Result::ok(extractChanInfoField(ci.value(), field)); } Result> SdkSession::getMatchingChannelIds( @@ -1638,9 +1610,9 @@ Result> SdkSession::getMatchingChannelIds( std::vector ids; size_t count = 0; for (uint32_t ch = 0; ch < cbMAXCHANS && count < nChans; ++ch) { - const auto* ci = m_impl->getChanInfoPtr(ch); - if (!ci) continue; - if (classifyChannelByCaps(*ci) != chanType) continue; + auto ci = getChanInfo(ch + 1); + if (ci.isError()) continue; + if (classifyChannelByCaps(ci.value()) != chanType) continue; ids.push_back(ch + 1); count++; } @@ -1652,10 +1624,10 @@ Result> SdkSession::getChannelField( std::vector values; size_t count = 0; for (uint32_t ch = 0; ch < cbMAXCHANS && count < nChans; ++ch) { - const auto* ci = m_impl->getChanInfoPtr(ch); - if (!ci) continue; - if (classifyChannelByCaps(*ci) != chanType) continue; - values.push_back(extractChanInfoField(*ci, field)); + auto ci = getChanInfo(ch + 1); + if (ci.isError()) continue; + if (classifyChannelByCaps(ci.value()) != chanType) continue; + values.push_back(extractChanInfoField(ci.value(), field)); count++; } return Result>::ok(std::move(values)); @@ -1666,10 +1638,10 @@ Result> SdkSession::getChannelLabels( std::vector labels; size_t count = 0; for (uint32_t ch = 0; ch < cbMAXCHANS && count < nChans; ++ch) { - const auto* ci = m_impl->getChanInfoPtr(ch); - if (!ci) continue; - if (classifyChannelByCaps(*ci) != chanType) continue; - labels.emplace_back(ci->label); + auto ci = getChanInfo(ch + 1); + if (ci.isError()) continue; + if (classifyChannelByCaps(ci.value()) != chanType) continue; + labels.emplace_back(ci.value().label); count++; } return Result>::ok(std::move(labels)); @@ -1680,13 +1652,13 @@ Result> SdkSession::getChannelPositions( std::vector positions; size_t count = 0; for (uint32_t ch = 0; ch < cbMAXCHANS && count < nChans; ++ch) { - const auto* ci = m_impl->getChanInfoPtr(ch); - if (!ci) continue; - if (classifyChannelByCaps(*ci) != chanType) continue; - positions.push_back(ci->position[0]); - positions.push_back(ci->position[1]); - positions.push_back(ci->position[2]); - positions.push_back(ci->position[3]); + auto ci = getChanInfo(ch + 1); + if (ci.isError()) continue; + if (classifyChannelByCaps(ci.value()) != chanType) continue; + positions.push_back(ci.value().position[0]); + positions.push_back(ci.value().position[1]); + positions.push_back(ci.value().position[2]); + positions.push_back(ci.value().position[3]); count++; } return Result>::ok(std::move(positions)); @@ -1723,8 +1695,8 @@ static std::vector resolveTargetChans( result.reserve(std::min(nChans, cbMAXCHANS)); } for (uint32_t chan = 1; chan <= cbMAXCHANS && result.size() < nChans; ++chan) { - const cbPKT_CHANINFO* ci = session.getChanInfo(chan); - if (ci && classifyChannelByCaps(*ci) == chanType) { + auto ci = session.getChanInfo(chan); + if (ci.isOk() && classifyChannelByCaps(ci.value()) == chanType) { result.push_back(chan); } } @@ -1746,9 +1718,9 @@ Result SdkSession::setSampleGroup( // Always sends the full chaninfo (seeded from local cache), so a stale // CHANREP can't leave us stuck against a concurrent change. auto build_packet = [this](uint32_t chan, uint32_t grp) -> std::optional { - const cbPKT_CHANINFO* base = getChanInfo(chan); - if (!base || base->chan == 0) return std::nullopt; - cbPKT_CHANINFO chaninfo = *base; + auto base = getChanInfo(chan); + if (base.isError() || base.value().chan == 0) return std::nullopt; + cbPKT_CHANINFO& chaninfo = base.value(); chaninfo.chan = chan; if (grp > 0 && grp < 6) { chaninfo.cbpkt_header.type = cbPKTTYPE_CHANSETSMP; @@ -1783,8 +1755,8 @@ Result SdkSession::setSampleGroup( std::set target_set(targets.begin(), targets.end()); for (uint32_t chan = 1; chan <= cbMAXCHANS; ++chan) { if (target_set.count(chan)) continue; - const cbPKT_CHANINFO* ci = getChanInfo(chan); - if (!ci || classifyChannelByCaps(*ci) != chanType) continue; + auto ci = getChanInfo(chan); + if (ci.isError() || classifyChannelByCaps(ci.value()) != chanType) continue; if (auto pkt = build_packet(chan, 0u); pkt) { packets.push_back(reinterpret_cast(*pkt)); } @@ -1829,9 +1801,9 @@ static Result applyBulkSetter( std::vector packets; packets.reserve(targets.size()); for (uint32_t chan : targets) { - const cbPKT_CHANINFO* base = session.getChanInfo(chan); - if (!base || base->chan == 0) continue; - cbPKT_CHANINFO chaninfo = *base; + auto base = session.getChanInfo(chan); + if (base.isError() || base.value().chan == 0) continue; + cbPKT_CHANINFO& chaninfo = base.value(); chaninfo.chan = chan; mutate(chaninfo); packets.push_back(reinterpret_cast(chaninfo)); @@ -1998,12 +1970,12 @@ Result SdkSession::setAnalogOutputMonitor(uint32_t aout_chan_id, uint32_t if (aout_chan_id < 1 || aout_chan_id > cbMAXCHANS) return Result::error("Invalid analog output channel ID"); - const cbPKT_CHANINFO* info = getChanInfo(aout_chan_id); - if (!info) + auto info = getChanInfo(aout_chan_id); + if (info.isError()) return Result::error("Channel info not available for channel " + std::to_string(aout_chan_id)); // Copy current config and modify analog output fields - cbPKT_CHANINFO chaninfo = *info; + cbPKT_CHANINFO& chaninfo = info.value(); // Set monitor channel chaninfo.monchan = static_cast(monitor_chan_id); @@ -2123,9 +2095,9 @@ Result SdkSession::loadChannelMap( // device, so no analogous push for position. if (m_impl->device_session || m_impl->shmem_session) { for (const auto& [chan_id, label] : labels_to_push) { - const cbPKT_CHANINFO* info = getChanInfo(chan_id); - if (!info) continue; - cbPKT_CHANINFO ci = *info; + auto info = getChanInfo(chan_id); + if (info.isError()) continue; + cbPKT_CHANINFO& ci = info.value(); ci.chan = chan_id; ci.cbpkt_header.type = cbPKTTYPE_CHANSETLABEL; std::strncpy(ci.label, label.c_str(), sizeof(ci.label) - 1); @@ -2170,9 +2142,9 @@ Result SdkSession::clearChannelMap() { // local-only. if (m_impl->device_session || m_impl->shmem_session) { for (uint32_t chan_id : mapped_chans) { - const cbPKT_CHANINFO* info = getChanInfo(chan_id); - if (!info) continue; - cbPKT_CHANINFO ci = *info; + auto info = getChanInfo(chan_id); + if (info.isError()) continue; + cbPKT_CHANINFO& ci = info.value(); ci.chan = chan_id; ci.cbpkt_header.type = cbPKTTYPE_CHANSETLABEL; char default_label[16]; From 1ab99a0af30f88b6b0ca05f090ac2a127e816734 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Wed, 10 Jun 2026 17:05:03 -0600 Subject: [PATCH 18/62] Change ShmemSession to use the Central adapter Removed the CENTRAL_COMPAT layout and replaced it with CENTRAL. Spike buffer and cache operations with the CENTRAL layout are only performed for the most recent version of Central. In the future, most of the ShmemSession implementation should be moved into the Central adapter. --- src/cbshm/include/cbshm/shmem_session.h | 49 +- src/cbshm/src/shmem_session.cpp | 740 ++++++++---------------- 2 files changed, 255 insertions(+), 534 deletions(-) diff --git a/src/cbshm/include/cbshm/shmem_session.h b/src/cbshm/include/cbshm/shmem_session.h index 2d2fd4e6..51c6638d 100644 --- a/src/cbshm/include/cbshm/shmem_session.h +++ b/src/cbshm/include/cbshm/shmem_session.h @@ -20,8 +20,8 @@ #define CBSHM_SHMEM_SESSION_H // Include Central-compatible types which bring in protocol definitions +#include #include -#include #include #include #include @@ -47,8 +47,7 @@ enum class Mode { /// Controls buffer sizes, struct types, and bounds checking. /// enum class ShmemLayout { - CENTRAL, ///< CereLink's own Central-compatible layout (cbConfigBuffer) - CENTRAL_COMPAT, ///< Central's actual binary layout (CentralLegacyCFGBUFF) + CENTRAL, ///< Central's actual binary layout (CentralLegacyCFGBUFF) NATIVE ///< Native single-instrument layout (NativeConfigBuffer) }; @@ -159,6 +158,17 @@ class ShmemSession { /// @param channel Channel number (0-based, global across all instruments) /// @return cbPKT_CHANINFO structure on success Result getChanInfo(uint32_t channel) const; + + /// @brief Get system information + /// @return cbPKT_SYSINFO structure on success + Result getSysInfo() const; + + /// @brief Get sample group information + /// @param id Instrument ID (1-based) + /// @param group Group number (0-based, 0 to cbMAXGROUPS-1) + /// @param info cbPKT_GROUPINFO structure to write + /// @return Result indicating success or failure + Result getGroupInfo(cbproto::InstrumentId id, uint32_t group) const; /// @} @@ -210,19 +220,6 @@ class ShmemSession { /// @name Configuration Buffer Direct Access /// @{ - /// @brief Get direct pointer to Central configuration buffer - /// - /// Provides direct access to the shared memory config buffer for zero-copy - /// operations. Used by SdkSession to connect DeviceSession's config buffer - /// to shared memory. - /// - /// @return Pointer to configuration buffer, or nullptr if not CENTRAL layout - cbConfigBuffer* getConfigBuffer(); - - /// @brief Get direct pointer to Central configuration buffer (const version) - /// @return Const pointer to configuration buffer, or nullptr if not CENTRAL layout - const cbConfigBuffer* getConfigBuffer() const; - /// @brief Get direct pointer to native configuration buffer /// @return Pointer to native configuration buffer, or nullptr if not NATIVE layout NativeConfigBuffer* getNativeConfigBuffer(); @@ -231,16 +228,10 @@ class ShmemSession { /// @return Const pointer to native configuration buffer, or nullptr if not NATIVE layout const NativeConfigBuffer* getNativeConfigBuffer() const; - // TODO: REMOVE getLegacyConfigBuffer due to fundamental incompatibility with multi-version-central-compat - - // /// @brief Get direct pointer to Central legacy configuration buffer - // /// @return Pointer to legacy config buffer, or nullptr if not CENTRAL_COMPAT layout - // CentralLegacyCFGBUFF* getLegacyConfigBuffer(); - // - // /// @brief Get direct pointer to Central legacy configuration buffer (const version) - // /// @deprecated since multi-version-central-compat merged with master. - // /// @return Const pointer to legacy config buffer, or nullptr if not CENTRAL_COMPAT layout - // const CentralLegacyCFGBUFF* getLegacyConfigBuffer() const; + /// @brief Get a translated copy of Central's configuration buffer + /// @param id Instrument ID (1-based) + /// @return Result::value containing the configuration buffer, or Result::error if not CENTRAL layout + Result getLegacyConfigBuffer(cbproto::InstrumentId id); /// @} @@ -366,13 +357,13 @@ class ShmemSession { /// @brief Get NSP status for specified instrument /// @param id Instrument ID (1-based) /// @return NSP status (INIT, NOIPADDR, NOREPLY, FOUND, INVALID) - Result getNspStatus(cbproto::InstrumentId id) const; + Result getNspStatus(cbproto::InstrumentId id) const; /// @brief Set NSP status for specified instrument /// @param id Instrument ID (1-based) /// @param status NSP status to set /// @return Result indicating success or failure - Result setNspStatus(cbproto::InstrumentId id, central::NSPStatus status); + Result setNspStatus(cbproto::InstrumentId id, NativeNSPStatus status); /// @brief Check if system is configured as Gemini /// @return true if Gemini system, false otherwise @@ -398,7 +389,7 @@ class ShmemSession { /// @param channel Channel number (0-based) /// @param cache Output parameter to receive spike cache /// @return Result indicating success or failure - Result getSpikeCache(uint32_t channel, central::CentralSpikeCache& cache) const; + Result getSpikeCache(uint32_t channel, NativeSpikeCache& cache) const; /// @brief Get most recent spike packet from cache /// diff --git a/src/cbshm/src/shmem_session.cpp b/src/cbshm/src/shmem_session.cpp index fba792ee..baa24176 100644 --- a/src/cbshm/src/shmem_session.cpp +++ b/src/cbshm/src/shmem_session.cpp @@ -101,6 +101,7 @@ inline uint32_t shm_load_relaxed_u32(const uint32_t* p) { struct ShmemSession::Impl { Mode mode; ShmemLayout layout; + std::unique_ptr bootstrap_adapter; std::unique_ptr adapter; std::string cfg_name; // Config buffer name (e.g., "cbCFGbuffer") std::string rec_name; // Receive buffer name (e.g., "cbRECbuffer") @@ -159,144 +160,14 @@ struct ShmemSession::Impl { // Detected protocol version for CENTRAL_COMPAT mode cbproto_protocol_version_t compat_protocol; - // Typed accessors for config buffer - CentralConfigBuffer* centralCfg() { return static_cast(cfg_buffer_raw); } - const CentralConfigBuffer* centralCfg() const { return static_cast(cfg_buffer_raw); } - NativeConfigBuffer* nativeCfg() { return static_cast(cfg_buffer_raw); } - const NativeConfigBuffer* nativeCfg() const { return static_cast(cfg_buffer_raw); } - // CentralLegacyCFGBUFF* legacyCfg() { return static_cast(cfg_buffer_raw); } - // const CentralLegacyCFGBUFF* legacyCfg() const { return static_cast(cfg_buffer_raw); } - - // // Read-only config accessor for CENTRAL_COMPAT mode - // CentralConfigBuffer legacyCfg() const { - // switch (compat_protocol) { - // default: - // /* fallthrough */ - // case CBPROTO_PROTOCOL_CURRENT: { - // auto buf = static_cast(cfg_buffer_raw); - // - // CentralConfigBuffer cfg; - // - // cfg.version = buf->version; - // cfg.sysflags = buf->sysflags; - // // skip optiontable - // // skip colortable - // - // cfg.sysinfo = fromLegacyPktSysinfo(&buf->sysinfo); - // - // for (size_t i = 0; i < std::size(buf->procinfo); ++i) { // TODO: Handle cfg < buf - // cfg.procinfo[i] = fromLegacyPktProcinfo(&buf->procinfo[i]); - // } // TODO: Handle cfg > buf - // - // for (size_t i = 0; i < std::size(buf->bankinfo); ++i) { // TODO: Handle cfg != buf - // for (size_t j = 0; j < std::size(buf->bankinfo[i]); ++j) { - // - // cfg.bankinfo[i][j] = fromLegacyPktBankInfo(&buf->bankinfo[i][j]); - // } - // } - // - // for (size_t i = 0; i < std::size(buf->groupinfo); ++i) { // TODO: Handle cfg != buf - // for (size_t j = 0; j < std::size(buf->bankinfo[i]); ++j) { - // cfg.groupinfo[i][j] = fromLegacyPktGroupInfo(&buf->groupinfo[i][j]); - // } - // } - // - // for (size_t i = 0; i < std::size(buf->filtinfo); ++i) { // TODO: Handle cfg != buf - // for (size_t j = 0; j < std::size(buf->filtinfo[i]); ++j) { - // cfg.filtinfo[i][j] = fromLegacyPktFiltInfo(&buf->filtinfo[i][j]); - // } - // } - // - // for (size_t n = 0; n < std::size(buf->adaptinfo); ++n) { // TODO: Handle cfg < buf - // cfg.adaptinfo[n] = fromLegacyPktAdaptFiltInfo(&buf->adaptinfo[n]); - // } // TODO: Handle cfg > buf - // - // for (size_t n = 0; n < std::size(buf->refelecinfo); ++n) { // TODO: Handle cfg < buf - // cfg.refelecinfo[n] = fromLegacyPktRefElecInfo(&buf->refelecinfo[n]); - // } // TODO: Handle cfg > buf - // - // for (size_t i = 0; i < std::size(buf->chaninfo); ++i) { // TODO: Handle cfg < buf - // const auto& buf_chaninfo = buf->chaninfo[i]; - // auto& cfg_chaninfo = cfg.chaninfo[i]; - // } // TODO: Handle cfg > buf - // for (size_t n = 0; n < std::size(buf->isSortingOptions.asBasis); ++n) { // TODO: Handle cfg < buf - // const auto& buf_isSortingOptions_asBasis = buf->isSortingOptions.asBasis[n]; - // auto& cfg_isSortingOptions_asBasis = cfg.isSortingOptions.asBasis[n]; - // cfg_isSortingOptions_asBasis.cbpkt_header = fromLegacyPktHeader(&buf_isSortingOptions_asBasis.cbpkt_header); - // cfg_isSortingOptions_asBasis.chan = buf_isSortingOptions_asBasis.chan; - // cfg_isSortingOptions_asBasis.mode = buf_isSortingOptions_asBasis.mode; - // cfg_isSortingOptions_asBasis.fs = buf_isSortingOptions_asBasis.fs; - // for (size_t y = 0; y < std::size(buf_isSortingOptions_asBasis.basis); ++y) { // TODO: Handle cfg < buf - // for (size_t x = 0; x < std::size(buf_isSortingOptions_asBasis.basis[y]); ++x) { // TODO: Handle cfg < buf - // cfg_isSortingOptions_asBasis.basis[y][x] = buf_isSortingOptions_asBasis.basis[y][x]; - // } // TODO: Handle cfg > buf - // } // TODO: Handle cfg > buf - // } // TODO: Handle cfg > buf - // for (size_t i = 0; i < std::size(buf->isSortingOptions.asSortModel); ++i) { // TODO: Handle cfg != buf - // for (size_t j = 0; j < std::size(buf->isSortingOptions.asSortModel[i]); ++j) { - // const auto& buf_isSortingOptions_asSortModel = buf->isSortingOptions.asSortModel[i][j]; - // auto& cfg_isSortingOptions_asSortModel = cfg.isSortingOptions.asSortModel[i][j]; - // cfg_isSortingOptions_asSortModel.cbpkt_header = fromLegacyPktHeader(&buf_isSortingOptions_asSortModel.cbpkt_header); - // cfg_isSortingOptions_asSortModel.chan = buf_isSortingOptions_asSortModel.chan; - // cfg_isSortingOptions_asSortModel.unit_number = buf_isSortingOptions_asSortModel.unit_number; - // } - // } - // cfg.isSortingOptions.pktDetect - // cfg.isSortingOptions.pktArtifReject - // cfg.isSortingOptions.pktNoiseBoundary - // cfg.isSortingOptions.pktStatistics - // cfg.isSortingOptions.pktStatus - // break; - // } - // case CBPROTO_PROTOCOL_410: { - // // TODO: - // break; - // } - // case CBPROTO_PROTOCOL_400: { - // // TODO: - // break; - // } - // case CBPROTO_PROTOCOL_311: { - // // TODO: - // break; - // } - // } - // } - - // Generic receive buffer header access (header fields are at identical offsets in both layouts) - uint32_t& recReceived() { - return *static_cast(rec_buffer_raw); - } - PROCTIME& recLasttime() { - // lasttime is at offset sizeof(uint32_t) in both CentralReceiveBuffer and NativeReceiveBuffer - return *reinterpret_cast(static_cast(rec_buffer_raw) + sizeof(uint32_t)); - } - uint32_t& recHeadwrap() { - return *reinterpret_cast(static_cast(rec_buffer_raw) + sizeof(uint32_t) + sizeof(PROCTIME)); - } - uint32_t& recHeadindex() { - return *reinterpret_cast(static_cast(rec_buffer_raw) + sizeof(uint32_t) + sizeof(PROCTIME) + sizeof(uint32_t)); - } - uint32_t* recBuffer() { - return reinterpret_cast(static_cast(rec_buffer_raw) + sizeof(uint32_t) + sizeof(PROCTIME) + sizeof(uint32_t) + sizeof(uint32_t)); - } - - // Transmit buffer accessors (header fields are identical between Central and Native) - struct XmtHeader { - uint32_t transmitted; - uint32_t headindex; - uint32_t tailindex; - uint32_t last_valid_index; - uint32_t bufferlen; - }; - XmtHeader* xmtGlobal() { return static_cast(xmt_buffer_raw); } - uint32_t* xmtGlobalBuffer() { return reinterpret_cast(static_cast(xmt_buffer_raw) + sizeof(XmtHeader)); } - XmtHeader* xmtLocal() { return static_cast(xmt_local_buffer_raw); } - uint32_t* xmtLocalBuffer() { return reinterpret_cast(static_cast(xmt_local_buffer_raw) + sizeof(XmtHeader)); } + // Typed accessor for config buffer + NativeConfigBuffer* nativeCfg() { + return static_cast(cfg_buffer_raw); + } Impl() : mode(Mode::STANDALONE) - , layout(ShmemLayout::CENTRAL) + , layout(ShmemLayout::NATIVE) , adapter(nullptr) , is_open(false) #ifdef _WIN32 @@ -469,8 +340,8 @@ struct ShmemSession::Impl { return Result::error("Session already open"); } - if (mode == Mode::CLIENT && layout == ShmemLayout::CENTRAL_COMPAT) { - // Detect protocol version for CLIENT + CENTRAL_COMPAT mode + if (mode == Mode::CLIENT && layout == ShmemLayout::CENTRAL) { + // Detect protocol version for CLIENT + CENTRAL mode auto compat_result = detectCompatProtocol(); if (compat_result.isError()) { return Result::error("Failed to get Central's protocol version: " + compat_result.error()); @@ -482,7 +353,25 @@ struct ShmemSession::Impl { compat_protocol = CBPROTO_PROTOCOL_CURRENT; } - // Compute buffer sizes based on layout + // Select the bootstrap adapter for fetching pointers to Central's shared memory. + switch (compat_protocol) { + default: + /* fallthrough */ + case CBPROTO_PROTOCOL_CURRENT: + bootstrap_adapter = std::make_unique(); + break; + case CBPROTO_PROTOCOL_410: + bootstrap_adapter = std::make_unique(); + break; + case CBPROTO_PROTOCOL_400: + bootstrap_adapter = std::make_unique(); + break; + case CBPROTO_PROTOCOL_311: + bootstrap_adapter = std::make_unique(); + break; + } + + // Compute buffer sizes based on layout and protocol version if (layout == ShmemLayout::NATIVE) { cfg_buffer_size = sizeof(NativeConfigBuffer); rec_buffer_size = sizeof(NativeReceiveBuffer); @@ -491,56 +380,15 @@ struct ShmemSession::Impl { status_buffer_size = sizeof(NativePCStatus); spike_buffer_size = sizeof(NativeSpikeBuffer); rec_buffer_len = NATIVE_cbRECBUFFLEN; - } else if (layout == ShmemLayout::CENTRAL_COMPAT) { - switch (compat_protocol) { - default: - /* fallthrough */ - case CBPROTO_PROTOCOL_CURRENT: - cfg_buffer_size = sizeof(central::CentralLegacyCFGBUFF); - rec_buffer_size = sizeof(central::CentralReceiveBuffer); - xmt_buffer_size = sizeof(central::CentralTransmitBuffer); - xmt_local_buffer_size = sizeof(central::CentralTransmitBufferLocal); - status_buffer_size = sizeof(central::CentralPCStatus); - spike_buffer_size = sizeof(central::CentralSpikeBuffer); - rec_buffer_len = central::cbRECBUFFLEN; - break; - case CBPROTO_PROTOCOL_410: - cfg_buffer_size = sizeof(central_v4_1::CentralLegacyCFGBUFF); - rec_buffer_size = sizeof(central_v4_1::CentralReceiveBuffer); - xmt_buffer_size = sizeof(central_v4_1::CentralTransmitBuffer); - xmt_local_buffer_size = sizeof(central_v4_1::CentralTransmitBufferLocal); - status_buffer_size = sizeof(central_v4_1::CentralPCStatus); - spike_buffer_size = sizeof(central_v4_1::CentralSpikeBuffer); - rec_buffer_len = central_v4_1::cbRECBUFFLEN; - break; - case CBPROTO_PROTOCOL_400: - cfg_buffer_size = sizeof(central_v4_0::CentralLegacyCFGBUFF); - rec_buffer_size = sizeof(central_v4_0::CentralReceiveBuffer); - xmt_buffer_size = sizeof(central_v4_0::CentralTransmitBuffer); - xmt_local_buffer_size = sizeof(central_v4_0::CentralTransmitBufferLocal); - status_buffer_size = sizeof(central_v4_0::CentralPCStatus); - spike_buffer_size = sizeof(central_v4_0::CentralSpikeBuffer); - rec_buffer_len = central_v4_0::cbRECBUFFLEN; - break; - case CBPROTO_PROTOCOL_311: - cfg_buffer_size = sizeof(central_v3_11::CentralLegacyCFGBUFF); - rec_buffer_size = sizeof(central_v3_11::CentralReceiveBuffer); - xmt_buffer_size = sizeof(central_v3_11::CentralTransmitBuffer); - xmt_local_buffer_size = sizeof(central_v3_11::CentralTransmitBufferLocal); - status_buffer_size = sizeof(central_v3_11::CentralPCStatus); - spike_buffer_size = sizeof(central_v3_11::CentralSpikeBuffer); - rec_buffer_len = central_v3_11::cbRECBUFFLEN; - break; - } } else { - // TODO: Remove CENTRAL mode and only keep NATIVE and CENTRAL_COMPAT (?) - cfg_buffer_size = sizeof(CentralConfigBuffer); - rec_buffer_size = sizeof(central::CentralReceiveBuffer); - xmt_buffer_size = sizeof(central::CentralTransmitBuffer); - xmt_local_buffer_size = sizeof(central::CentralTransmitBufferLocal); - status_buffer_size = sizeof(central::CentralPCStatus); - spike_buffer_size = sizeof(central::CentralSpikeBuffer); - rec_buffer_len = central::cbRECBUFFLEN; + // These adapter methods work regardless of the state of the internal pointer + cfg_buffer_size = bootstrap_adapter->getConfigBufferSize(); + rec_buffer_size = bootstrap_adapter->getReceiveBufferSize(); + xmt_buffer_size = bootstrap_adapter->getTransmitBufferSize(); + xmt_local_buffer_size = bootstrap_adapter->getTransmitBufferLocalSize(); + status_buffer_size = bootstrap_adapter->getStatusBufferSize(); + spike_buffer_size = bootstrap_adapter->getSpikeBufferSize(); + rec_buffer_len = bootstrap_adapter->getReceiveBufferLen(); } #ifdef _WIN32 @@ -665,218 +513,91 @@ struct ShmemSession::Impl { return Result::error("Failed to create/open signal semaphore: " + std::string(strerror(errno))); } #endif - - // Initialize buffers in standalone mode - if (mode == Mode::STANDALONE) { - initBuffers(); - } - - is_open = true; - - // In CLIENT mode, sync our read position to the current head so we only - // read NEW packets, not stale data that was already in the ring buffer. - // Use acquire load on head_index to pair with the producer's release - // store (see writeToReceiveBuffer). - if (mode == Mode::CLIENT) { - rec_tailindex = shm_load_acquire_u32(&recHeadindex()); - rec_tailwrap = shm_load_relaxed_u32(&recHeadwrap()); - } - - // Select the adapter for compatiibility with Central's shared memory. - // This adapter is used in Mode::CENTRAL and Mode::CENTRAL_COMPAT. + + // Select the adapter for compatibility with Central's shared memory. switch (compat_protocol) { default: /* fallthrough */ case CBPROTO_PROTOCOL_CURRENT: - adapter = std::make_unique(cfg_buffer_raw); + adapter = std::make_unique(cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); break; case CBPROTO_PROTOCOL_410: - adapter = std::make_unique(cfg_buffer_raw); + adapter = std::make_unique(cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); break; case CBPROTO_PROTOCOL_400: - adapter = std::make_unique(cfg_buffer_raw); + adapter = std::make_unique(cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); break; case CBPROTO_PROTOCOL_311: - adapter = std::make_unique(cfg_buffer_raw); + adapter = std::make_unique(cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); break; } - return Result::ok(); - } - - /// @brief Initialize buffers for STANDALONE mode - void initBuffers() { - // TODO: modes CENTRAL and CENTRAL_COMPAT should never instantiate their own buffers - if (layout == ShmemLayout::NATIVE) { - initNativeBuffers(); - } else if (layout == ShmemLayout::CENTRAL_COMPAT) { - // // TODO: REMOVE - // initLegacyBuffers(); - } else { - // // TODO: REMOVE - // initCentralBuffers(); - } - } - - // void initCentralBuffers() { - // auto* cfg = centralCfg(); - // std::memset(cfg, 0, cfg_buffer_size); - // cfg->version = cbVERSION_MAJOR * 100 + cbVERSION_MINOR; - // for (int i = 0; i < central::cbMAXPROCS; ++i) { - // cfg->instrument_status[i] = static_cast(InstrumentStatus::INACTIVE); - // } - // - // // Initialize receive buffer - // std::memset(rec_buffer_raw, 0, rec_buffer_size); - // - // // Initialize transmit buffers - // auto* xmt = static_cast(xmt_buffer_raw); - // std::memset(xmt, 0, xmt_buffer_size); - // xmt->last_valid_index = central::cbXMT_GLOBAL_BUFFLEN - 1; - // xmt->bufferlen = central::cbXMT_GLOBAL_BUFFLEN; - // - // auto* xmt_local = static_cast(xmt_local_buffer_raw); - // std::memset(xmt_local, 0, xmt_local_buffer_size); - // xmt_local->last_valid_index = central::cbXMT_LOCAL_BUFFLEN - 1; - // xmt_local->bufferlen = central::cbXMT_LOCAL_BUFFLEN; - // - // // Initialize status buffer - // auto* status = static_cast(status_buffer_raw); - // std::memset(status, 0, status_buffer_size); - // status->m_nNumFEChans = central::cbNUM_FE_CHANS; - // status->m_nNumAnainChans = central::cbNUM_ANAIN_CHANS; - // status->m_nNumAnalogChans = central::cbNUM_ANALOG_CHANS; - // status->m_nNumAoutChans = central::cbNUM_ANAOUT_CHANS; - // status->m_nNumAudioChans = central::cbNUM_AUDOUT_CHANS; - // status->m_nNumAnalogoutChans = central::cbNUM_ANALOGOUT_CHANS; - // status->m_nNumDiginChans = central::cbNUM_DIGIN_CHANS; - // status->m_nNumSerialChans = central::cbNUM_SERIAL_CHANS; - // status->m_nNumDigoutChans = central::cbNUM_DIGOUT_CHANS; - // status->m_nNumTotalChans = central::cbMAXCHANS; - // for (int i = 0; i < central::cbMAXPROCS; ++i) { - // status->m_nNspStatus[i] = central::NSPStatus::NSP_INIT; - // } - // - // // Initialize spike cache buffer - // auto* spike = static_cast(spike_buffer_raw); - // std::memset(spike, 0, spike_buffer_size); - // spike->chidmax = central::cbNUM_ANALOG_CHANS; - // spike->linesize = sizeof(central::CentralSpikeCache); - // for (uint32_t ch = 0; ch < central::cbPKT_SPKCACHELINECNT; ++ch) { - // spike->cache[ch].chid = ch; - // spike->cache[ch].pktcnt = central::cbPKT_SPKCACHEPKTCNT; - // spike->cache[ch].pktsize = sizeof(central::cbPKT_SPK); - // } - // } - - // void initLegacyBuffers() { - // // TODO: FIX - // auto* cfg = legacyCfg(); - // std::memset(cfg, 0, cfg_buffer_size); - // cfg->version = cbVERSION_MAJOR * 100 + cbVERSION_MINOR; - // - // // Set procinfo version so detectCompatProtocol() identifies current format. - // // In STANDALONE mode, CereLink owns the memory and writes current-format packets. - // // MAKELONG(minor, major) = (major << 16) | minor - // for (int i = 0; i < CENTRAL_cbMAXPROCS; ++i) { - // cfg->procinfo[i].version = (cbVERSION_MAJOR << 16) | cbVERSION_MINOR; - // } - // - // // Initialize receive buffer - // std::memset(rec_buffer_raw, 0, rec_buffer_size); - // - // // Initialize transmit buffers (same struct as Central) - // auto* xmt = static_cast(xmt_buffer_raw); - // std::memset(xmt, 0, xmt_buffer_size); - // xmt->last_valid_index = CENTRAL_cbXMT_GLOBAL_BUFFLEN - 1; - // xmt->bufferlen = CENTRAL_cbXMT_GLOBAL_BUFFLEN; - // - // auto* xmt_local = static_cast(xmt_local_buffer_raw); - // std::memset(xmt_local, 0, xmt_local_buffer_size); - // xmt_local->last_valid_index = CENTRAL_cbXMT_LOCAL_BUFFLEN - 1; - // xmt_local->bufferlen = CENTRAL_cbXMT_LOCAL_BUFFLEN; - // - // // Initialize status buffer (same struct as Central) - // auto* status = static_cast(status_buffer_raw); - // std::memset(status, 0, status_buffer_size); - // status->m_nNumFEChans = CENTRAL_cbNUM_FE_CHANS; - // status->m_nNumAnainChans = CENTRAL_cbNUM_ANAIN_CHANS; - // status->m_nNumAnalogChans = CENTRAL_cbNUM_ANALOG_CHANS; - // status->m_nNumAoutChans = CENTRAL_cbNUM_ANAOUT_CHANS; - // status->m_nNumAudioChans = CENTRAL_cbNUM_AUDOUT_CHANS; - // status->m_nNumAnalogoutChans = CENTRAL_cbNUM_ANALOGOUT_CHANS; - // status->m_nNumDiginChans = CENTRAL_cbNUM_DIGIN_CHANS; - // status->m_nNumSerialChans = CENTRAL_cbNUM_SERIAL_CHANS; - // status->m_nNumDigoutChans = CENTRAL_cbNUM_DIGOUT_CHANS; - // status->m_nNumTotalChans = CENTRAL_cbMAXCHANS; - // for (int i = 0; i < CENTRAL_cbMAXPROCS; ++i) { - // status->m_nNspStatus[i] = NSPStatus::NSP_INIT; - // } - // - // // Initialize spike cache buffer (same struct as Central) - // auto* spike = static_cast(spike_buffer_raw); - // std::memset(spike, 0, spike_buffer_size); - // spike->chidmax = CENTRAL_cbNUM_ANALOG_CHANS; - // spike->linesize = sizeof(CentralSpikeCache); - // for (uint32_t ch = 0; ch < CENTRAL_cbPKT_SPKCACHELINECNT; ++ch) { - // spike->cache[ch].chid = ch; - // spike->cache[ch].pktcnt = CENTRAL_cbPKT_SPKCACHEPKTCNT; - // spike->cache[ch].pktsize = sizeof(cbPKT_SPK); - // } - // } - - void initNativeBuffers() { - auto* cfg = nativeCfg(); - std::memset(cfg, 0, cfg_buffer_size); - cfg->version = cbVERSION_MAJOR * 100 + cbVERSION_MINOR; - cfg->instrument_status = static_cast(InstrumentStatus::INACTIVE); + // Initialize buffers in standalone mode + if (mode == Mode::STANDALONE && layout == ShmemLayout::NATIVE) { + auto* cfg = nativeCfg(); + std::memset(cfg, 0, cfg_buffer_size); + cfg->version = cbVERSION_MAJOR * 100 + cbVERSION_MINOR; + cfg->instrument_status = static_cast(InstrumentStatus::INACTIVE); #ifdef _WIN32 - cfg->owner_pid = GetCurrentProcessId(); + cfg->owner_pid = GetCurrentProcessId(); #else - cfg->owner_pid = static_cast(getpid()); + cfg->owner_pid = static_cast(getpid()); #endif - // Initialize receive buffer - std::memset(rec_buffer_raw, 0, rec_buffer_size); - - // Initialize transmit buffers - auto* xmt = static_cast(xmt_buffer_raw); - std::memset(xmt, 0, xmt_buffer_size); - xmt->last_valid_index = NATIVE_cbXMT_GLOBAL_BUFFLEN - 1; - xmt->bufferlen = NATIVE_cbXMT_GLOBAL_BUFFLEN; - - auto* xmt_local = static_cast(xmt_local_buffer_raw); - std::memset(xmt_local, 0, xmt_local_buffer_size); - xmt_local->last_valid_index = NATIVE_cbXMT_LOCAL_BUFFLEN - 1; - xmt_local->bufferlen = NATIVE_cbXMT_LOCAL_BUFFLEN; - - // Initialize status buffer - auto* status = static_cast(status_buffer_raw); - std::memset(status, 0, status_buffer_size); - status->m_nNumFEChans = NATIVE_NUM_FE_CHANS; - status->m_nNumAnainChans = cbNUM_ANAIN_CHANS; - status->m_nNumAnalogChans = NATIVE_NUM_ANALOG_CHANS; - status->m_nNumAoutChans = cbNUM_ANAOUT_CHANS; - status->m_nNumAudioChans = cbNUM_AUDOUT_CHANS; - status->m_nNumAnalogoutChans = cbNUM_ANALOGOUT_CHANS; - status->m_nNumDiginChans = cbNUM_DIGIN_CHANS; - status->m_nNumSerialChans = cbNUM_SERIAL_CHANS; - status->m_nNumDigoutChans = cbNUM_DIGOUT_CHANS; - status->m_nNumTotalChans = NATIVE_MAXCHANS; - status->m_nNspStatus = central::NSPStatus::NSP_INIT; - - // Initialize spike cache buffer - auto* spike = static_cast(spike_buffer_raw); - std::memset(spike, 0, spike_buffer_size); - spike->chidmax = NATIVE_NUM_ANALOG_CHANS; - spike->linesize = sizeof(NativeSpikeCache); - for (uint32_t ch = 0; ch < NATIVE_cbPKT_SPKCACHELINECNT; ++ch) { - spike->cache[ch].chid = ch; - spike->cache[ch].pktcnt = NATIVE_cbPKT_SPKCACHEPKTCNT; - spike->cache[ch].pktsize = sizeof(cbPKT_SPK); + // Initialize receive buffer + std::memset(rec_buffer_raw, 0, rec_buffer_size); + + // Initialize transmit buffers + auto* xmt = static_cast(xmt_buffer_raw); + std::memset(xmt, 0, xmt_buffer_size); + xmt->last_valid_index = NATIVE_cbXMT_GLOBAL_BUFFLEN - 1; + xmt->bufferlen = NATIVE_cbXMT_GLOBAL_BUFFLEN; + + auto* xmt_local = static_cast(xmt_local_buffer_raw); + std::memset(xmt_local, 0, xmt_local_buffer_size); + xmt_local->last_valid_index = NATIVE_cbXMT_LOCAL_BUFFLEN - 1; + xmt_local->bufferlen = NATIVE_cbXMT_LOCAL_BUFFLEN; + + // Initialize status buffer + auto* status = static_cast(status_buffer_raw); + std::memset(status, 0, status_buffer_size); + status->m_nNumFEChans = NATIVE_NUM_FE_CHANS; + status->m_nNumAnainChans = cbNUM_ANAIN_CHANS; + status->m_nNumAnalogChans = NATIVE_NUM_ANALOG_CHANS; + status->m_nNumAoutChans = cbNUM_ANAOUT_CHANS; + status->m_nNumAudioChans = cbNUM_AUDOUT_CHANS; + status->m_nNumAnalogoutChans = cbNUM_ANALOGOUT_CHANS; + status->m_nNumDiginChans = cbNUM_DIGIN_CHANS; + status->m_nNumSerialChans = cbNUM_SERIAL_CHANS; + status->m_nNumDigoutChans = cbNUM_DIGOUT_CHANS; + status->m_nNumTotalChans = NATIVE_MAXCHANS; + status->m_nNspStatus = NativeNSPStatus::NSP_INIT; + + // Initialize spike cache buffer + auto* spike = static_cast(spike_buffer_raw); + std::memset(spike, 0, spike_buffer_size); + spike->chidmax = NATIVE_NUM_ANALOG_CHANS; + spike->linesize = sizeof(NativeSpikeCache); + for (uint32_t ch = 0; ch < NATIVE_cbPKT_SPKCACHELINECNT; ++ch) { + spike->cache[ch].chid = ch; + spike->cache[ch].pktcnt = NATIVE_cbPKT_SPKCACHEPKTCNT; + spike->cache[ch].pktsize = sizeof(cbPKT_SPK); + } } - } + is_open = true; + + // In CLIENT mode, sync our read position to the current head so we only + // read NEW packets, not stale data that was already in the ring buffer. + // Use acquire load on head_index to pair with the producer's release + // store (see writeToReceiveBuffer). + if (mode == Mode::CLIENT) { + rec_tailindex = shm_load_acquire_u32(&adapter->getRecHeadindexPtr()); + rec_tailwrap = shm_load_relaxed_u32(&adapter->getRecHeadwrapPtr()); + } + + return Result::ok(); + } /////////////////////////////////////////////////////////////////////////////////////////////////// // Packet Routing (THE KEY FIX!) @@ -909,8 +630,8 @@ struct ShmemSession::Impl { return Result::error("Packet too large for receive buffwither"); } - uint32_t head = recHeadindex(); - uint32_t* buf = recBuffer(); + uint32_t head = adapter->getRecHeadindexPtr(); + uint32_t* buf = adapter->getRecBufferPtr(); // Decide whether to wrap. Wrap if either (a) the packet would not // fit, or (b) writing it would leave a 1..3 dword tail gap that we @@ -940,19 +661,19 @@ struct ShmemSession::Impl { std::memcpy(&buf[head], &marker, sizeof(cbPKT_HEADER)); } head = 0; - shm_store_relaxed_u32(&recHeadwrap(), recHeadwrap() + 1); + shm_store_relaxed_u32(&adapter->getRecHeadwrapPtr(), adapter->getRecHeadwrapPtr() + 1); } const uint32_t* pkt_data = reinterpret_cast(&pkt); std::memcpy(&buf[head], pkt_data, pkt_size_words * sizeof(uint32_t)); - recReceived()++; - recLasttime() = pkt.cbpkt_header.time; + adapter->getRecReceived()++; + adapter->setRecLasttime(pkt.cbpkt_header.time); // Release fence: head_index store synchronizes-with the consumer's // acquire load, ensuring all prior writes (marker, memcpy, wrap, // lasttime) are visible before the consumer sees the new head_index. - shm_store_release_u32(&recHeadindex(), head + pkt_size_words); + shm_store_release_u32(&adapter->getRecHeadindexPtr(), head + pkt_size_words); return Result::ok(); } @@ -1181,13 +902,10 @@ Result ShmemSession::isInstrumentActive(cbproto::InstrumentId id) const { } bool active = (m_impl->nativeCfg()->instrument_status == static_cast(InstrumentStatus::ACTIVE)); return Result::ok(active); - } else if (m_impl->layout == ShmemLayout::CENTRAL_COMPAT) { + } else { // CentralLegacyCFGBUFF has no instrument_status field; // if the shared memory exists, instruments are as Central configured them return Result::ok(true); - } else { - bool active = (m_impl->centralCfg()->instrument_status[idx] == static_cast(InstrumentStatus::ACTIVE)); - return Result::ok(active); } } @@ -1207,10 +925,8 @@ Result ShmemSession::setInstrumentActive(cbproto::InstrumentId id, bool ac return Result::error("Native mode: single instrument only (index 0)"); } m_impl->nativeCfg()->instrument_status = val; - } else if (m_impl->layout == ShmemLayout::CENTRAL_COMPAT) { - return Result::error("CENTRAL_COMPAT mode: instrument status is read-only (no instrument_status field in Central's layout)"); } else { - m_impl->centralCfg()->instrument_status[idx] = val; + return Result::error("CENTRAL_COMPAT mode: instrument status is read-only (no instrument_status field in Central's layout)"); } return Result::ok(); @@ -1225,15 +941,9 @@ Result ShmemSession::getFirstActiveInstrument() const { if (m_impl->nativeCfg()->instrument_status == static_cast(InstrumentStatus::ACTIVE)) { return Result::ok(cbproto::InstrumentId::fromIndex(0)); } - } else if (m_impl->layout == ShmemLayout::CENTRAL_COMPAT) { + } else { // No instrument_status in legacy layout; return first instrument (always "active") return Result::ok(cbproto::InstrumentId::fromIndex(0)); - } else { - for (uint8_t i = 0; i < central::cbMAXPROCS; ++i) { - if (m_impl->centralCfg()->instrument_status[i] == static_cast(InstrumentStatus::ACTIVE)) { - return Result::ok(cbproto::InstrumentId::fromIndex(i)); - } - } } return Result::error("No active instruments"); @@ -1323,6 +1033,42 @@ Result ShmemSession::getChanInfo(uint32_t channel) const { } } +Result ShmemSession::getSysInfo() const { + if (!isOpen()) { + return Result::error("Session not open"); + } + + if (m_impl->layout == ShmemLayout::NATIVE) { + return Result::ok(m_impl->nativeCfg()->sysinfo); + } else { + return m_impl->adapter->getSysInfo(); + } +} + +Result ShmemSession::getGroupInfo(cbproto::InstrumentId id, uint32_t group) const { + if (!isOpen()) { + return Result::error("Session not open"); + } + if (!id.isValid()) { + return Result::error("Invalid instrument ID"); + } + + uint8_t idx = id.toIndex(); + + if (m_impl->layout == ShmemLayout::NATIVE) { + if (idx != 0) { + return Result::error("Native mode: single instrument only"); + } + if (group >= NATIVE_MAXGROUPS) { + return Result::error("Group index out of range"); + } + return Result::ok(m_impl->nativeCfg()->groupinfo[group]); + } else { + return m_impl->adapter->getGroupInfo(idx, group); + } +} + + /////////////////////////////////////////////////////////////////////////////////////////////////// // Configuration Write Operations @@ -1442,30 +1188,16 @@ Result ShmemSession::setGroupInfo(cbproto::InstrumentId id, uint32_t group return Result::error("Group index out of range"); } m_impl->nativeCfg()->groupinfo[group] = info; + return Result::ok(); } else { return m_impl->adapter->setGroupInfo(idx, group, info); } - return Result::ok(); } /////////////////////////////////////////////////////////////////////////////////////////////////// // Configuration Buffer Direct Access -cbConfigBuffer* ShmemSession::getConfigBuffer() { - if (!isOpen() || m_impl->layout != ShmemLayout::CENTRAL) { - return nullptr; - } - return m_impl->centralCfg(); -} - -const cbConfigBuffer* ShmemSession::getConfigBuffer() const { - if (!isOpen() || m_impl->layout != ShmemLayout::CENTRAL) { - return nullptr; - } - return m_impl->centralCfg(); -} - NativeConfigBuffer* ShmemSession::getNativeConfigBuffer() { if (!isOpen() || m_impl->layout != ShmemLayout::NATIVE) { return nullptr; @@ -1480,22 +1212,13 @@ const NativeConfigBuffer* ShmemSession::getNativeConfigBuffer() const { return m_impl->nativeCfg(); } -// TODO: REMOVE getLegacyConfigBuffer due to fundamental incompatibility with multi-version-central-compat - -// CentralLegacyCFGBUFF* ShmemSession::getLegacyConfigBuffer() { -// if (!isOpen() || m_impl->layout != ShmemLayout::CENTRAL_COMPAT) { -// return nullptr; -// } -// return m_impl->legacyCfg(); -// } -// -// const CentralLegacyCFGBUFF* ShmemSession::getLegacyConfigBuffer() const { -// if (!isOpen() || m_impl->layout != ShmemLayout::CENTRAL_COMPAT) { -// return nullptr; -// } -// return m_impl->legacyCfg(); -// } - +Result ShmemSession::getLegacyConfigBuffer(cbproto::InstrumentId id) { + if (!isOpen() || m_impl->layout != ShmemLayout::CENTRAL) { + return Result::error("Not open or invalid layout"); + } + uint8_t idx = id.toIndex(); + return m_impl->adapter->getConfigBuffer(idx); +} Result ShmemSession::storePacket(const cbPKT_GENERIC& pkt) { if (!isOpen()) { @@ -1544,7 +1267,7 @@ Result ShmemSession::enqueuePacket(const cbPKT_GENERIC& pkt) { } // In CENTRAL_COMPAT mode with an older protocol, translate to the legacy format - const bool needs_translation = (m_impl->layout == ShmemLayout::CENTRAL_COMPAT && + const bool needs_translation = (m_impl->layout == ShmemLayout::CENTRAL && m_impl->compat_protocol != CBPROTO_PROTOCOL_CURRENT); const uint8_t* write_data; @@ -1572,7 +1295,7 @@ Result ShmemSession::enqueuePacket(const cbPKT_GENERIC& pkt) { // Central's xmt consumer expects device-native format. auto gemini = isGeminiSystem(); if (gemini.isOk() && !gemini.value() && dest_hdr.time != 0) { - uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check + uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check the return value if (sysfreq == 0) sysfreq = 30000; uint64_t g = std::gcd(uint64_t(1000000000), uint64_t(sysfreq)); dest_hdr.time = dest_hdr.time * (sysfreq / g) / (1000000000 / g); @@ -1595,7 +1318,7 @@ Result ShmemSession::enqueuePacket(const cbPKT_GENERIC& pkt) { // Non-Gemini: convert nanosecond timestamp back to device clock ticks. auto gemini = isGeminiSystem(); if (gemini.isOk() && !gemini.value() && dest_hdr.time != 0) { - uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check + uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check the return value if (sysfreq == 0) sysfreq = 30000; uint64_t g = std::gcd(uint64_t(1000000000), uint64_t(sysfreq)); dest_hdr.time = dest_hdr.time * (sysfreq / g) / (1000000000 / g); @@ -1603,14 +1326,14 @@ Result ShmemSession::enqueuePacket(const cbPKT_GENERIC& pkt) { write_size_bytes = cbPKT_HEADER_SIZE + dest_dlen * 4; } write_data = translated_buf; - } else if (m_impl->layout == ShmemLayout::CENTRAL_COMPAT && m_impl->status_buffer_raw) { + } else if (m_impl->layout == ShmemLayout::CENTRAL && m_impl->status_buffer_raw) { // Protocol is CURRENT but device may be non-Gemini — still need ns→ticks conversion. auto gemini = isGeminiSystem(); if (gemini.isOk() && !gemini.value() && pkt.cbpkt_header.time != 0) { std::memcpy(translated_buf, &pkt, (cbPKT_HEADER_32SIZE + pkt.cbpkt_header.dlen) * sizeof(uint32_t)); auto& dest_hdr = *reinterpret_cast(translated_buf); - uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check + uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check the return value if (sysfreq == 0) sysfreq = 30000; uint64_t g = std::gcd(uint64_t(1000000000), uint64_t(sysfreq)); dest_hdr.time = dest_hdr.time * (sysfreq / g) / (1000000000 / g); @@ -1627,12 +1350,10 @@ Result ShmemSession::enqueuePacket(const cbPKT_GENERIC& pkt) { // Round up to dword-aligned size for ring buffer uint32_t pkt_size_words = (write_size_bytes + 3) / 4; - auto* xmt = m_impl->xmtGlobal(); - uint32_t* buf = m_impl->xmtGlobalBuffer(); - - uint32_t head = xmt->headindex; - uint32_t tail = xmt->tailindex; - uint32_t last_valid = xmt->last_valid_index; + uint32_t head = m_impl->adapter->getXmtHeadindexPtr(); + uint32_t tail = m_impl->adapter->getXmtTailindexPtr(); + uint32_t last_valid = m_impl->adapter->getXmtLastValidIndexPtr(); + uint32_t* buf = m_impl->adapter->getXmtBufferPtr(); // Linear buffer with wrap-to-zero (matches Central's cbSendPacket): // Packets are always written CONTIGUOUSLY. If the next packet doesn't fit @@ -1665,7 +1386,7 @@ Result ShmemSession::enqueuePacket(const cbPKT_GENERIC& pkt) { const uint32_t* pkt_words = reinterpret_cast(write_data); uint32_t time_word = pkt_words[0]; if (time_word == 0) { - PROCTIME t = m_impl->recLasttime(); + PROCTIME t = m_impl->adapter->getRecLasttime(); time_word = (t != 0) ? static_cast(t) : 1; } @@ -1673,7 +1394,7 @@ Result ShmemSession::enqueuePacket(const cbPKT_GENERIC& pkt) { std::memcpy(&buf[head + 1], &pkt_words[1], (pkt_size_words - 1) * sizeof(uint32_t)); // Advance head index - xmt->headindex = new_head; + m_impl->adapter->getXmtHeadindexPtr() = new_head; // Pass 2: atomically write the time field to mark packet as ready #ifdef _WIN32 @@ -1693,11 +1414,9 @@ Result ShmemSession::dequeuePacket(cbPKT_GENERIC& pkt) { return Result::error("Transmit buffer not initialized"); } - auto* xmt = m_impl->xmtGlobal(); - uint32_t* buf = m_impl->xmtGlobalBuffer(); - - uint32_t head = xmt->headindex; - uint32_t tail = xmt->tailindex; + uint32_t head = m_impl->adapter->getXmtHeadindexPtr(); + uint32_t tail = m_impl->adapter->getXmtTailindexPtr(); + uint32_t* buf = m_impl->adapter->getXmtBufferPtr(); if (head == tail) { return Result::ok(false); // Queue is empty @@ -1730,8 +1449,8 @@ Result ShmemSession::dequeuePacket(cbPKT_GENERIC& pkt) { // Clear the time field to 0 so it's clean for next use buf[tail] = 0; - xmt->tailindex = tail + pkt_size_words; - xmt->transmitted++; + m_impl->adapter->getXmtTailindexPtr() = tail + pkt_size_words; + m_impl->adapter->getXmtTransmittedPtr()++; return Result::ok(true); } @@ -1740,8 +1459,7 @@ bool ShmemSession::hasTransmitPackets() const { if (!m_impl || !m_impl->is_open || !m_impl->xmt_buffer_raw) { return false; } - auto* xmt = m_impl->xmtGlobal(); - return xmt->headindex != xmt->tailindex; + return m_impl->adapter->getXmtHeadindexPtr() != m_impl->adapter->getXmtTailindexPtr(); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1756,14 +1474,12 @@ Result ShmemSession::enqueueLocalPacket(const cbPKT_GENERIC& pkt) { return Result::error("Local transmit buffer not initialized"); } - auto* xmt_local = m_impl->xmtLocal(); - uint32_t* buf = m_impl->xmtLocalBuffer(); - uint32_t pkt_size_words = cbPKT_HEADER_32SIZE + pkt.cbpkt_header.dlen; - uint32_t head = xmt_local->headindex; - uint32_t tail = xmt_local->tailindex; - uint32_t last_valid = xmt_local->last_valid_index; + uint32_t head = m_impl->adapter->getLocalXmtHeadindexPtr(); + uint32_t tail = m_impl->adapter->getLocalXmtTailindexPtr(); + uint32_t last_valid = m_impl->adapter->getLocalXmtLastValidIndexPtr(); + uint32_t* buf = m_impl->adapter->getLocalXmtBufferPtr(); // Linear buffer with wrap-to-zero (matches Central's cbSendLoopbackPacket) uint32_t new_head = head + pkt_size_words; @@ -1784,12 +1500,12 @@ Result ShmemSession::enqueueLocalPacket(const cbPKT_GENERIC& pkt) { const uint32_t* pkt_data = reinterpret_cast(&pkt); uint32_t time_word = pkt_data[0]; if (time_word == 0) { - PROCTIME t = m_impl->recLasttime(); + PROCTIME t = m_impl->adapter->getRecLasttime(); time_word = (t != 0) ? static_cast(t) : 1; } std::memcpy(&buf[head + 1], &pkt_data[1], (pkt_size_words - 1) * sizeof(uint32_t)); - xmt_local->headindex = new_head; + m_impl->adapter->getLocalXmtHeadindexPtr() = new_head; #ifdef _WIN32 InterlockedExchange(reinterpret_cast(&buf[head]), @@ -1808,11 +1524,9 @@ Result ShmemSession::dequeueLocalPacket(cbPKT_GENERIC& pkt) { return Result::error("Local transmit buffer not initialized"); } - auto* xmt_local = m_impl->xmtLocal(); - uint32_t* buf = m_impl->xmtLocalBuffer(); - - uint32_t head = xmt_local->headindex; - uint32_t tail = xmt_local->tailindex; + uint32_t head = m_impl->adapter->getLocalXmtHeadindexPtr(); + uint32_t tail = m_impl->adapter->getLocalXmtTailindexPtr(); + uint32_t* buf = m_impl->adapter->getLocalXmtBufferPtr(); if (head == tail) { return Result::ok(false); // Queue is empty @@ -1845,8 +1559,8 @@ Result ShmemSession::dequeueLocalPacket(cbPKT_GENERIC& pkt) { // Clear the time field to 0 so it's clean for next use buf[tail] = 0; - xmt_local->tailindex = tail + pkt_size_words; - xmt_local->transmitted++; + m_impl->adapter->getLocalXmtTailindexPtr() = tail + pkt_size_words; + m_impl->adapter->getLocalXmtTransmittedPtr()++; return Result::ok(true); } @@ -1855,8 +1569,7 @@ bool ShmemSession::hasLocalTransmitPackets() const { if (!m_impl || !m_impl->is_open || !m_impl->xmt_local_buffer_raw) { return false; } - auto* xmt_local = m_impl->xmtLocal(); - return xmt_local->headindex != xmt_local->tailindex; + return m_impl->adapter->getLocalXmtHeadindexPtr() != m_impl->adapter->getLocalXmtTailindexPtr(); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1873,37 +1586,42 @@ Result ShmemSession::getNumTotalChans() const { if (m_impl->layout == ShmemLayout::NATIVE) { return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nNumTotalChans); } else { - // TODO: Use adapter instead - // CENTRAL and CENTRAL_COMPAT share the same CentralPCStatus struct - return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nNumTotalChans); + auto status = m_impl->adapter->getPcStatus(0); // instrument idx doesn't matter for m_nNumTotalChans (brittle) + if (status.isError()) { + return Result::error("Unable to fetch PC status"); + } + return Result::ok(status.value().m_nNumTotalChans); } } -Result ShmemSession::getNspStatus(cbproto::InstrumentId id) const { +Result ShmemSession::getNspStatus(cbproto::InstrumentId id) const { if (!m_impl || !m_impl->is_open) { - return Result::error("Session is not open"); + return Result::error("Session is not open"); } if (!m_impl->status_buffer_raw) { - return Result::error("Status buffer not initialized"); + return Result::error("Status buffer not initialized"); } uint32_t index = id.toIndex(); if (m_impl->layout == ShmemLayout::NATIVE) { if (index != 0) { - return Result::error("Native mode: single instrument only"); + return Result::error("Native mode: single instrument only"); } - return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nNspStatus); + return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nNspStatus); } else { - // TODO: Use adapter instead if (index >= central::cbMAXPROCS) { - return Result::error("Invalid instrument ID"); + return Result::error("Invalid instrument ID"); } - return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nNspStatus[index]); + auto status = m_impl->adapter->getPcStatus(index); + if (status.isError()) { + return Result::error("Unable to fetch PC status"); + } + return Result::ok(status.value().m_nNspStatus); } } -Result ShmemSession::setNspStatus(cbproto::InstrumentId id, central::NSPStatus status) { +Result ShmemSession::setNspStatus(cbproto::InstrumentId id, NativeNSPStatus status) { if (!m_impl || !m_impl->is_open) { return Result::error("Session is not open"); } @@ -1919,12 +1637,15 @@ Result ShmemSession::setNspStatus(cbproto::InstrumentId id, central::NSPSt } static_cast(m_impl->status_buffer_raw)->m_nNspStatus = status; } else { - // TODO: Use adapter instead if (index >= central::cbMAXPROCS) { return Result::error("Invalid instrument ID"); } - static_cast(m_impl->status_buffer_raw)->m_nNspStatus[index] = status; - return Result::error("Not Implemented"); + auto pc_status = m_impl->adapter->getPcStatus(index); + if (pc_status.isError()) { + return Result::error("Unable to fetch PC status"); + } + pc_status.value().m_nNspStatus = status; + return m_impl->adapter->setPcStatus(index, pc_status.value()); } return Result::ok(); @@ -1941,8 +1662,11 @@ Result ShmemSession::isGeminiSystem() const { if (m_impl->layout == ShmemLayout::NATIVE) { return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nGeminiSystem != 0); } else { - // TODO: Use adapter instead - return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nGeminiSystem != 0); + auto status = m_impl->adapter->getPcStatus(0); // instrument idx doesn't matter for m_nGeminiSystem (brittle) + if (status.isError()) { + return Result::error("Unable to fetch PC status"); + } + return Result::ok(status.value().m_nGeminiSystem); } } @@ -1957,8 +1681,12 @@ Result ShmemSession::setGeminiSystem(bool is_gemini) { if (m_impl->layout == ShmemLayout::NATIVE) { static_cast(m_impl->status_buffer_raw)->m_nGeminiSystem = is_gemini ? 1 : 0; } else { - // TODO: Use adapter instead - static_cast(m_impl->status_buffer_raw)->m_nGeminiSystem = is_gemini ? 1 : 0; + auto status = m_impl->adapter->getPcStatus(0); // instrument idx doesn't matter for m_nGeminiSystem (brittle) + if (status.isError()) { + return Result::error("Unable to fetch PC status"); + } + status.value().m_nGeminiSystem = is_gemini ? 1 : 0; + return m_impl->adapter->setPcStatus(0, status.value()); // instrument idx doesn't matter for m_nGeminiSystem (brittle) } return Result::ok(); @@ -1967,7 +1695,7 @@ Result ShmemSession::setGeminiSystem(bool is_gemini) { /////////////////////////////////////////////////////////////////////////////////////////////////// // Spike Cache Buffer Access -Result ShmemSession::getSpikeCache(uint32_t channel, central::CentralSpikeCache& cache) const { +Result ShmemSession::getSpikeCache(uint32_t channel, NativeSpikeCache& cache) const { if (!m_impl || !m_impl->is_open) { return Result::error("Session is not open"); } @@ -1993,8 +1721,9 @@ Result ShmemSession::getSpikeCache(uint32_t channel, central::CentralSpike if (channel >= central::cbPKT_SPKCACHELINECNT) { return Result::error("Invalid channel number"); } - auto* spike = static_cast(m_impl->spike_buffer_raw); - cache = spike->cache[channel]; + auto* spike = static_cast(m_impl->spike_buffer_raw); + // // TODO: Implement fromLegacy for cbSPKCACHE + // cache = fromLegacy(spike->cache[channel]); } return Result::ok(); @@ -2025,14 +1754,14 @@ Result ShmemSession::getRecentSpike(uint32_t channel, cbPKT_SPK& spike) co if (channel >= central::cbPKT_SPKCACHELINECNT) { return Result::error("Invalid channel number"); } - auto* buf = static_cast(m_impl->spike_buffer_raw); + auto* buf = static_cast(m_impl->spike_buffer_raw); const auto& cache = buf->cache[channel]; if (cache.valid == 0) { return Result::ok(false); } uint32_t recent_idx = (cache.head == 0) ? (cache.pktcnt - 1) : (cache.head - 1); // TODO: Use adapter instead - // TODO: Implement + // TODO: Implement fromLegacy // spike = central::fromLegacy(cache.spkpkt[recent_idx]); return Result::ok(true); } @@ -2155,14 +1884,14 @@ PROCTIME ShmemSession::getLastTime() const { if (!m_impl || !m_impl->is_open || !m_impl->rec_buffer_raw) { return 0; } - PROCTIME t = m_impl->recLasttime(); + PROCTIME t = m_impl->adapter->getRecLasttime(); // In CENTRAL_COMPAT mode, Central writes lasttime using the device's native // timestamp unit. Non-Gemini devices use clock ticks; convert to nanoseconds // for consistency with readReceiveBuffer() which translates packet timestamps. - if (t != 0 && m_impl->layout == ShmemLayout::CENTRAL_COMPAT) { + if (t != 0 && m_impl->layout == ShmemLayout::CENTRAL) { auto gemini = isGeminiSystem(); if (gemini.isOk() && !gemini.value()) { - uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check + uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check return value if (sysfreq == 0) sysfreq = 30000; uint64_t g = std::gcd(uint64_t(1000000000), uint64_t(sysfreq)); t = t * (1000000000 / g) / (sysfreq / g); @@ -2201,21 +1930,22 @@ Result ShmemSession::readReceiveBuffer(cbPKT_GENERIC* packets, size_t max_ } packets_read = 0; - uint32_t* buf = m_impl->recBuffer(); + uint32_t* buf = m_impl->adapter->getRecBufferPtr(); uint32_t buflen = m_impl->rec_buffer_len; // Acquire-load: pairs with the producer's release-store of head_index in // writeToReceiveBuffer. Without this, on weak memory architectures // (ARM/Apple Silicon) we can observe an advanced head_index but stale or // partial packet bytes, leading to misaligned reads of the ring buffer. - uint32_t head_index = shm_load_acquire_u32(&m_impl->recHeadindex()); - uint32_t head_wrap = shm_load_relaxed_u32(&m_impl->recHeadwrap()); + uint32_t head_index = shm_load_acquire_u32(&m_impl->adapter->getRecHeadindexPtr()); + uint32_t head_wrap = shm_load_relaxed_u32(&m_impl->adapter->getRecHeadwrapPtr()); if (m_impl->rec_tailwrap == head_wrap && m_impl->rec_tailindex == head_index) { return Result::ok(); } - const bool needs_translation = (m_impl->layout == ShmemLayout::CENTRAL_COMPAT && + // TODO: Use the Central adapter instead + const bool needs_translation = (m_impl->layout == ShmemLayout::CENTRAL && m_impl->compat_protocol != CBPROTO_PROTOCOL_CURRENT); // For non-Gemini systems, header timestamps are in clock ticks and need @@ -2224,7 +1954,7 @@ Result ShmemSession::readReceiveBuffer(cbPKT_GENERIC* packets, size_t max_ // (Protocol 3.11 handles conversion inline with its hardcoded 30 kHz factor.) uint64_t ts_num = 1, ts_den = 1; bool needs_ts_conversion = false; - if (m_impl->layout == ShmemLayout::CENTRAL_COMPAT && + if (m_impl->layout == ShmemLayout::CENTRAL && m_impl->compat_protocol != CBPROTO_PROTOCOL_311 && m_impl->status_buffer_raw) { auto gemini = isGeminiSystem(); @@ -2403,11 +2133,11 @@ Result ShmemSession::getReceiveBufferStats(uint32_t& received, uint32_t& a return Result::error("Receive buffer not initialized"); } - received = m_impl->recReceived(); + received = m_impl->adapter->getRecReceived(); uint32_t buflen = m_impl->rec_buffer_len; - uint32_t head_index = m_impl->recHeadindex(); - uint32_t head_wrap = m_impl->recHeadwrap(); + uint32_t head_index = m_impl->adapter->getRecHeadindexPtr(); + uint32_t head_wrap = m_impl->adapter->getRecHeadwrapPtr(); if (m_impl->rec_tailwrap == head_wrap) { if (head_index >= m_impl->rec_tailindex) { From 2194fecdc40fd13d7aa534d87571743620057bac Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Mon, 15 Jun 2026 16:28:26 -0600 Subject: [PATCH 19/62] Consolidate Central translators into the Central adapters Each ShmemSession operates on a specific instrument. With the CENTRAL layout, the instrument filter is always active. Multi-instrument control is possible by creating multiple SdkSession instances (one per instrument). --- src/cbsdk/src/sdk_session.cpp | 35 +- src/cbshm/CMakeLists.txt | 4 - .../include/cbshm/central_types/adapters.h | 557 +++++++-- .../include/cbshm/central_types/translators.h | 352 ------ src/cbshm/include/cbshm/shmem_session.h | 97 +- src/cbshm/src/central_adapters/v3_11.cpp | 1040 +++++++++++++++- src/cbshm/src/central_adapters/v4_0.cpp | 1045 +++++++++++++++- src/cbshm/src/central_adapters/v4_1.cpp | 1049 +++++++++++++++- src/cbshm/src/central_adapters/v4_2.cpp | 1050 ++++++++++++++++- src/cbshm/src/central_translators/utils.h | 83 -- src/cbshm/src/central_translators/v3_11.cpp | 998 ---------------- src/cbshm/src/central_translators/v4_0.cpp | 1003 ---------------- src/cbshm/src/central_translators/v4_1.cpp | 1007 ---------------- src/cbshm/src/central_translators/v4_2.cpp | 1007 ---------------- src/cbshm/src/shmem_session.cpp | 245 +--- 15 files changed, 4668 insertions(+), 4904 deletions(-) delete mode 100644 src/cbshm/include/cbshm/central_types/translators.h delete mode 100644 src/cbshm/src/central_translators/utils.h delete mode 100644 src/cbshm/src/central_translators/v3_11.cpp delete mode 100644 src/cbshm/src/central_translators/v4_0.cpp delete mode 100644 src/cbshm/src/central_translators/v4_1.cpp delete mode 100644 src/cbshm/src/central_translators/v4_2.cpp diff --git a/src/cbsdk/src/sdk_session.cpp b/src/cbsdk/src/sdk_session.cpp index 917d8605..ea267fc9 100644 --- a/src/cbsdk/src/sdk_session.cpp +++ b/src/cbsdk/src/sdk_session.cpp @@ -396,7 +396,7 @@ struct SdkSession::Impl { const auto* p = device_session->getChanInfo(chan_id); if (p && p->chan > 0) { ci = *p; valid = true; } } else if (shmem_session) { - auto r = shmem_session->getChanInfo(chan_id); + auto r = shmem_session->getChanInfo(chan_id - 1); if (r.isOk() && r.value().chan > 0) { ci = r.value(); valid = true; } } if (!valid) continue; @@ -406,7 +406,7 @@ struct SdkSession::Impl { ci.label[sizeof(ci.label) - 1] = '\0'; if (shmem_session) { - shmem_session->setChanInfo(chan_id - 1, ci); + shmem_session->setChanInfo(chan_id, ci); } } } @@ -719,18 +719,12 @@ Result SdkSession::create(const SdkConfig& config) { std::string central_spk = getCentralSpikeBufferName(config.device_type); std::string central_signal = getCentralSignalEventName(config.device_type); + auto inst = cbproto::InstrumentId::fromIndex(getCentralInstrumentIndex(config.device_type)); auto shmem_result = cbshm::ShmemSession::create( - central_cfg, central_rec, central_xmt, central_xmt_local, + inst, central_cfg, central_rec, central_xmt, central_xmt_local, central_status, central_spk, central_signal, cbshm::Mode::CLIENT, cbshm::ShmemLayout::CENTRAL); - if (shmem_result.isOk()) { - // Set instrument filter for CENTRAL_COMPAT mode (Central's receive buffer - // contains packets from ALL instruments; we only want our device's packets) - int32_t inst_idx = getCentralInstrumentIndex(config.device_type); - shmem_result.value().setInstrumentFilter(inst_idx); - } - if (shmem_result.isError()) { // --- Attempt 2: Native CLIENT mode --- // Try to attach to an existing CereLink STANDALONE's native segments @@ -743,6 +737,7 @@ Result SdkSession::create(const SdkConfig& config) { std::string native_signal = getNativeSegmentName(config.device_type, "signal"); shmem_result = cbshm::ShmemSession::create( + cbproto::InstrumentId::fromIndex(0), native_cfg, native_rec, native_xmt, native_xmt_local, native_status, native_spk, native_signal, cbshm::Mode::CLIENT, cbshm::ShmemLayout::NATIVE); @@ -759,6 +754,7 @@ Result SdkSession::create(const SdkConfig& config) { // --- Attempt 3: Native STANDALONE mode --- // No existing shared memory found, create new native-mode segments shmem_result = cbshm::ShmemSession::create( + cbproto::InstrumentId::fromIndex(0), native_cfg, native_rec, native_xmt, native_xmt_local, native_status, native_spk, native_signal, cbshm::Mode::STANDALONE, cbshm::ShmemLayout::NATIVE); @@ -921,9 +917,7 @@ Result SdkSession::start() { // can read device configuration (chaninfo, procinfo, sysinfo, groupinfo). if (pkt.cbpkt_header.type == cbPKTTYPE_PROCREP) { const auto* procinfo = reinterpret_cast(&pkt); - impl->shmem_session->setProcInfo( - cbproto::InstrumentId::fromPacketField(pkt.cbpkt_header.instrument), - *procinfo); + impl->shmem_session->setProcInfo(*procinfo); } if ((pkt.cbpkt_header.type & 0xF0) == cbPKTTYPE_SYSREP) { const auto* sysinfo = reinterpret_cast(&pkt); @@ -932,9 +926,7 @@ Result SdkSession::start() { if (pkt.cbpkt_header.type == cbPKTTYPE_GROUPREP) { const auto* groupinfo = reinterpret_cast(&pkt); if (groupinfo->group >= 1 && groupinfo->group <= cbMAXGROUPS) { - impl->shmem_session->setGroupInfo( - cbproto::InstrumentId::fromPacketField(pkt.cbpkt_header.instrument), - groupinfo->group - 1, *groupinfo); + impl->shmem_session->setGroupInfo(groupinfo->group - 1, *groupinfo); } } if ((pkt.cbpkt_header.type & 0xF0) == cbPKTTYPE_CHANREP) { @@ -1430,8 +1422,7 @@ Result SdkSession::getGroupInfo(uint32_t group_id) const { return Result::ok(config.groupinfo[group_id - 1]); } if (m_impl->shmem_session) { - auto inst = cbproto::InstrumentId::fromIndex(getCentralInstrumentIndex(m_impl->config.device_type)); - return m_impl->shmem_session->getGroupInfo(inst, group_id); + return m_impl->shmem_session->getGroupInfo(group_id - 1); } return Result::error("Group information not available"); } @@ -1478,8 +1469,7 @@ Result SdkSession::getFilterInfo(const uint32_t filter_id) const return Result::ok(config.filtinfo[filter_id]); } if (m_impl->shmem_session) { - auto inst = cbproto::InstrumentId::fromIndex(getCentralInstrumentIndex(m_impl->config.device_type)); - return m_impl->shmem_session->getFilterInfo(inst, filter_id); + return m_impl->shmem_session->getFilterInfo(filter_id); } return Result::error("Filter information not available"); } @@ -1524,10 +1514,7 @@ std::string SdkSession::getProcIdent() const { return std::string(native->procinfo.ident, strnlen(native->procinfo.ident, sizeof(native->procinfo.ident))); } else { - int32_t inst_idx = getCentralInstrumentIndex(m_impl->config.device_type); - auto inst = cbproto::InstrumentId::fromIndex(inst_idx); - // TODO: Check if inst >= 0? - auto procinfo = m_impl->shmem_session->getProcInfo(inst); + auto procinfo = m_impl->shmem_session->getProcInfo(); if (procinfo.isError()) { return {}; } diff --git a/src/cbshm/CMakeLists.txt b/src/cbshm/CMakeLists.txt index 7f1cb364..e18185c3 100644 --- a/src/cbshm/CMakeLists.txt +++ b/src/cbshm/CMakeLists.txt @@ -9,10 +9,6 @@ project(cbshm # Library sources set(CBSHMEM_SOURCES src/shmem_session.cpp - src/central_translators/v4_2.cpp - src/central_translators/v4_1.cpp - src/central_translators/v4_0.cpp - src/central_translators/v3_11.cpp src/central_adapters/v4_2.cpp src/central_adapters/v4_1.cpp src/central_adapters/v4_0.cpp diff --git a/src/cbshm/include/cbshm/central_types/adapters.h b/src/cbshm/include/cbshm/central_types/adapters.h index 6c517eae..d18c06ff 100644 --- a/src/cbshm/include/cbshm/central_types/adapters.h +++ b/src/cbshm/include/cbshm/central_types/adapters.h @@ -10,6 +10,7 @@ #ifndef CBSHM_CENTRAL_TYPES_ADAPTERS_H #define CBSHM_CENTRAL_TYPES_ADAPTERS_H +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include namespace cbshm { @@ -39,9 +41,73 @@ class CentralBootstrapAdapterBase { /// @brief Base-class adapter for Central-compatible shared memory access /// class CentralAdapterBase { +protected: + template + static void copyArr(T(&lhs)[lhs_n], const T(&rhs)[rhs_n]) { + if (lhs_n <= rhs_n) { + std::memcpy(lhs, rhs, lhs_n * sizeof(T)); + } else { + std::memcpy(lhs, rhs, rhs_n * sizeof(T)); + std::memset(lhs + rhs_n, 0, (lhs_n - rhs_n) * sizeof(T)); + } + } + + template + static void copyArr(LHS_T(&lhs)[lhs_n], const RHS_T(&rhs)[rhs_n], const A* adapter, LHS_T(A::*translation_func)(const RHS_T&) const) { + if (lhs_n <= rhs_n) { + for (size_t i = 0; i < lhs_n; ++i) { + lhs[i] = (adapter->*translation_func)(rhs[i]); + } + } else { + for (size_t i = 0; i < rhs_n; ++i) { + lhs[i] = (adapter->*translation_func)(rhs[i]); + } + std::memset(lhs + rhs_n, 0, (lhs_n - rhs_n) * sizeof(LHS_T)); + } + } + + template + static void copyArr2D(T(&lhs)[lhs_ny][lhs_nx], const T(&rhs)[rhs_ny][rhs_nx]) { + if (lhs_ny <= rhs_ny) { + if (lhs_nx == rhs_nx) { + std::memcpy(lhs, rhs, (lhs_ny * lhs_nx) * sizeof(T)); + } else { + for (size_t i = 0; i < lhs_ny; ++i) { + copyArr(lhs[i], rhs[i]); + } + } + } else { + if (lhs_nx == rhs_nx) { + std::memcpy(lhs, rhs, (rhs_ny * rhs_nx) * sizeof(T)); + } else { + for (size_t i = 0; i < rhs_ny; ++i) { + copyArr(lhs[i], rhs[i]); + } + } + std::memset(lhs + rhs_ny, 0, ((lhs_ny - rhs_ny) * lhs_nx) * sizeof(T)); + } + } + + template + static const void copyArr2D(LHS_T(&lhs)[lhs_ny][lhs_nx], const RHS_T(&rhs)[rhs_ny][rhs_nx], const A* adapter, LHS_T(A::*translation_func)(const RHS_T&) const) { + if (lhs_ny <= rhs_ny) { + for (size_t i = 0; i < lhs_ny; ++i) { + copyArr(lhs[i], rhs[i], adapter, translation_func); + } + } else { + for (size_t i = 0; i < rhs_ny; ++i) { + copyArr(lhs[i], rhs[i], adapter, translation_func); + } + std::memset(lhs + rhs_ny, 0, ((lhs_ny - rhs_ny) * lhs_nx) * sizeof(LHS_T)); + } + } + public: virtual ~CentralAdapterBase() = default; + // Max instrument count + virtual uint32_t getMaxProcs() const = 0; + /////////////////////////////////////////////////////////////////////////////////////////////// // DANGER !!! // These methods are brittle and serve as a workaround for the ShmemSession @@ -73,28 +139,29 @@ class CentralAdapterBase { /////////////////////////////////////////////////////////////////////////////////////////////// /// Config read operations - virtual Result<::cbPKT_PROCINFO> getProcInfo(uint8_t instrument_idx) const = 0; - virtual Result<::cbPKT_BANKINFO> getBankInfo(uint8_t instrument_idx, uint32_t bank) const = 0; - virtual Result<::cbPKT_FILTINFO> getFilterInfo(uint8_t instrument_idx, uint32_t filter) const = 0; + virtual Result<::cbPKT_PROCINFO> getProcInfo() const = 0; + virtual Result<::cbPKT_BANKINFO> getBankInfo(uint32_t bank) const = 0; + virtual Result<::cbPKT_FILTINFO> getFilterInfo(uint32_t filter) const = 0; virtual Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const = 0; virtual Result<::cbPKT_SYSINFO> getSysInfo() const = 0; - virtual Result<::cbPKT_GROUPINFO> getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const = 0; - virtual Result getConfigBuffer(uint8_t instrument_idx) const = 0; - virtual Result getPcStatus(uint8_t instrument_idx) const = 0; + virtual Result<::cbPKT_GROUPINFO> getGroupInfo(uint32_t group_idx) const = 0; + virtual Result getConfigBuffer() const = 0; + virtual Result getPcStatus() const = 0; /// Config write operations - virtual Result setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) = 0; - virtual Result setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) = 0; - virtual Result setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) = 0; + virtual Result setProcInfo(const ::cbPKT_PROCINFO& info) = 0; + virtual Result setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) = 0; + virtual Result setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) = 0; virtual Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) = 0; virtual Result setSysInfo(const ::cbPKT_SYSINFO& info) = 0; - virtual Result setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) = 0; - virtual Result setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const = 0; // TODO: currently single-instrument only! needs to be multi-instrument safe + virtual Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) = 0; + virtual Result setPcStatus(const NativePCStatus& status) const = 0; // TODO: currently single-instrument only! needs to be multi-instrument safe }; +/////////////////////////////////////////////////////////////////////////////////////////////////// namespace central_v4_2 { -/////////////////////////////////////////////////////////////////////////////////////////////////// +/// /// @brief Adapter that provides information for fetching pointers to Central's shared memory /// class BootstrapAdapter : public CentralBootstrapAdapterBase { @@ -109,11 +176,12 @@ class BootstrapAdapter : public CentralBootstrapAdapterBase { size_t getReceiveBufferLen() const override; }; -/////////////////////////////////////////////////////////////////////////////////////////////////// +/// /// @brief Adapter for Central-compatible shared memory access /// class Adapter : public CentralAdapterBase { private: + uint8_t instrument_idx; cbCFGBUFF* cfg; cbRECBUFF* rec; cbXMTBUFF* xmt; @@ -121,10 +189,97 @@ class Adapter : public CentralAdapterBase { cbPcStatus* status; cbSPKBUFF* spike; + ::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) const; + ::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) const; + ::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) const; + ::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) const; + ::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) const; + ::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) const; + ::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) const; + ::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg) const; + ::cbSCALING fromLegacy(const cbSCALING& leg) const; + ::cbFILTDESC fromLegacy(const cbFILTDESC& leg) const; + ::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) const; + ::cbHOOP fromLegacy(const cbHOOP& leg) const; + ::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) const; + ::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) const; + ::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) const; + ::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg) const; + ::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) const; + ::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) const; + ::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) const; + ::cbAdaptControl fromLegacy(const cbAdaptControl& leg) const; + ::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg) const; + ::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg) const; + ::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg) const; + ::cbWaveformData fromLegacy(const cbWaveformData& leg) const; + ::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const; + ::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg) const; + ::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) const; + ::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg) const; + ::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) const; + ::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) const; + NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg) const; + NativeNSPStatus fromLegacy(const NSPStatus& leg) const; + ::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg) const; + NativePCStatus fromLegacy(const cbPcStatus& leg) const; + NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg) const; + NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg) const; + NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg) const; + + cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) const; + cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) const; + cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) const; + cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) const; + cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) const; + cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) const; + cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) const; + cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur) const; + cbSCALING toLegacy(const ::cbSCALING& cur) const; + cbFILTDESC toLegacy(const ::cbFILTDESC& cur) const; + cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) const; + cbHOOP toLegacy(const ::cbHOOP& cur) const; + cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) const; + cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) const; + cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) const; + cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur) const; + cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) const; + cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; + cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) const; + cbAdaptControl toLegacy(const ::cbAdaptControl& cur) const; + cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur) const; + cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur) const; + cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur) const; + cbWaveformData toLegacy(const ::cbWaveformData& cur) const; + cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const; + cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur) const; + cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) const; + cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) const; + cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) const; + cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) const; + // cbCFGBUFF -> NativeConfigBuffer is a lossy translation and cannot be reversed + NSPStatus toLegacy(const NativeNSPStatus& cur) const; + cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const; + cbPcStatus toLegacy(const NativePCStatus& cur) const; + cbRECBUFF toLegacy(const NativeReceiveBuffer& cur) const; + cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur) const; + cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur) const; + public: - Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr); + Adapter( + uint8_t instrument_idx, + void* cfg_ptr, + void* rec_ptr, + void* xmt_ptr, + void* xmt_local_ptr, + void* status_ptr, + void* spike_ptr + ); ~Adapter() = default; + // Max instrument count + uint32_t getMaxProcs() const override; + // Receive buffer access uint32_t& getRecReceived() override; uint64_t getRecLasttime() override; @@ -149,30 +304,31 @@ class Adapter : public CentralAdapterBase { uint32_t* getLocalXmtBufferPtr() override; /// Config read operations - Result<::cbPKT_PROCINFO> getProcInfo(uint8_t instrument_idx) const override; - Result<::cbPKT_BANKINFO> getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const override; - Result<::cbPKT_FILTINFO> getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const override; + Result<::cbPKT_PROCINFO> getProcInfo() const override; + Result<::cbPKT_BANKINFO> getBankInfo(uint32_t bank_num) const override; + Result<::cbPKT_FILTINFO> getFilterInfo(uint32_t filter_num) const override; Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const override; Result<::cbPKT_SYSINFO> getSysInfo() const override; - Result<::cbPKT_GROUPINFO> getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const override; - Result getConfigBuffer(uint8_t instrument_idx) const override; - Result getPcStatus(uint8_t instrument_idx) const override; + Result<::cbPKT_GROUPINFO> getGroupInfo(uint32_t group_idx) const override; + Result getConfigBuffer() const override; + Result getPcStatus() const override; /// Config write operations - Result setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) override; - Result setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; - Result setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; + Result setProcInfo(const ::cbPKT_PROCINFO& info) override; + Result setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; + Result setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; Result setSysInfo(const ::cbPKT_SYSINFO& info) override; - Result setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; - Result setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const override; + Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; + Result setPcStatus(const NativePCStatus& status) const override; }; } // namespace central_v4_2 +/////////////////////////////////////////////////////////////////////////////////////////////////// namespace central_v4_1 { -/////////////////////////////////////////////////////////////////////////////////////////////////// +/// /// @brief Adapter that provides information for fetching pointers to Central's shared memory /// class BootstrapAdapter : public CentralBootstrapAdapterBase { @@ -187,11 +343,12 @@ class BootstrapAdapter : public CentralBootstrapAdapterBase { size_t getReceiveBufferLen() const override; }; -/////////////////////////////////////////////////////////////////////////////////////////////////// +/// /// @brief Adapter for Central-compatible shared memory access /// class Adapter : public CentralAdapterBase { private: + uint8_t instrument_idx; cbCFGBUFF* cfg; cbRECBUFF* rec; cbXMTBUFF* xmt; @@ -199,10 +356,97 @@ class Adapter : public CentralAdapterBase { cbPcStatus* status; cbSPKBUFF* spike; + ::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) const; + ::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) const; + ::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) const; + ::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) const; + ::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) const; + ::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) const; + ::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) const; + ::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg) const; + ::cbSCALING fromLegacy(const cbSCALING& leg) const; + ::cbFILTDESC fromLegacy(const cbFILTDESC& leg) const; + ::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) const; + ::cbHOOP fromLegacy(const cbHOOP& leg) const; + ::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) const; + ::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) const; + ::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) const; + ::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg) const; + ::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) const; + ::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) const; + ::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) const; + ::cbAdaptControl fromLegacy(const cbAdaptControl& leg) const; + ::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg) const; + ::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg) const; + ::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg) const; + ::cbWaveformData fromLegacy(const cbWaveformData& leg) const; + ::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const; + ::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg) const; + ::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) const; + ::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg) const; + ::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) const; + ::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) const; + NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg) const; + NativeNSPStatus fromLegacy(const NSPStatus& leg) const; + ::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg) const; + NativePCStatus fromLegacy(const cbPcStatus& leg) const; + NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg) const; + NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg) const; + NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg) const; + + cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) const; + cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) const; + cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) const; + cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) const; + cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) const; + cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) const; + cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) const; + cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur) const; + cbSCALING toLegacy(const ::cbSCALING& cur) const; + cbFILTDESC toLegacy(const ::cbFILTDESC& cur) const; + cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) const; + cbHOOP toLegacy(const ::cbHOOP& cur) const; + cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) const; + cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) const; + cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) const; + cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur) const; + cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) const; + cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; + cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) const; + cbAdaptControl toLegacy(const ::cbAdaptControl& cur) const; + cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur) const; + cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur) const; + cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur) const; + cbWaveformData toLegacy(const ::cbWaveformData& cur) const; + cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const; + cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur) const; + cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) const; + cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) const; + cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) const; + cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) const; + // cbCFGBUFF -> NativeConfigBuffer is a lossy translation and cannot be reversed + NSPStatus toLegacy(const NativeNSPStatus& cur) const; + cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const; + cbPcStatus toLegacy(const NativePCStatus& cur) const; + cbRECBUFF toLegacy(const NativeReceiveBuffer& cur) const; + cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur) const; + cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur) const; + public: - Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr); + Adapter( + uint8_t instrument_idx, + void* cfg_ptr, + void* rec_ptr, + void* xmt_ptr, + void* xmt_local_ptr, + void* status_ptr, + void* spike_ptr + ); ~Adapter() = default; + // Max instrument count + uint32_t getMaxProcs() const override; + // Receive buffer access uint32_t& getRecReceived() override; uint64_t getRecLasttime() override; @@ -227,30 +471,31 @@ class Adapter : public CentralAdapterBase { uint32_t* getLocalXmtBufferPtr() override; /// Config read operations - Result<::cbPKT_PROCINFO> getProcInfo(uint8_t instrument_idx) const override; - Result<::cbPKT_BANKINFO> getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const override; - Result<::cbPKT_FILTINFO> getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const override; + Result<::cbPKT_PROCINFO> getProcInfo() const override; + Result<::cbPKT_BANKINFO> getBankInfo(uint32_t bank_num) const override; + Result<::cbPKT_FILTINFO> getFilterInfo(uint32_t filter_num) const override; Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const override; Result<::cbPKT_SYSINFO> getSysInfo() const override; - Result<::cbPKT_GROUPINFO> getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const override; - Result getConfigBuffer(uint8_t instrument_idx) const override; - Result getPcStatus(uint8_t instrument_idx) const override; + Result<::cbPKT_GROUPINFO> getGroupInfo(uint32_t group_idx) const override; + Result getConfigBuffer() const override; + Result getPcStatus() const override; /// Config write operations - Result setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) override; - Result setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; - Result setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; + Result setProcInfo(const ::cbPKT_PROCINFO& info) override; + Result setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; + Result setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; Result setSysInfo(const ::cbPKT_SYSINFO& info) override; - Result setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; - Result setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const override; + Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; + Result setPcStatus(const NativePCStatus& status) const override; }; } // namespace central_v4_1 +/////////////////////////////////////////////////////////////////////////////////////////////////// namespace central_v4_0 { -/////////////////////////////////////////////////////////////////////////////////////////////////// +/// /// @brief Adapter that provides information for fetching pointers to Central's shared memory /// class BootstrapAdapter : public CentralBootstrapAdapterBase { @@ -265,11 +510,12 @@ class BootstrapAdapter : public CentralBootstrapAdapterBase { size_t getReceiveBufferLen() const override; }; -/////////////////////////////////////////////////////////////////////////////////////////////////// +/// /// @brief Adapter for Central-compatible shared memory access /// class Adapter : public CentralAdapterBase { private: + uint8_t instrument_idx; cbCFGBUFF* cfg; cbRECBUFF* rec; cbXMTBUFF* xmt; @@ -277,10 +523,97 @@ class Adapter : public CentralAdapterBase { cbPcStatus* status; cbSPKBUFF* spike; + ::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) const; + ::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) const; + ::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) const; + ::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) const; + ::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) const; + ::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) const; + ::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) const; + ::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg) const; + ::cbSCALING fromLegacy(const cbSCALING& leg) const; + ::cbFILTDESC fromLegacy(const cbFILTDESC& leg) const; + ::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) const; + ::cbHOOP fromLegacy(const cbHOOP& leg) const; + ::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) const; + ::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) const; + ::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) const; + ::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg) const; + ::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) const; + ::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) const; + ::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) const; + ::cbAdaptControl fromLegacy(const cbAdaptControl& leg) const; + ::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg) const; + ::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg) const; + ::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg) const; + ::cbWaveformData fromLegacy(const cbWaveformData& leg) const; + ::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const; + ::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg) const; + ::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) const; + ::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg) const; + ::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) const; + ::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) const; + NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg) const; + NativeNSPStatus fromLegacy(const NSPStatus& leg) const; + ::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg) const; + NativePCStatus fromLegacy(const cbPcStatus& leg) const; + NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg) const; + NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg) const; + NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg) const; + + cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) const; + cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) const; + cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) const; + cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) const; + cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) const; + cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) const; + cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) const; + cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur) const; + cbSCALING toLegacy(const ::cbSCALING& cur) const; + cbFILTDESC toLegacy(const ::cbFILTDESC& cur) const; + cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) const; + cbHOOP toLegacy(const ::cbHOOP& cur) const; + cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) const; + cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) const; + cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) const; + cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur) const; + cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) const; + cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; + cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) const; + cbAdaptControl toLegacy(const ::cbAdaptControl& cur) const; + cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur) const; + cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur) const; + cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur) const; + cbWaveformData toLegacy(const ::cbWaveformData& cur) const; + cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const; + cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur) const; + cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) const; + cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) const; + cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) const; + cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) const; + // cbCFGBUFF -> NativeConfigBuffer is a lossy translation and cannot be reversed + NSPStatus toLegacy(const NativeNSPStatus& cur) const; + cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const; + cbPcStatus toLegacy(const NativePCStatus& cur) const; + cbRECBUFF toLegacy(const NativeReceiveBuffer& cur) const; + cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur) const; + cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur) const; + public: - Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr); + Adapter( + uint8_t instrument_idx, + void* cfg_ptr, + void* rec_ptr, + void* xmt_ptr, + void* xmt_local_ptr, + void* status_ptr, + void* spike_ptr + ); ~Adapter() = default; + // Max instrument count + uint32_t getMaxProcs() const override; + // Receive buffer access uint32_t& getRecReceived() override; uint64_t getRecLasttime() override; @@ -305,30 +638,31 @@ class Adapter : public CentralAdapterBase { uint32_t* getLocalXmtBufferPtr() override; /// Config read operations - Result<::cbPKT_PROCINFO> getProcInfo(uint8_t instrument_idx) const override; - Result<::cbPKT_BANKINFO> getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const override; - Result<::cbPKT_FILTINFO> getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const override; + Result<::cbPKT_PROCINFO> getProcInfo() const override; + Result<::cbPKT_BANKINFO> getBankInfo(uint32_t bank_num) const override; + Result<::cbPKT_FILTINFO> getFilterInfo(uint32_t filter_num) const override; Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const override; Result<::cbPKT_SYSINFO> getSysInfo() const override; - Result<::cbPKT_GROUPINFO> getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const override; - Result getConfigBuffer(uint8_t instrument_idx) const override; - Result getPcStatus(uint8_t instrument_idx) const override; + Result<::cbPKT_GROUPINFO> getGroupInfo(uint32_t group_idx) const override; + Result getConfigBuffer() const override; + Result getPcStatus() const override; /// Config write operations - Result setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) override; - Result setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; - Result setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; + Result setProcInfo(const ::cbPKT_PROCINFO& info) override; + Result setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; + Result setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; Result setSysInfo(const ::cbPKT_SYSINFO& info) override; - Result setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; - Result setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const override; + Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; + Result setPcStatus(const NativePCStatus& status) const override; }; } // namespace central_v4_0 +/////////////////////////////////////////////////////////////////////////////////////////////////// namespace central_v3_11 { -/////////////////////////////////////////////////////////////////////////////////////////////////// +/// /// @brief Adapter that provides information for fetching pointers to Central's shared memory /// class BootstrapAdapter : public CentralBootstrapAdapterBase { @@ -343,11 +677,12 @@ class BootstrapAdapter : public CentralBootstrapAdapterBase { size_t getReceiveBufferLen() const override; }; -/////////////////////////////////////////////////////////////////////////////////////////////////// +/// /// @brief Adapter for Central-compatible shared memory access /// class Adapter : public CentralAdapterBase { private: + uint8_t instrument_idx; cbCFGBUFF* cfg; cbRECBUFF* rec; cbXMTBUFF* xmt; @@ -355,10 +690,97 @@ class Adapter : public CentralAdapterBase { cbPcStatus* status; cbSPKBUFF* spike; + ::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) const; + ::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) const; + ::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) const; + ::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) const; + ::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) const; + ::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) const; + ::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) const; + ::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg) const; + ::cbSCALING fromLegacy(const cbSCALING& leg) const; + ::cbFILTDESC fromLegacy(const cbFILTDESC& leg) const; + ::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) const; + ::cbHOOP fromLegacy(const cbHOOP& leg) const; + ::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) const; + ::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) const; + ::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) const; + ::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg) const; + ::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) const; + ::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) const; + ::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) const; + ::cbAdaptControl fromLegacy(const cbAdaptControl& leg) const; + ::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg) const; + ::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg) const; + ::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg) const; + ::cbWaveformData fromLegacy(const cbWaveformData& leg) const; + ::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const; + ::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg) const; + ::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) const; + ::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg) const; + ::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) const; + ::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) const; + NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg) const; + NativeNSPStatus fromLegacy(const NSPStatus& leg) const; + ::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg) const; + NativePCStatus fromLegacy(const cbPcStatus& leg) const; + NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg) const; + NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg) const; + NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg) const; + + cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) const; + cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) const; + cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) const; + cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) const; + cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) const; + cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) const; + cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) const; + cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur) const; + cbSCALING toLegacy(const ::cbSCALING& cur) const; + cbFILTDESC toLegacy(const ::cbFILTDESC& cur) const; + cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) const; + cbHOOP toLegacy(const ::cbHOOP& cur) const; + cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) const; + cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) const; + cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) const; + cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur) const; + cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) const; + cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; + cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) const; + cbAdaptControl toLegacy(const ::cbAdaptControl& cur) const; + cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur) const; + cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur) const; + cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur) const; + cbWaveformData toLegacy(const ::cbWaveformData& cur) const; + cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const; + cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur) const; + cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) const; + cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) const; + cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) const; + cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) const; + // cbCFGBUFF -> NativeConfigBuffer is a lossy translation and cannot be reversed + NSPStatus toLegacy(const NativeNSPStatus& cur) const; + cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const; + cbPcStatus toLegacy(const NativePCStatus& cur) const; + cbRECBUFF toLegacy(const NativeReceiveBuffer& cur) const; + cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur) const; + cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur) const; + public: - Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr); + Adapter( + uint8_t instrument_idx, + void* cfg_ptr, + void* rec_ptr, + void* xmt_ptr, + void* xmt_local_ptr, + void* status_ptr, + void* spike_ptr + ); ~Adapter() = default; + // Max instrument count + uint32_t getMaxProcs() const override; + // Receive buffer access uint32_t& getRecReceived() override; uint64_t getRecLasttime() override; @@ -383,26 +805,27 @@ class Adapter : public CentralAdapterBase { uint32_t* getLocalXmtBufferPtr() override; /// Config read operations - Result<::cbPKT_PROCINFO> getProcInfo(uint8_t instrument_idx) const override; - Result<::cbPKT_BANKINFO> getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const override; - Result<::cbPKT_FILTINFO> getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const override; + Result<::cbPKT_PROCINFO> getProcInfo() const override; + Result<::cbPKT_BANKINFO> getBankInfo(uint32_t bank_num) const override; + Result<::cbPKT_FILTINFO> getFilterInfo(uint32_t filter_num) const override; Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const override; Result<::cbPKT_SYSINFO> getSysInfo() const override; - Result<::cbPKT_GROUPINFO> getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const override; - Result getConfigBuffer(uint8_t instrument_idx) const override; - Result getPcStatus(uint8_t instrument_idx) const override; + Result<::cbPKT_GROUPINFO> getGroupInfo(uint32_t group_idx) const override; + Result getConfigBuffer() const override; + Result getPcStatus() const override; /// Config write operations - Result setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) override; - Result setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; - Result setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; + Result setProcInfo(const ::cbPKT_PROCINFO& info) override; + Result setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; + Result setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; Result setSysInfo(const ::cbPKT_SYSINFO& info) override; - Result setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; - Result setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const override; + Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; + Result setPcStatus(const NativePCStatus& status) const override; }; } // namespace central_v3_11 +/////////////////////////////////////////////////////////////////////////////////////////////////// } // namespace cbshm diff --git a/src/cbshm/include/cbshm/central_types/translators.h b/src/cbshm/include/cbshm/central_types/translators.h deleted file mode 100644 index 1898c62a..00000000 --- a/src/cbshm/include/cbshm/central_types/translators.h +++ /dev/null @@ -1,352 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file translators.h -/// @author Caden Shmookler -/// @date 2026-05-22 -/// -/// @brief Translators for Central-compatible shared memory access -/// -/// Downstream functions require that translations always succeed. -/// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#ifndef CBSHM_CENTRAL_TYPES_TRANSLATORS_H -#define CBSHM_CENTRAL_TYPES_TRANSLATORS_H - -#include -#include -#include -#include -#include -#include -#include - -namespace cbshm { - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Additional context for the translation functions -/// -/// Not all translators need this context, but it's provided to all functions so the signatures -/// remain the same. -/// -/// TODO: Move all translations to within the adapter classes as well as the translation context. -/// -struct TranslationContext { - // cbCFGBUFF, cbPcStatus - uint8_t instrument_idx; -}; - -namespace central_v4_2 { - -::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg, const TranslationContext& ctx); -::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg, const TranslationContext& ctx); -::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg, const TranslationContext& ctx); -::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg, const TranslationContext& ctx); -::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg, const TranslationContext& ctx); -::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg, const TranslationContext& ctx); -::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg, const TranslationContext& ctx); -::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg, const TranslationContext& ctx); -::cbSCALING fromLegacy(const cbSCALING& leg, const TranslationContext& ctx); -::cbFILTDESC fromLegacy(const cbFILTDESC& leg, const TranslationContext& ctx); -::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg, const TranslationContext& ctx); -::cbHOOP fromLegacy(const cbHOOP& leg, const TranslationContext& ctx); -::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg, const TranslationContext& ctx); -::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg, const TranslationContext& ctx); -::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg, const TranslationContext& ctx); -::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg, const TranslationContext& ctx); -::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg, const TranslationContext& ctx); -::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg, const TranslationContext& ctx); -::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg, const TranslationContext& ctx); -::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg, const TranslationContext& ctx); -::cbproto::SpikeSorting fromLegacy(const cbproto::SpikeSorting& leg, const TranslationContext& ctx); -::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg, const TranslationContext& ctx); -::cbWaveformData fromLegacy(const cbWaveformData& leg, const TranslationContext& ctx); -::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg, const TranslationContext& ctx); -::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg, const TranslationContext& ctx); -::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg, const TranslationContext& ctx); -::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg, const TranslationContext& ctx); -::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg, const TranslationContext& ctx); -::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg, const TranslationContext& ctx); -NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg, const TranslationContext& ctx); -NativeNSPStatus fromLegacy(const NSPStatus& leg, const TranslationContext& ctx); -::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg, const TranslationContext& ctx); -NativePCStatus fromLegacy(const cbPcStatus& leg, const TranslationContext& ctx); -NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg, const TranslationContext& ctx); -NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg, const TranslationContext& ctx); -NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg, const TranslationContext& ctx); - -cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur, const TranslationContext& ctx); -cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur, const TranslationContext& ctx); -cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur, const TranslationContext& ctx); -cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur, const TranslationContext& ctx); -cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur, const TranslationContext& ctx); -cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur, const TranslationContext& ctx); -cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur, const TranslationContext& ctx); -cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur, const TranslationContext& ctx); -cbSCALING toLegacy(const ::cbSCALING& cur, const TranslationContext& ctx); -cbFILTDESC toLegacy(const ::cbFILTDESC& cur, const TranslationContext& ctx); -cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur, const TranslationContext& ctx); -cbHOOP toLegacy(const ::cbHOOP& cur, const TranslationContext& ctx); -cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur, const TranslationContext& ctx); -cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur, const TranslationContext& ctx); -cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur, const TranslationContext& ctx); -cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur, const TranslationContext& ctx); -cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur, const TranslationContext& ctx); -cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur, const TranslationContext& ctx); -cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur, const TranslationContext& ctx); -cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur, const TranslationContext& ctx); -cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur, const TranslationContext& ctx); -cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur, const TranslationContext& ctx); -cbWaveformData toLegacy(const ::cbWaveformData& cur, const TranslationContext& ctx); -cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur, const TranslationContext& ctx); -cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur, const TranslationContext& ctx); -cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur, const TranslationContext& ctx); -cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur, const TranslationContext& ctx); -cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur, const TranslationContext& ctx); -cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur, const TranslationContext& ctx); -// cbCFGBUFF -> NativeConfigBuffer is a lossy translation and cannot be reversed -NSPStatus toLegacy(const NativeNSPStatus& cur, const TranslationContext& ctx); -cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur, const TranslationContext& ctx); -cbPcStatus toLegacy(const NativePCStatus& cur, const TranslationContext& ctx); -cbRECBUFF toLegacy(const NativeReceiveBuffer& cur, const TranslationContext& ctx); -cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur, const TranslationContext& ctx); -cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur, const TranslationContext& ctx); - -} // namespace central_v4_2 - -namespace central_v4_1 { - -::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg, const TranslationContext& ctx); -::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg, const TranslationContext& ctx); -::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg, const TranslationContext& ctx); -::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg, const TranslationContext& ctx); -::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg, const TranslationContext& ctx); -::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg, const TranslationContext& ctx); -::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg, const TranslationContext& ctx); -::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg, const TranslationContext& ctx); -::cbSCALING fromLegacy(const cbSCALING& leg, const TranslationContext& ctx); -::cbFILTDESC fromLegacy(const cbFILTDESC& leg, const TranslationContext& ctx); -::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg, const TranslationContext& ctx); -::cbHOOP fromLegacy(const cbHOOP& leg, const TranslationContext& ctx); -::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg, const TranslationContext& ctx); -::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg, const TranslationContext& ctx); -::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg, const TranslationContext& ctx); -::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg, const TranslationContext& ctx); -::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg, const TranslationContext& ctx); -::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg, const TranslationContext& ctx); -::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg, const TranslationContext& ctx); -::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg, const TranslationContext& ctx); -::cbproto::SpikeSorting fromLegacy(const cbproto::SpikeSorting& leg, const TranslationContext& ctx); -::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg, const TranslationContext& ctx); -::cbWaveformData fromLegacy(const cbWaveformData& leg, const TranslationContext& ctx); -::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg, const TranslationContext& ctx); -::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg, const TranslationContext& ctx); -::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg, const TranslationContext& ctx); -::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg, const TranslationContext& ctx); -::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg, const TranslationContext& ctx); -::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg, const TranslationContext& ctx); -NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg, const TranslationContext& ctx); -NativeNSPStatus fromLegacy(const NSPStatus& leg, const TranslationContext& ctx); -::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg, const TranslationContext& ctx); -NativePCStatus fromLegacy(const cbPcStatus& leg, const TranslationContext& ctx); -NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg, const TranslationContext& ctx); -NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg, const TranslationContext& ctx); -NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg, const TranslationContext& ctx); - -cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur, const TranslationContext& ctx); -cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur, const TranslationContext& ctx); -cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur, const TranslationContext& ctx); -cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur, const TranslationContext& ctx); -cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur, const TranslationContext& ctx); -cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur, const TranslationContext& ctx); -cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur, const TranslationContext& ctx); -cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur, const TranslationContext& ctx); -cbSCALING toLegacy(const ::cbSCALING& cur, const TranslationContext& ctx); -cbFILTDESC toLegacy(const ::cbFILTDESC& cur, const TranslationContext& ctx); -cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur, const TranslationContext& ctx); -cbHOOP toLegacy(const ::cbHOOP& cur, const TranslationContext& ctx); -cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur, const TranslationContext& ctx); -cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur, const TranslationContext& ctx); -cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur, const TranslationContext& ctx); -cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur, const TranslationContext& ctx); -cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur, const TranslationContext& ctx); -cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur, const TranslationContext& ctx); -cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur, const TranslationContext& ctx); -cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur, const TranslationContext& ctx); -cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur, const TranslationContext& ctx); -cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur, const TranslationContext& ctx); -cbWaveformData toLegacy(const ::cbWaveformData& cur, const TranslationContext& ctx); -cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur, const TranslationContext& ctx); -cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur, const TranslationContext& ctx); -cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur, const TranslationContext& ctx); -cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur, const TranslationContext& ctx); -cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur, const TranslationContext& ctx); -cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur, const TranslationContext& ctx); -// cbCFGBUFF -> NativeConfigBuffer is a lossy translation and cannot be reversed -NSPStatus toLegacy(const NativeNSPStatus& cur, const TranslationContext& ctx); -cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur, const TranslationContext& ctx); -cbPcStatus toLegacy(const NativePCStatus& cur, const TranslationContext& ctx); -cbRECBUFF toLegacy(const NativeReceiveBuffer& cur, const TranslationContext& ctx); -cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur, const TranslationContext& ctx); -cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur, const TranslationContext& ctx); - -} // namespace central_v4_1 - -namespace central_v4_0 { - -::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg, const TranslationContext& ctx); -::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg, const TranslationContext& ctx); -::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg, const TranslationContext& ctx); -::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg, const TranslationContext& ctx); -::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg, const TranslationContext& ctx); -::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg, const TranslationContext& ctx); -::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg, const TranslationContext& ctx); -::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg, const TranslationContext& ctx); -::cbSCALING fromLegacy(const cbSCALING& leg, const TranslationContext& ctx); -::cbFILTDESC fromLegacy(const cbFILTDESC& leg, const TranslationContext& ctx); -::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg, const TranslationContext& ctx); -::cbHOOP fromLegacy(const cbHOOP& leg, const TranslationContext& ctx); -::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg, const TranslationContext& ctx); -::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg, const TranslationContext& ctx); -::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg, const TranslationContext& ctx); -::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg, const TranslationContext& ctx); -::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg, const TranslationContext& ctx); -::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg, const TranslationContext& ctx); -::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg, const TranslationContext& ctx); -::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg, const TranslationContext& ctx); -::cbproto::SpikeSorting fromLegacy(const cbproto::SpikeSorting& leg, const TranslationContext& ctx); -::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg, const TranslationContext& ctx); -::cbWaveformData fromLegacy(const cbWaveformData& leg, const TranslationContext& ctx); -::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg, const TranslationContext& ctx); -::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg, const TranslationContext& ctx); -::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg, const TranslationContext& ctx); -::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg, const TranslationContext& ctx); -::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg, const TranslationContext& ctx); -::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg, const TranslationContext& ctx); -NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg, const TranslationContext& ctx); -NativeNSPStatus fromLegacy(const NSPStatus& leg, const TranslationContext& ctx); -::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg, const TranslationContext& ctx); -NativePCStatus fromLegacy(const cbPcStatus& leg, const TranslationContext& ctx); -NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg, const TranslationContext& ctx); -NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg, const TranslationContext& ctx); -NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg, const TranslationContext& ctx); - -cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur, const TranslationContext& ctx); -cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur, const TranslationContext& ctx); -cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur, const TranslationContext& ctx); -cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur, const TranslationContext& ctx); -cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur, const TranslationContext& ctx); -cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur, const TranslationContext& ctx); -cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur, const TranslationContext& ctx); -cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur, const TranslationContext& ctx); -cbSCALING toLegacy(const ::cbSCALING& cur, const TranslationContext& ctx); -cbFILTDESC toLegacy(const ::cbFILTDESC& cur, const TranslationContext& ctx); -cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur, const TranslationContext& ctx); -cbHOOP toLegacy(const ::cbHOOP& cur, const TranslationContext& ctx); -cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur, const TranslationContext& ctx); -cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur, const TranslationContext& ctx); -cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur, const TranslationContext& ctx); -cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur, const TranslationContext& ctx); -cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur, const TranslationContext& ctx); -cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur, const TranslationContext& ctx); -cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur, const TranslationContext& ctx); -cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur, const TranslationContext& ctx); -cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur, const TranslationContext& ctx); -cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur, const TranslationContext& ctx); -cbWaveformData toLegacy(const ::cbWaveformData& cur, const TranslationContext& ctx); -cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur, const TranslationContext& ctx); -cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur, const TranslationContext& ctx); -cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur, const TranslationContext& ctx); -cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur, const TranslationContext& ctx); -cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur, const TranslationContext& ctx); -cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur, const TranslationContext& ctx); -// cbCFGBUFF -> NativeConfigBuffer is a lossy translation and cannot be reversed -NSPStatus toLegacy(const NativeNSPStatus& cur, const TranslationContext& ctx); -cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur, const TranslationContext& ctx); -cbPcStatus toLegacy(const NativePCStatus& cur, const TranslationContext& ctx); -cbRECBUFF toLegacy(const NativeReceiveBuffer& cur, const TranslationContext& ctx); -cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur, const TranslationContext& ctx); -cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur, const TranslationContext& ctx); - -} // namespace central_v4_0 - -namespace central_v3_11 { - -::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg, const TranslationContext& ctx); -::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg, const TranslationContext& ctx); -::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg, const TranslationContext& ctx); -::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg, const TranslationContext& ctx); -::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg, const TranslationContext& ctx); -::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg, const TranslationContext& ctx); -::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg, const TranslationContext& ctx); -::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg, const TranslationContext& ctx); -::cbSCALING fromLegacy(const cbSCALING& leg, const TranslationContext& ctx); -::cbFILTDESC fromLegacy(const cbFILTDESC& leg, const TranslationContext& ctx); -::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg, const TranslationContext& ctx); -::cbHOOP fromLegacy(const cbHOOP& leg, const TranslationContext& ctx); -::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg, const TranslationContext& ctx); -::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg, const TranslationContext& ctx); -::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg, const TranslationContext& ctx); -::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg, const TranslationContext& ctx); -::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg, const TranslationContext& ctx); -::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg, const TranslationContext& ctx); -::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg, const TranslationContext& ctx); -::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg, const TranslationContext& ctx); -::cbproto::SpikeSorting fromLegacy(const cbproto::SpikeSorting& leg, const TranslationContext& ctx); -::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg, const TranslationContext& ctx); -::cbWaveformData fromLegacy(const cbWaveformData& leg, const TranslationContext& ctx); -::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg, const TranslationContext& ctx); -::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg, const TranslationContext& ctx); -::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg, const TranslationContext& ctx); -::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg, const TranslationContext& ctx); -::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg, const TranslationContext& ctx); -::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg, const TranslationContext& ctx); -NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg, const TranslationContext& ctx); -NativeNSPStatus fromLegacy(const NSPStatus& leg, const TranslationContext& ctx); -::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg, const TranslationContext& ctx); -NativePCStatus fromLegacy(const cbPcStatus& leg, const TranslationContext& ctx); -NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg, const TranslationContext& ctx); -NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg, const TranslationContext& ctx); -NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg, const TranslationContext& ctx); - -cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur, const TranslationContext& ctx); -cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur, const TranslationContext& ctx); -cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur, const TranslationContext& ctx); -cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur, const TranslationContext& ctx); -cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur, const TranslationContext& ctx); -cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur, const TranslationContext& ctx); -cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur, const TranslationContext& ctx); -cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur, const TranslationContext& ctx); -cbSCALING toLegacy(const ::cbSCALING& cur, const TranslationContext& ctx); -cbFILTDESC toLegacy(const ::cbFILTDESC& cur, const TranslationContext& ctx); -cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur, const TranslationContext& ctx); -cbHOOP toLegacy(const ::cbHOOP& cur, const TranslationContext& ctx); -cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur, const TranslationContext& ctx); -cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur, const TranslationContext& ctx); -cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur, const TranslationContext& ctx); -cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur, const TranslationContext& ctx); -cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur, const TranslationContext& ctx); -cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur, const TranslationContext& ctx); -cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur, const TranslationContext& ctx); -cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur, const TranslationContext& ctx); -cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur, const TranslationContext& ctx); -cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur, const TranslationContext& ctx); -cbWaveformData toLegacy(const ::cbWaveformData& cur, const TranslationContext& ctx); -cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur, const TranslationContext& ctx); -cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur, const TranslationContext& ctx); -cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur, const TranslationContext& ctx); -cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur, const TranslationContext& ctx); -cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur, const TranslationContext& ctx); -cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur, const TranslationContext& ctx); -// cbCFGBUFF -> NativeConfigBuffer is a lossy translation and cannot be reversed -NSPStatus toLegacy(const NativeNSPStatus& cur, const TranslationContext& ctx); -cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur, const TranslationContext& ctx); -cbPcStatus toLegacy(const NativePCStatus& cur, const TranslationContext& ctx); -cbRECBUFF toLegacy(const NativeReceiveBuffer& cur, const TranslationContext& ctx); -cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur, const TranslationContext& ctx); -cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur, const TranslationContext& ctx); - -} // namespace central_v3_11 - -} // namespace cbshm - -#endif // CBSHM_CENTRAL_TYPES_TRANSLATORS_H diff --git a/src/cbshm/include/cbshm/shmem_session.h b/src/cbshm/include/cbshm/shmem_session.h index 51c6638d..e601fb50 100644 --- a/src/cbshm/include/cbshm/shmem_session.h +++ b/src/cbshm/include/cbshm/shmem_session.h @@ -67,6 +67,7 @@ class ShmemSession { /// @{ /// @brief Create a new shared memory session + /// @param id Instrument ID (1-based) /// @param cfg_name Config buffer shared memory name (e.g., "cbCFGbuffer") /// @param rec_name Receive buffer shared memory name (e.g., "cbRECbuffer") /// @param xmt_name Transmit buffer shared memory name (e.g., "XmtGlobal") @@ -77,7 +78,7 @@ class ShmemSession { /// @param mode Operating mode (STANDALONE or CLIENT) /// @param layout Buffer layout (CENTRAL or NATIVE, default CENTRAL for backward compat) /// @return Result containing ShmemSession on success, error message on failure - static Result create(const std::string& cfg_name, const std::string& rec_name, + static Result create(cbproto::InstrumentId id, const std::string& cfg_name, const std::string& rec_name, const std::string& xmt_name, const std::string& xmt_local_name, const std::string& status_name, const std::string& spk_name, const std::string& signal_event_name, Mode mode, @@ -110,26 +111,28 @@ class ShmemSession { /// @return CENTRAL or NATIVE ShmemLayout getLayout() const; + /// @brief Get the maximum number of instruments + /// + /// With the NATIVE layout, always returns 1. + /// With the CENTRAL layout, returns the value of cbMAXPROCS. + /// + /// @return the maximum instrument count + uint32_t getMaxProcs() const; + /// @} /////////////////////////////////////////////////////////////////////////// - /// @name Instrument Status (CRITICAL for multi-instrument) + /// @name Instrument Status /// @{ /// @brief Get instrument active status - /// @param id Instrument ID (1-based) /// @return true if instrument is active in shared memory - Result isInstrumentActive(cbproto::InstrumentId id) const; + Result isInstrumentActive() const; /// @brief Set instrument active status - /// @param id Instrument ID (1-based) /// @param active true to mark active, false to mark inactive /// @return Result indicating success or failure - Result setInstrumentActive(cbproto::InstrumentId id, bool active); - - /// @brief Get first active instrument ID - /// @return InstrumentId of first active instrument, or error if none active - Result getFirstActiveInstrument() const; + Result setInstrumentActive(bool active); /// @} @@ -137,22 +140,19 @@ class ShmemSession { /// @name Configuration Read Operations /// @{ - /// @brief Get processor information for specified instrument - /// @param id Instrument ID (1-based, e.g., cbNSP1) + /// @brief Get processor information /// @return cbPKT_PROCINFO structure on success - Result getProcInfo(cbproto::InstrumentId id) const; + Result getProcInfo() const; /// @brief Get bank information - /// @param id Instrument ID (1-based) /// @param bank Bank number (1-based, as used in cbPKT_BANKINFO) /// @return cbPKT_BANKINFO structure on success - Result getBankInfo(cbproto::InstrumentId id, uint32_t bank) const; + Result getBankInfo(uint32_t bank) const; /// @brief Get filter information - /// @param id Instrument ID (1-based) /// @param filter Filter number (1-based, as used in cbPKT_FILTINFO) /// @return cbPKT_FILTINFO structure on success - Result getFilterInfo(cbproto::InstrumentId id, uint32_t filter) const; + Result getFilterInfo(uint32_t filter) const; /// @brief Get channel information /// @param channel Channel number (0-based, global across all instruments) @@ -164,11 +164,10 @@ class ShmemSession { Result getSysInfo() const; /// @brief Get sample group information - /// @param id Instrument ID (1-based) /// @param group Group number (0-based, 0 to cbMAXGROUPS-1) /// @param info cbPKT_GROUPINFO structure to write /// @return Result indicating success or failure - Result getGroupInfo(cbproto::InstrumentId id, uint32_t group) const; + Result getGroupInfo(uint32_t group) const; /// @} @@ -176,25 +175,22 @@ class ShmemSession { /// @name Configuration Write Operations /// @{ - /// @brief Set processor information for specified instrument - /// @param id Instrument ID (1-based) + /// @brief Set processor information /// @param info cbPKT_PROCINFO structure to write /// @return Result indicating success or failure - Result setProcInfo(cbproto::InstrumentId id, const cbPKT_PROCINFO& info); + Result setProcInfo(const cbPKT_PROCINFO& info); /// @brief Set bank information - /// @param id Instrument ID (1-based) /// @param bank Bank number (0-based) /// @param info cbPKT_BANKINFO structure to write /// @return Result indicating success or failure - Result setBankInfo(cbproto::InstrumentId id, uint32_t bank, const cbPKT_BANKINFO& info); + Result setBankInfo(uint32_t bank, const cbPKT_BANKINFO& info); /// @brief Set filter information - /// @param id Instrument ID (1-based) /// @param filter Filter number (0-based) /// @param info cbPKT_FILTINFO structure to write /// @return Result indicating success or failure - Result setFilterInfo(cbproto::InstrumentId id, uint32_t filter, const cbPKT_FILTINFO& info); + Result setFilterInfo(uint32_t filter, const cbPKT_FILTINFO& info); /// @brief Set channel information /// @param channel Channel number (0-based) @@ -208,11 +204,10 @@ class ShmemSession { Result setSysInfo(const cbPKT_SYSINFO& info); /// @brief Set sample group information - /// @param id Instrument ID (1-based) /// @param group Group number (0-based, 0 to cbMAXGROUPS-1) /// @param info cbPKT_GROUPINFO structure to write /// @return Result indicating success or failure - Result setGroupInfo(cbproto::InstrumentId id, uint32_t group, const cbPKT_GROUPINFO& info); + Result setGroupInfo(uint32_t group, const cbPKT_GROUPINFO& info); /// @} @@ -229,9 +224,8 @@ class ShmemSession { const NativeConfigBuffer* getNativeConfigBuffer() const; /// @brief Get a translated copy of Central's configuration buffer - /// @param id Instrument ID (1-based) /// @return Result::value containing the configuration buffer, or Result::error if not CENTRAL layout - Result getLegacyConfigBuffer(cbproto::InstrumentId id); + Result getLegacyConfigBuffer(); /// @} @@ -354,16 +348,14 @@ class ShmemSession { /// @return Total channel count Result getNumTotalChans() const; - /// @brief Get NSP status for specified instrument - /// @param id Instrument ID (1-based) + /// @brief Get NSP status /// @return NSP status (INIT, NOIPADDR, NOREPLY, FOUND, INVALID) - Result getNspStatus(cbproto::InstrumentId id) const; + Result getNspStatus() const; - /// @brief Set NSP status for specified instrument - /// @param id Instrument ID (1-based) + /// @brief Set NSP status /// @param status NSP status to set /// @return Result indicating success or failure - Result setNspStatus(cbproto::InstrumentId id, NativeNSPStatus status); + Result setNspStatus(NativeNSPStatus status); /// @brief Check if system is configured as Gemini /// @return true if Gemini system, false otherwise @@ -403,34 +395,15 @@ class ShmemSession { /// @} - /////////////////////////////////////////////////////////////////////////// - /// @name Instrument Filtering (CENTRAL_COMPAT mode) - /// @{ - - /// @brief Set instrument filter for receive buffer reads + /// @brief Get detected protocol version for CENTRAL mode /// - /// In CENTRAL_COMPAT mode, Central's receive buffer contains packets from ALL - /// instruments. This filter causes readReceiveBuffer() to only return packets - /// matching the specified instrument index. - /// - /// @param instrument_index 0-based instrument index to filter for, or -1 for no filter (default) - void setInstrumentFilter(int32_t instrument_index); - - /// @brief Get current instrument filter - /// @return Current filter (-1 = no filter) - int32_t getInstrumentFilter() const; - - /// @brief Get detected protocol version for CENTRAL_COMPAT mode - /// - /// In CENTRAL_COMPAT mode, Central may store packets in an older protocol format. - /// This returns the detected protocol version based on procinfo[0].version. - /// Returns CBPROTO_PROTOCOL_CURRENT for CENTRAL and NATIVE layouts. + /// In CENTRAL mode, Central may store packets in an older protocol format. + /// This returns the detected protocol version based on Central's executable + /// file. Returns CBPROTO_PROTOCOL_CURRENT for the NATIVE layout. /// /// @return Detected protocol version cbproto_protocol_version_t getCompatProtocolVersion() const; - /// @} - /////////////////////////////////////////////////////////////////////////// /// @name Receive Buffer Access (Ring Buffer for Incoming Packets) /// @{ @@ -495,9 +468,9 @@ class ShmemSession { /// @brief Get last timestamp from receive buffer (always nanoseconds) /// /// Returns the most recent packet timestamp written to the receive buffer. - /// In CENTRAL_COMPAT mode with a non-Gemini device the raw value (clock - /// ticks) is converted to nanoseconds using sysfreq, so callers always - /// receive a uniform nanosecond timestamp. + /// In CENTRAL mode with a non-Gemini device the raw value (clock ticks) + /// is converted to nanoseconds using sysfreq, so callers always receive a + /// uniform nanosecond timestamp. /// /// @return Last timestamp in nanoseconds, or 0 if receive buffer not initialized PROCTIME getLastTime() const; diff --git a/src/cbshm/src/central_adapters/v3_11.cpp b/src/cbshm/src/central_adapters/v3_11.cpp index 3a54b14b..4c2cbf17 100644 --- a/src/cbshm/src/central_adapters/v3_11.cpp +++ b/src/cbshm/src/central_adapters/v3_11.cpp @@ -8,7 +8,6 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// #include -#include #include namespace cbshm { @@ -43,8 +42,987 @@ size_t BootstrapAdapter::getReceiveBufferLen() const { return sizeof(cbRECBUFFLEN); } -Adapter::Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) - : cfg(static_cast(cfg_ptr)) +::cbPKT_HEADER Adapter::fromLegacy(const cbPKT_HEADER& leg) const { + ::cbPKT_HEADER cur{}; + cur.time = leg.time; // TODO: explicit or implicit conversion here (?) (and for all PROCTIME) + cur.chid = leg.chid; + cur.type = static_cast(leg.type); + cur.dlen = static_cast(leg.dlen); + cur.instrument = 0; + cur.reserved = 0; + return cur; +} + +::cbPKT_SYSINFO Adapter::fromLegacy(const cbPKT_SYSINFO& leg) const { + ::cbPKT_SYSINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.sysfreq = leg.sysfreq; + cur.spikelen = leg.spikelen; + cur.spikepre = leg.spikepre; + cur.resetque = leg.resetque; + cur.runlevel = leg.runlevel; + cur.runflags = leg.runflags; + return cur; +} + +::cbPKT_PROCINFO Adapter::fromLegacy(const cbPKT_PROCINFO& leg) const { + ::cbPKT_PROCINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.idcode = leg.idcode; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; + cur.bankcount = leg.bankcount; + cur.groupcount = leg.groupcount; + cur.filtcount = leg.filtcount; + cur.sortcount = leg.sortcount; + cur.unitcount = leg.unitcount; + cur.hoopcount = leg.hoopcount; + cur.reserved = leg.sortmethod; + cur.version = leg.version; + return cur; +} + +::cbPKT_BANKINFO Adapter::fromLegacy(const cbPKT_BANKINFO& leg) const { + ::cbPKT_BANKINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + copyArr(cur.label, leg.label); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; + return cur; +} + +::cbPKT_GROUPINFO Adapter::fromLegacy(const cbPKT_GROUPINFO& leg) const { + ::cbPKT_GROUPINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.group = leg.group; + copyArr(cur.label, leg.label); + cur.period = leg.period; + cur.length = leg.length; + copyArr(cur.list, leg.list); + return cur; +} + +::cbPKT_FILTINFO Adapter::fromLegacy(const cbPKT_FILTINFO& leg) const { + ::cbPKT_FILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.filt = leg.filt; + copyArr(cur.label, leg.label); + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; + cur.gain = leg.gain; + cur.sos1a1 = leg.sos1a1; + cur.sos1a2 = leg.sos1a2; + cur.sos1b1 = leg.sos1b1; + cur.sos1b2 = leg.sos1b2; + cur.sos2a1 = leg.sos2a1; + cur.sos2a2 = leg.sos2a2; + cur.sos2b1 = leg.sos2b1; + cur.sos2b2 = leg.sos2b2; + return cur; +} + +::cbPKT_ADAPTFILTINFO Adapter::fromLegacy(const cbPKT_ADAPTFILTINFO& leg) const { + ::cbPKT_ADAPTFILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.dLearningRate = leg.dLearningRate; + cur.nRefChan1 = leg.nRefChan1; + cur.nRefChan2 = leg.nRefChan2; + return cur; +} + +::cbPKT_REFELECFILTINFO Adapter::fromLegacy(const cbPKT_REFELECFILTINFO& leg) const { + ::cbPKT_REFELECFILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.nRefChan = leg.nRefChan; + return cur; +} + +::cbSCALING Adapter::fromLegacy(const cbSCALING& leg) const { + ::cbSCALING cur{}; + cur.digmin = leg.digmin; + cur.digmax = leg.digmax; + cur.anamin = leg.anamin; + cur.anamax = leg.anamax; + cur.anagain = leg.anagain; + copyArr(cur.anaunit, leg.anaunit); + return cur; +} + +::cbFILTDESC Adapter::fromLegacy(const cbFILTDESC& leg) const { + ::cbFILTDESC cur{}; + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; + return cur; +} + +::cbMANUALUNITMAPPING Adapter::fromLegacy(const cbMANUALUNITMAPPING& leg) const { + ::cbMANUALUNITMAPPING cur{}; + cur.nOverride = leg.nOverride; + copyArr(cur.afOrigin, leg.afOrigin); + copyArr2D(cur.afShape, leg.afShape); + cur.aPhi = leg.aPhi; + cur.bValid = leg.bValid; + return cur; +} + +::cbHOOP Adapter::fromLegacy(const cbHOOP& leg) const { + ::cbHOOP cur{}; + cur.valid = leg.valid; + cur.time = leg.time; + cur.min = leg.min; + cur.max = leg.max; + return cur; +} + +::cbPKT_CHANINFO Adapter::fromLegacy(const cbPKT_CHANINFO& leg) const { + ::cbPKT_CHANINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.term = leg.term; + cur.chancaps = leg.chancaps; + cur.doutcaps = leg.doutcaps; + cur.dinpcaps = leg.dinpcaps; + cur.aoutcaps = leg.aoutcaps; + cur.ainpcaps = leg.ainpcaps; + cur.spkcaps = leg.spkcaps; + cur.physcalin = fromLegacy(leg.physcalin); + cur.phyfiltin = fromLegacy(leg.phyfiltin); + cur.physcalout = fromLegacy(leg.physcalout); + cur.phyfiltout = fromLegacy(leg.phyfiltout); + copyArr(cur.label, leg.label); + cur.userflags = leg.userflags; + copyArr(cur.position, leg.position); + cur.scalin = fromLegacy(leg.scalin); + cur.scalout = fromLegacy(leg.scalout); + cur.doutopts = leg.doutopts; + cur.dinpopts = leg.dinpopts; + cur.aoutopts = leg.aoutopts; + cur.eopchar = leg.eopchar; + cur.moninst = static_cast((leg.monsource >> 16) & 0xFFFF); // aka lowsamples + cur.monchan = static_cast(leg.monsource & 0xFFFF); // aka highsamples + cur.outvalue = leg.outvalue; // aka offset + cur.trigtype = leg.trigtype; + // skip reserved + cur.triginst = 0; // TODO: VERIFY + cur.trigchan = leg.trigchan; + cur.trigval = leg.trigval; + cur.ainpopts = leg.ainpopts; + cur.lncrate = leg.lncrate; + cur.smpfilter = leg.smpfilter; + cur.smpgroup = leg.smpgroup; + cur.smpdispmin = leg.smpdispmin; + cur.smpdispmax = leg.smpdispmax; + cur.spkfilter = leg.spkfilter; + cur.spkdispmax = leg.spkdispmax; + cur.lncdispmax = leg.lncdispmax; + cur.spkopts = leg.spkopts; + cur.spkthrlevel = leg.spkthrlevel; + cur.spkthrlimit = leg.spkthrlimit; + cur.spkgroup = leg.spkgroup; + cur.amplrejpos = leg.amplrejpos; + cur.amplrejneg = leg.amplrejneg; + cur.refelecchan = leg.refelecchan; + copyArr(cur.unitmapping, leg.unitmapping, this, &Adapter::fromLegacy); + copyArr2D(cur.spkhoops, leg.spkhoops, this, &Adapter::fromLegacy); + return cur; +} + +::cbPKT_FS_BASIS Adapter::fromLegacy(const cbPKT_FS_BASIS& leg) const { + ::cbPKT_FS_BASIS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.fs = leg.fs; + copyArr2D(cur.basis, leg.basis); + return cur; +} + +::cbPKT_SS_MODELSET Adapter::fromLegacy(const cbPKT_SS_MODELSET& leg) const { + ::cbPKT_SS_MODELSET cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.unit_number = leg.unit_number; + cur.valid = leg.valid; + cur.inverted = leg.inverted; + cur.num_samples = leg.num_samples; + copyArr(cur.mu_x, leg.mu_x); + copyArr2D(cur.Sigma_x, leg.Sigma_x); + cur.determinant_Sigma_x = leg.determinant_Sigma_x; + copyArr2D(cur.Sigma_x_inv, leg.Sigma_x_inv); + cur.log_determinant_Sigma_x = leg.log_determinant_Sigma_x; + cur.subcluster_spread_factor_numerator = leg.subcluster_spread_factor_numerator; + cur.subcluster_spread_factor_denominator = leg.subcluster_spread_factor_denominator; + cur.mu_e = leg.mu_e; + cur.sigma_e_squared = leg.sigma_e_squared; + return cur; +} + +::cbPKT_SS_DETECT Adapter::fromLegacy(const cbPKT_SS_DETECT& leg) const { + ::cbPKT_SS_DETECT cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.fThreshold = leg.fThreshold; + cur.fMultiplier = leg.fMultiplier; + return cur; +} + +::cbPKT_SS_ARTIF_REJECT Adapter::fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) const { + ::cbPKT_SS_ARTIF_REJECT cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.nMaxSimulChans = leg.nMaxSimulChans; + cur.nRefractoryCount = leg.nRefractoryCount; + return cur; +} + +::cbPKT_SS_NOISE_BOUNDARY Adapter::fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) const { + ::cbPKT_SS_NOISE_BOUNDARY cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + copyArr(cur.afc, leg.afc); + copyArr2D(cur.afS, leg.afS); + return cur; +} + +::cbPKT_SS_STATISTICS Adapter::fromLegacy(const cbPKT_SS_STATISTICS& leg) const { + ::cbPKT_SS_STATISTICS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.nUpdateSpikes = leg.nUpdateSpikes; + cur.nAutoalg = leg.nAutoalg; + cur.nMode = leg.nMode; + cur.fMinClusterPairSpreadFactor = leg.fMinClusterPairSpreadFactor; + cur.fMaxSubclusterSpreadFactor = leg.fMaxSubclusterSpreadFactor; + cur.fMinClusterHistCorrMajMeasure = leg.fMinClusterHistCorrMajMeasure; + cur.fMaxClusterPairHistCorrMajMeasure = leg.fMaxClusterPairHistCorrMajMeasure; + cur.fClusterHistValleyPercentage = leg.fClusterHistValleyPercentage; + cur.fClusterHistClosePeakPercentage = leg.fClusterHistClosePeakPercentage; + cur.fClusterHistMinPeakPercentage = leg.fClusterHistMinPeakPercentage; + cur.nWaveBasisSize = leg.nWaveBasisSize; + cur.nWaveSampleSize = leg.nWaveSampleSize; + return cur; +} + +::cbAdaptControl Adapter::fromLegacy(const cbAdaptControl& leg) const { + ::cbAdaptControl cur{}; + cur.nMode = leg.nMode; + cur.fTimeOutMinutes = leg.fTimeOutMinutes; + cur.fElapsedMinutes = leg.fElapsedMinutes; + return cur; +} + +::cbPKT_SS_STATUS Adapter::fromLegacy(const cbPKT_SS_STATUS& leg) const { + ::cbPKT_SS_STATUS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats); + cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits); + return cur; +} + +::cbproto::SpikeSorting Adapter::fromLegacy(const cbSPIKE_SORTING& leg) const { + ::cbproto::SpikeSorting cur{}; + copyArr(cur.basis, leg.asBasis, this, &Adapter::fromLegacy); + copyArr2D(cur.models, leg.asSortModel, this, &Adapter::fromLegacy); + cur.detect = fromLegacy(leg.pktDetect); + cur.artifact_reject = fromLegacy(leg.pktArtifReject); + copyArr(cur.noise_boundary, leg.pktNoiseBoundary, this, &Adapter::fromLegacy); + cur.statistics = fromLegacy(leg.pktStatistics); + cur.status = fromLegacy(leg.pktStatus); + return cur; +} + +::cbPKT_NTRODEINFO Adapter::fromLegacy(const cbPKT_NTRODEINFO& leg) const { + ::cbPKT_NTRODEINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.ntrode = leg.ntrode; + copyArr(cur.label, leg.label); + copyArr2D(cur.ellipses, leg.ellipses, this, &Adapter::fromLegacy); + cur.nSite = leg.nSite; + cur.fs = leg.fs; + copyArr(cur.nChan, leg.nChan); + return cur; +} + +::cbWaveformData Adapter::fromLegacy(const cbWaveformData& leg) const { + ::cbWaveformData cur{}; + cur.offset = leg.offset; // aka sineFrequency + cur.seq = leg.seq; // aka sineAmplitude + cur.seqTotal = leg.seqTotal; + cur.phases = leg.phases; + copyArr(cur.duration, leg.duration); + copyArr(cur.amplitude, leg.amplitude); + return cur; +} + +::cbPKT_AOUT_WAVEFORM Adapter::fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const { + ::cbPKT_AOUT_WAVEFORM cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.repeats = leg.repeats; + cur.trig = static_cast((leg.trig >> 8) & 0xFF); + cur.trigInst = static_cast(leg.trig & 0xFF); + cur.trigChan = leg.trigChan; + cur.trigValue = leg.trigValue; + cur.trigNum = leg.trigNum; + cur.active = leg.active; + cur.wave = fromLegacy(leg.wave); + return cur; +} + +::cbPKT_LNC Adapter::fromLegacy(const cbPKT_LNC& leg) const { + ::cbPKT_LNC cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.lncFreq = leg.lncFreq; + cur.lncRefChan = leg.lncRefChan; + cur.lncGlobalMode = leg.lncGlobalMode; + return cur; +} + +::cbPKT_NPLAY Adapter::fromLegacy(const cbPKT_NPLAY& leg) const { + ::cbPKT_NPLAY cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.ftime = leg.ftime; // aka opt + cur.stime = leg.stime; + cur.etime = leg.etime; + cur.val = leg.val; + cur.mode = leg.mode; + cur.flags = leg.flags; + cur.speed = leg.speed; + copyArr(cur.fname, leg.fname); + return cur; +} + +::cbVIDEOSOURCE Adapter::fromLegacy(const cbVIDEOSOURCE& leg) const { + ::cbVIDEOSOURCE cur{}; + copyArr(cur.name, leg.name); + cur.fps = leg.fps; + return cur; +} + +::cbTRACKOBJ Adapter::fromLegacy(const cbTRACKOBJ& leg) const { + ::cbTRACKOBJ cur{}; + copyArr(cur.name, leg.name); + cur.type = leg.type; + cur.pointCount = leg.pointCount; + return cur; +} + +::cbPKT_FILECFG Adapter::fromLegacy(const cbPKT_FILECFG& leg) const { + ::cbPKT_FILECFG cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.options = leg.options; + cur.duration = leg.duration; + cur.recording = leg.recording; + cur.extctrl = leg.extctrl; + copyArr(cur.username, leg.username); + copyArr(cur.filename, leg.filename); // aka datetime + copyArr(cur.comment, leg.comment); + return cur; +} + +NativeConfigBuffer Adapter::fromLegacy(const cbCFGBUFF& leg) const { + // TODO: VERIFY that each list that's assumed to be instrument-independent is in fact independent from any particular instrument. + NativeConfigBuffer cur{}; + cur.version = leg.version; + cur.sysflags = leg.sysflags; + cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); + cur.sysinfo = fromLegacy(leg.sysinfo); + cur.procinfo = fromLegacy(leg.procinfo[instrument_idx]); + copyArr(cur.bankinfo, leg.bankinfo[instrument_idx], this, &Adapter::fromLegacy); + copyArr(cur.groupinfo, leg.groupinfo[instrument_idx], this, &Adapter::fromLegacy); + copyArr(cur.filtinfo, leg.filtinfo[instrument_idx], this, &Adapter::fromLegacy); + cur.adaptinfo = fromLegacy(leg.adaptinfo[instrument_idx]); + cur.refelecinfo = fromLegacy(leg.refelecinfo[instrument_idx]); + copyArr(cur.chaninfo, leg.chaninfo, this, &Adapter::fromLegacy); + copyArr(cur.asBasis, leg.isSortingOptions.asBasis, this, &Adapter::fromLegacy); + copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); + // TODO: Move native isSortingOptions fields into a struct + cur.pktDetect = fromLegacy(leg.isSortingOptions.pktDetect); + cur.pktArtifReject = fromLegacy(leg.isSortingOptions.pktArtifReject); + copyArr(cur.pktNoiseBoundary, leg.isSortingOptions.pktNoiseBoundary, this, &Adapter::fromLegacy); + cur.pktStatistics = fromLegacy(leg.isSortingOptions.pktStatistics); + cur.pktStatus = fromLegacy(leg.isSortingOptions.pktStatus); + copyArr(cur.isNTrodeInfo, leg.isNTrodeInfo, this, &Adapter::fromLegacy); + copyArr2D(cur.isWaveform, leg.isWaveform, this, &Adapter::fromLegacy); + cur.isLnc = fromLegacy(leg.isLnc[instrument_idx]); + cur.isNPlay = fromLegacy(leg.isNPlay); + copyArr(cur.isVideoSource, leg.isVideoSource, this, &Adapter::fromLegacy); + copyArr(cur.isTrackObj, leg.isTrackObj, this, &Adapter::fromLegacy); + cur.fileinfo = fromLegacy(leg.fileinfo); + + return cur; +} + +NativeNSPStatus Adapter::fromLegacy(const NSPStatus& leg) const { + switch(leg) { + case NSPStatus::NSP_INIT: + return NativeNSPStatus::NSP_INIT; + case NSPStatus::NSP_NOIPADDR: + return NativeNSPStatus::NSP_NOIPADDR; + case NSPStatus::NSP_NOREPLY: + return NativeNSPStatus::NSP_NOREPLY; + case NSPStatus::NSP_FOUND: + return NativeNSPStatus::NSP_FOUND; + case NSPStatus::NSP_INVALID: + default: + return NativeNSPStatus::NSP_INVALID; + } +} + +::cbPKT_UNIT_SELECTION Adapter::fromLegacy(const cbPKT_UNIT_SELECTION& leg) const { + ::cbPKT_UNIT_SELECTION cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.lastchan = leg.lastchan; + copyArr(cur.abyUnitSelections, leg.abyUnitSelections); + return cur; +} + +NativePCStatus Adapter::fromLegacy(const cbPcStatus& leg) const { + NativePCStatus cur{}; + cur.isSelection = fromLegacy(leg.isSelection[instrument_idx]); + cur.m_iBlockRecording = leg.m_iBlockRecording; + cur.m_nPCStatusFlags = leg.m_nPCStatusFlags; + cur.m_nNumFEChans = leg.m_nNumFEChans; + cur.m_nNumAnainChans = leg.m_nNumAnainChans; + cur.m_nNumAnalogChans = leg.m_nNumAnalogChans; + cur.m_nNumAoutChans = leg.m_nNumAoutChans; + cur.m_nNumAudioChans = leg.m_nNumAudioChans; + cur.m_nNumAnalogoutChans = leg.m_nNumAnalogoutChans; + cur.m_nNumDiginChans = leg.m_nNumDiginChans; + cur.m_nNumSerialChans = leg.m_nNumSerialChans; + cur.m_nNumDigoutChans = leg.m_nNumDigoutChans; + cur.m_nNumTotalChans = leg.m_nNumTotalChans; + cur.m_nNspStatus = NativeNSPStatus::NSP_FOUND; // TODO: VERIFY + cur.m_nNumNTrodesPerInstrument = cbMAXNTRODES; // TODO: VERIFY + cur.m_nGeminiSystem = 1; // TODO: VERIFY + // ignore APP_WORKSPACE + return cur; +} + +NativeReceiveBuffer Adapter::fromLegacy(const cbRECBUFF& leg) const { + NativeReceiveBuffer cur{}; + cur.received = leg.received; + cur.lasttime = leg.lasttime; + cur.headwrap = leg.headwrap; + cur.headindex = leg.headindex; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +NativeTransmitBuffer Adapter::fromLegacy(const cbXMTBUFF& leg) const { + NativeTransmitBuffer cur{}; + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +NativeTransmitBufferLocal Adapter::fromLegacy(const cbXMTBUFFLOCAL& leg) const { + NativeTransmitBufferLocal cur{}; + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +cbPKT_HEADER Adapter::toLegacy(const ::cbPKT_HEADER& cur) const { + cbPKT_HEADER leg{}; + leg.time = cur.time; + leg.chid = cur.chid; + leg.type = static_cast(cur.type); + leg.dlen = static_cast(cur.dlen); + return leg; +} + +cbPKT_SYSINFO Adapter::toLegacy(const ::cbPKT_SYSINFO& cur) const { + cbPKT_SYSINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.sysfreq = cur.sysfreq; + leg.spikelen = cur.spikelen; + leg.spikepre = cur.spikepre; + leg.resetque = cur.resetque; + leg.runlevel = cur.runlevel; + leg.runflags = cur.runflags; + return leg; +} + +cbPKT_PROCINFO Adapter::toLegacy(const ::cbPKT_PROCINFO& cur) const { + cbPKT_PROCINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.idcode = cur.idcode; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; + leg.bankcount = cur.bankcount; + leg.groupcount = cur.groupcount; + leg.filtcount = cur.filtcount; + leg.sortcount = cur.sortcount; + leg.unitcount = cur.unitcount; + leg.hoopcount = cur.hoopcount; + leg.sortmethod = cur.reserved; + leg.version = cur.version; + return leg; +} + +cbPKT_BANKINFO Adapter::toLegacy(const ::cbPKT_BANKINFO& cur) const { + cbPKT_BANKINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + copyArr(leg.label, cur.label); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; + return leg; +} + +cbPKT_GROUPINFO Adapter::toLegacy(const ::cbPKT_GROUPINFO& cur) const { + cbPKT_GROUPINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.group = cur.group; + copyArr(leg.label, cur.label); + leg.period = cur.period; + leg.length = cur.length; + copyArr(leg.list, cur.list); + return leg; +} + +cbPKT_FILTINFO Adapter::toLegacy(const ::cbPKT_FILTINFO& cur) const { + cbPKT_FILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.filt = cur.filt; + copyArr(leg.label, cur.label); + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; + leg.gain = cur.gain; + leg.sos1a1 = cur.sos1a1; + leg.sos1a2 = cur.sos1a2; + leg.sos1b1 = cur.sos1b1; + leg.sos1b2 = cur.sos1b2; + leg.sos2a1 = cur.sos2a1; + leg.sos2a2 = cur.sos2a2; + leg.sos2b1 = cur.sos2b1; + leg.sos2b2 = cur.sos2b2; + return leg; +} + +cbPKT_ADAPTFILTINFO Adapter::toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) const { + cbPKT_ADAPTFILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.dLearningRate = cur.dLearningRate; + leg.nRefChan1 = cur.nRefChan1; + leg.nRefChan2 = cur.nRefChan2; + return leg; +} + +cbPKT_REFELECFILTINFO Adapter::toLegacy(const ::cbPKT_REFELECFILTINFO& cur) const { + cbPKT_REFELECFILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.nRefChan = cur.nRefChan; + return leg; +} + +cbSCALING Adapter::toLegacy(const ::cbSCALING& cur) const { + cbSCALING leg{}; + leg.digmin = cur.digmin; + leg.digmax = cur.digmax; + leg.anamin = cur.anamin; + leg.anamax = cur.anamax; + leg.anagain = cur.anagain; + copyArr(leg.anaunit, cur.anaunit); + return leg; +} + +cbFILTDESC Adapter::toLegacy(const ::cbFILTDESC& cur) const { + cbFILTDESC leg{}; + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; + return leg; +} + +cbMANUALUNITMAPPING Adapter::toLegacy(const ::cbMANUALUNITMAPPING& cur) const { + cbMANUALUNITMAPPING leg{}; + leg.nOverride = cur.nOverride; + copyArr(leg.afOrigin, cur.afOrigin); + copyArr2D(leg.afShape, cur.afShape); + leg.aPhi = cur.aPhi; + leg.bValid = cur.bValid; + return leg; +} + +cbHOOP Adapter::toLegacy(const ::cbHOOP& cur) const { + cbHOOP leg{}; + leg.valid = cur.valid; + leg.time = cur.time; + leg.min = cur.min; + leg.max = cur.max; + return leg; +} + +cbPKT_CHANINFO Adapter::toLegacy(const ::cbPKT_CHANINFO& cur) const { + cbPKT_CHANINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.term = cur.term; + leg.chancaps = cur.chancaps; + leg.doutcaps = cur.doutcaps; + leg.dinpcaps = cur.dinpcaps; + leg.aoutcaps = cur.aoutcaps; + leg.ainpcaps = cur.ainpcaps; + leg.spkcaps = cur.spkcaps; + leg.physcalin = toLegacy(cur.physcalin); + leg.phyfiltin = toLegacy(cur.phyfiltin); + leg.physcalout = toLegacy(cur.physcalout); + leg.phyfiltout = toLegacy(cur.phyfiltout); + copyArr(leg.label, cur.label); + leg.userflags = cur.userflags; + copyArr(leg.position, cur.position); + leg.scalin = toLegacy(cur.scalin); + leg.scalout = toLegacy(cur.scalout); + leg.doutopts = cur.doutopts; + leg.dinpopts = cur.dinpopts; + leg.aoutopts = cur.aoutopts; + leg.eopchar = cur.eopchar; + leg.monsource = (static_cast(cur.moninst) << 16) | static_cast(cur.monchan); // aka highsamples and lowsamples + leg.outvalue = cur.outvalue; // aka offset + leg.trigtype = cur.trigtype; + leg.trigchan = cur.trigchan; + leg.trigval = cur.trigval; + leg.ainpopts = cur.ainpopts; + leg.lncrate = cur.lncrate; + leg.smpfilter = cur.smpfilter; + leg.smpgroup = cur.smpgroup; + leg.smpdispmin = cur.smpdispmin; + leg.smpdispmax = cur.smpdispmax; + leg.spkfilter = cur.spkfilter; + leg.spkdispmax = cur.spkdispmax; + leg.lncdispmax = cur.lncdispmax; + leg.spkopts = cur.spkopts; + leg.spkthrlevel = cur.spkthrlevel; + leg.spkthrlimit = cur.spkthrlimit; + leg.spkgroup = cur.spkgroup; + leg.amplrejpos = cur.amplrejpos; + leg.amplrejneg = cur.amplrejneg; + leg.refelecchan = cur.refelecchan; + copyArr(leg.unitmapping, cur.unitmapping, this, &Adapter::toLegacy); + copyArr2D(leg.spkhoops, cur.spkhoops, this, &Adapter::toLegacy); + return leg; +} + +cbPKT_FS_BASIS Adapter::toLegacy(const ::cbPKT_FS_BASIS& cur) const { + cbPKT_FS_BASIS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.fs = cur.fs; + copyArr2D(leg.basis, cur.basis); + return leg; +} + +cbPKT_SS_MODELSET Adapter::toLegacy(const ::cbPKT_SS_MODELSET& cur) const { + cbPKT_SS_MODELSET leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.unit_number = cur.unit_number; + leg.valid = cur.valid; + leg.inverted = cur.inverted; + leg.num_samples = cur.num_samples; + copyArr(leg.mu_x, cur.mu_x); + copyArr2D(leg.Sigma_x, cur.Sigma_x); + leg.determinant_Sigma_x = cur.determinant_Sigma_x; + copyArr2D(leg.Sigma_x_inv, cur.Sigma_x_inv); + leg.log_determinant_Sigma_x = cur.log_determinant_Sigma_x; + leg.subcluster_spread_factor_numerator = cur.subcluster_spread_factor_numerator; + leg.subcluster_spread_factor_denominator = cur.subcluster_spread_factor_denominator; + leg.mu_e = cur.mu_e; + leg.sigma_e_squared = cur.sigma_e_squared; + return leg; +} + +cbPKT_SS_DETECT Adapter::toLegacy(const ::cbPKT_SS_DETECT& cur) const { + cbPKT_SS_DETECT leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.fThreshold = cur.fThreshold; + leg.fMultiplier = cur.fMultiplier; + return leg; +} + +cbPKT_SS_ARTIF_REJECT Adapter::toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) const { + cbPKT_SS_ARTIF_REJECT leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.nMaxSimulChans = cur.nMaxSimulChans; + leg.nRefractoryCount = cur.nRefractoryCount; + return leg; +} + +cbPKT_SS_NOISE_BOUNDARY Adapter::toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) const { + cbPKT_SS_NOISE_BOUNDARY leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + copyArr(leg.afc, cur.afc); + copyArr2D(leg.afS, cur.afS); + return leg; +} + +cbPKT_SS_STATISTICS Adapter::toLegacy(const ::cbPKT_SS_STATISTICS& cur) const { + cbPKT_SS_STATISTICS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.nUpdateSpikes = cur.nUpdateSpikes; + leg.nAutoalg = cur.nAutoalg; + leg.nMode = cur.nMode; + leg.fMinClusterPairSpreadFactor = cur.fMinClusterPairSpreadFactor; + leg.fMaxSubclusterSpreadFactor = cur.fMaxSubclusterSpreadFactor; + leg.fMinClusterHistCorrMajMeasure = cur.fMinClusterHistCorrMajMeasure; + leg.fMaxClusterPairHistCorrMajMeasure = cur.fMaxClusterPairHistCorrMajMeasure; + leg.fClusterHistValleyPercentage = cur.fClusterHistValleyPercentage; + leg.fClusterHistClosePeakPercentage = cur.fClusterHistClosePeakPercentage; + leg.fClusterHistMinPeakPercentage = cur.fClusterHistMinPeakPercentage; + leg.nWaveBasisSize = cur.nWaveBasisSize; + leg.nWaveSampleSize = cur.nWaveSampleSize; + return leg; +} + +cbAdaptControl Adapter::toLegacy(const ::cbAdaptControl& cur) const { + cbAdaptControl leg{}; + leg.nMode = cur.nMode; + leg.fTimeOutMinutes = cur.fTimeOutMinutes; + leg.fElapsedMinutes = cur.fElapsedMinutes; + return leg; +} + +cbPKT_SS_STATUS Adapter::toLegacy(const ::cbPKT_SS_STATUS& cur) const { + cbPKT_SS_STATUS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cntlUnitStats = toLegacy(cur.cntlUnitStats); + leg.cntlNumUnits = toLegacy(cur.cntlNumUnits); + return leg; +} + +cbSPIKE_SORTING Adapter::toLegacy(const ::cbproto::SpikeSorting& cur) const { + cbSPIKE_SORTING leg{}; + copyArr(leg.asBasis, cur.basis, this, &Adapter::toLegacy); + copyArr2D(leg.asSortModel, cur.models, this, &Adapter::toLegacy); + leg.pktDetect = toLegacy(cur.detect); + leg.pktArtifReject = toLegacy(cur.artifact_reject); + copyArr(leg.pktNoiseBoundary, cur.noise_boundary, this, &Adapter::toLegacy); + leg.pktStatistics = toLegacy(cur.statistics); + leg.pktStatus = toLegacy(cur.status); + return leg; +} + +cbPKT_NTRODEINFO Adapter::toLegacy(const ::cbPKT_NTRODEINFO& cur) const { + cbPKT_NTRODEINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.ntrode = cur.ntrode; + copyArr(leg.label, cur.label); + copyArr2D(leg.ellipses, cur.ellipses, this, &Adapter::toLegacy); + leg.nSite = cur.nSite; + leg.fs = cur.fs; + copyArr(leg.nChan, cur.nChan); + return leg; +} + +cbWaveformData Adapter::toLegacy(const ::cbWaveformData& cur) const { + cbWaveformData leg{}; + leg.offset = cur.offset; // aka sineFrequency + leg.seq = cur.seq; // aka sineAmplitude + leg.seqTotal = cur.seqTotal; + leg.phases = cur.phases; + copyArr(leg.duration, cur.duration); + copyArr(leg.amplitude, cur.amplitude); + return leg; +} + +cbPKT_AOUT_WAVEFORM Adapter::toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const { + cbPKT_AOUT_WAVEFORM leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.repeats = cur.repeats; + leg.trig = (static_cast(cur.trig) << 8) | static_cast(cur.trigInst); + leg.trigChan = cur.trigChan; + leg.trigValue = cur.trigValue; + leg.trigNum = cur.trigNum; + leg.active = cur.active; + leg.wave = toLegacy(cur.wave); + return leg; +} + +cbPKT_LNC Adapter::toLegacy(const ::cbPKT_LNC& cur) const { + cbPKT_LNC leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.lncFreq = cur.lncFreq; + leg.lncRefChan = cur.lncRefChan; + leg.lncGlobalMode = cur.lncGlobalMode; + return leg; +} + +cbPKT_NPLAY Adapter::toLegacy(const ::cbPKT_NPLAY& cur) const { + cbPKT_NPLAY leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.ftime = cur.ftime; // aka opt + leg.stime = cur.stime; + leg.etime = cur.etime; + leg.val = cur.val; + leg.mode = cur.mode; + leg.flags = cur.flags; + leg.speed = cur.speed; + copyArr(leg.fname, cur.fname); + return leg; +} + +cbVIDEOSOURCE Adapter::toLegacy(const ::cbVIDEOSOURCE& cur) const { + cbVIDEOSOURCE leg{}; + copyArr(leg.name, cur.name); + leg.fps = cur.fps; + return leg; +} + +cbTRACKOBJ Adapter::toLegacy(const ::cbTRACKOBJ& cur) const { + cbTRACKOBJ leg{}; + copyArr(leg.name, cur.name); + leg.type = cur.type; + leg.pointCount = cur.pointCount; + return leg; +} + +cbPKT_FILECFG Adapter::toLegacy(const ::cbPKT_FILECFG& cur) const { + cbPKT_FILECFG leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.options = cur.options; + leg.duration = cur.duration; + leg.recording = cur.recording; + leg.extctrl = cur.extctrl; + copyArr(leg.username, cur.username); + copyArr(leg.filename, cur.filename); // aka datetime + copyArr(leg.comment, cur.comment); + return leg; +} + +NSPStatus Adapter::toLegacy(const NativeNSPStatus& cur) const { + switch(cur) { + case NativeNSPStatus::NSP_INIT: + return NSPStatus::NSP_INIT; + case NativeNSPStatus::NSP_NOIPADDR: + return NSPStatus::NSP_NOIPADDR; + case NativeNSPStatus::NSP_NOREPLY: + return NSPStatus::NSP_NOREPLY; + case NativeNSPStatus::NSP_FOUND: + return NSPStatus::NSP_FOUND; + case NativeNSPStatus::NSP_INVALID: + default: + return NSPStatus::NSP_INVALID; + } +} + +cbPKT_UNIT_SELECTION Adapter::toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const { + cbPKT_UNIT_SELECTION leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.lastchan = cur.lastchan; + copyArr(leg.abyUnitSelections, cur.abyUnitSelections); + return leg; +} + +cbPcStatus Adapter::toLegacy(const NativePCStatus& cur) const { + cbPcStatus leg{}; + leg.isSelection[instrument_idx] = toLegacy(cur.isSelection); + leg.m_iBlockRecording = cur.m_iBlockRecording; + leg.m_nPCStatusFlags = cur.m_nPCStatusFlags; + leg.m_nNumFEChans = cur.m_nNumFEChans; + leg.m_nNumAnainChans = cur.m_nNumAnainChans; + leg.m_nNumAnalogChans = cur.m_nNumAnalogChans; + leg.m_nNumAoutChans = cur.m_nNumAoutChans; + leg.m_nNumAudioChans = cur.m_nNumAudioChans; + leg.m_nNumAnalogoutChans = cur.m_nNumAnalogoutChans; + leg.m_nNumDiginChans = cur.m_nNumDiginChans; + leg.m_nNumSerialChans = cur.m_nNumSerialChans; + leg.m_nNumDigoutChans = cur.m_nNumDigoutChans; + leg.m_nNumTotalChans = cur.m_nNumTotalChans; + // ignore APP_WORKSPACE + return leg; +} + +cbRECBUFF Adapter::toLegacy(const NativeReceiveBuffer& cur) const { + cbRECBUFF leg{}; + leg.received = cur.received; + leg.lasttime = cur.lasttime; + leg.headwrap = cur.headwrap; + leg.headindex = cur.headindex; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +cbXMTBUFF Adapter::toLegacy(const NativeTransmitBuffer& cur) const { + cbXMTBUFF leg{}; + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +cbXMTBUFFLOCAL Adapter::toLegacy(const NativeTransmitBufferLocal& cur) const { + cbXMTBUFFLOCAL leg{}; + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +Adapter::Adapter(uint8_t instrument_idx, void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) + : instrument_idx(instrument_idx) + , cfg(static_cast(cfg_ptr)) , rec(static_cast(rec_ptr)) , xmt(static_cast(xmt_ptr)) , xmt_local(static_cast(xmt_local_ptr)) @@ -52,6 +1030,10 @@ Adapter::Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_pt , spike(static_cast(spike_ptr)) {} +uint32_t Adapter::getMaxProcs() const { + return cbMAXPROCS; +} + uint32_t& Adapter::getRecReceived() { return rec->received; } @@ -124,14 +1106,14 @@ uint32_t* Adapter::getLocalXmtBufferPtr() { return xmt->buffer; } -Result<::cbPKT_PROCINFO> Adapter::getProcInfo(uint8_t instrument_idx) const { +Result<::cbPKT_PROCINFO> Adapter::getProcInfo() const { if (instrument_idx >= std::size(cfg->procinfo)) { return Result<::cbPKT_PROCINFO>::error("Instrument index out of range"); } - return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx], {})); + return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx])); } -Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const { +Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint32_t bank_num) const { if (instrument_idx >= std::size(cfg->bankinfo)) { return Result<::cbPKT_BANKINFO>::error("Instrument index out of range"); } @@ -139,10 +1121,10 @@ Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t b if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result<::cbPKT_BANKINFO>::error("Bank number out of range"); } - return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx], {})); + return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx])); } -Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const { +Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint32_t filter_num) const { if (instrument_idx >= std::size(cfg->filtinfo)) { return Result<::cbPKT_FILTINFO>::error("Instrument index out of range"); } @@ -150,53 +1132,53 @@ Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result<::cbPKT_FILTINFO>::error("Filter number out of range"); } - return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx], {})); + return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx])); } Result<::cbPKT_CHANINFO> Adapter::getChanInfo(uint32_t channel_idx) const { if (channel_idx >= std::size(cfg->chaninfo)) { return Result<::cbPKT_CHANINFO>::error("Channel number out of range"); } - return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx], {})); + return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx])); } Result<::cbPKT_SYSINFO> Adapter::getSysInfo() const { - return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo, {})); + return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo)); } -Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const { +Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint32_t group_idx) const { if (instrument_idx >= std::size(cfg->groupinfo)) { return Result<::cbPKT_GROUPINFO>::error("Instrument index out of range"); } if (group_idx >= std::size(cfg->groupinfo[0])) { return Result<::cbPKT_GROUPINFO>::error("Group index out of range"); } - return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx], {})); + return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx])); } -Result Adapter::getConfigBuffer(uint8_t instrument_idx) const { +Result Adapter::getConfigBuffer() const { if (instrument_idx >= std::size(cfg->procinfo)) { return Result::error("Instrument index out of range"); } - return Result::ok(fromLegacy(*cfg, { .instrument_idx = instrument_idx })); + return Result::ok(fromLegacy(*cfg)); } -Result Adapter::getPcStatus(uint8_t instrument_idx) const { +Result Adapter::getPcStatus() const { if (instrument_idx >= std::size(status->isSelection)) { return Result::error("Instrument index out of range"); } - return Result::ok(fromLegacy(*status, { .instrument_idx = instrument_idx })); + return Result::ok(fromLegacy(*status)); } -Result Adapter::setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) { +Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { if (instrument_idx >= std::size(cfg->procinfo)) { return Result::error("Instrument index out of range"); } - cfg->procinfo[instrument_idx] = toLegacy(info, {}); + cfg->procinfo[instrument_idx] = toLegacy(info); return Result::ok(); } -Result Adapter::setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) { +Result Adapter::setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) { if (instrument_idx >= std::size(cfg->bankinfo)) { return Result::error("Instrument index out of range"); } @@ -204,11 +1186,11 @@ Result Adapter::setBankInfo(uint8_t instrument_idx, uint32_t bank_num, con if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result::error("Bank number out of range"); } - cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info, {}); + cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info); return Result::ok(); } -Result Adapter::setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) { +Result Adapter::setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) { if (instrument_idx >= std::size(cfg->filtinfo)) { return Result::error("Instrument index out of range"); } @@ -216,7 +1198,7 @@ Result Adapter::setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result::error("Filter number out of range"); } - cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info, {}); + cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info); return Result::ok(); } @@ -224,31 +1206,31 @@ Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& if (channel_idx >= std::size(cfg->chaninfo)) { return Result::error("Channel number out of range"); } - cfg->chaninfo[channel_idx] = toLegacy(info, {}); + cfg->chaninfo[channel_idx] = toLegacy(info); return Result::ok(); } Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { - cfg->sysinfo = toLegacy(info, {}); + cfg->sysinfo = toLegacy(info); return Result::ok(); } -Result Adapter::setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { +Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { if (instrument_idx >= std::size(cfg->groupinfo)) { return Result::error("Instrument index out of range"); } if (group_idx >= std::size(cfg->groupinfo[0])) { return Result::error("Group index out of range"); } - cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info, {}); + cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info); return Result::ok(); } -Result Adapter::setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const { +Result Adapter::setPcStatus(const NativePCStatus& status) const { if (instrument_idx >= std::size(this->status->isSelection)) { return Result::error("Instrument index out of range"); } - *(this->status) = toLegacy(status, { .instrument_idx = instrument_idx }); + *(this->status) = toLegacy(status); return Result::ok(); } diff --git a/src/cbshm/src/central_adapters/v4_0.cpp b/src/cbshm/src/central_adapters/v4_0.cpp index 5d2da5b3..a61e2ec8 100644 --- a/src/cbshm/src/central_adapters/v4_0.cpp +++ b/src/cbshm/src/central_adapters/v4_0.cpp @@ -8,7 +8,6 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// #include -#include #include namespace cbshm { @@ -43,8 +42,992 @@ size_t BootstrapAdapter::getReceiveBufferLen() const { return sizeof(cbRECBUFFLEN); } -Adapter::Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) - : cfg(static_cast(cfg_ptr)) +::cbPKT_HEADER Adapter::fromLegacy(const cbPKT_HEADER& leg) const { + ::cbPKT_HEADER cur{}; + cur.time = leg.time; + cur.chid = leg.chid; + cur.type = static_cast(leg.type); + cur.dlen = leg.dlen; + cur.instrument = leg.instrument; + cur.reserved = leg.reserved; + return cur; +} + +::cbPKT_SYSINFO Adapter::fromLegacy(const cbPKT_SYSINFO& leg) const { + ::cbPKT_SYSINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.sysfreq = leg.sysfreq; + cur.spikelen = leg.spikelen; + cur.spikepre = leg.spikepre; + cur.resetque = leg.resetque; + cur.runlevel = leg.runlevel; + cur.runflags = leg.runflags; + return cur; +} + +::cbPKT_PROCINFO Adapter::fromLegacy(const cbPKT_PROCINFO& leg) const { + ::cbPKT_PROCINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.idcode = leg.idcode; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; + cur.bankcount = leg.bankcount; + cur.groupcount = leg.groupcount; + cur.filtcount = leg.filtcount; + cur.sortcount = leg.sortcount; + cur.unitcount = leg.unitcount; + cur.hoopcount = leg.hoopcount; + cur.reserved = leg.reserved; + cur.version = leg.version; + return cur; +} + +::cbPKT_BANKINFO Adapter::fromLegacy(const cbPKT_BANKINFO& leg) const { + ::cbPKT_BANKINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + copyArr(cur.label, leg.label); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; + return cur; +} + +::cbPKT_GROUPINFO Adapter::fromLegacy(const cbPKT_GROUPINFO& leg) const { + ::cbPKT_GROUPINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.group = leg.group; + copyArr(cur.label, leg.label); + cur.period = leg.period; + cur.length = leg.length; + copyArr(cur.list, leg.list); + return cur; +} + +::cbPKT_FILTINFO Adapter::fromLegacy(const cbPKT_FILTINFO& leg) const { + ::cbPKT_FILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.filt = leg.filt; + copyArr(cur.label, leg.label); + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; + cur.gain = leg.gain; + cur.sos1a1 = leg.sos1a1; + cur.sos1a2 = leg.sos1a2; + cur.sos1b1 = leg.sos1b1; + cur.sos1b2 = leg.sos1b2; + cur.sos2a1 = leg.sos2a1; + cur.sos2a2 = leg.sos2a2; + cur.sos2b1 = leg.sos2b1; + cur.sos2b2 = leg.sos2b2; + return cur; +} + +::cbPKT_ADAPTFILTINFO Adapter::fromLegacy(const cbPKT_ADAPTFILTINFO& leg) const { + ::cbPKT_ADAPTFILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.dLearningRate = leg.dLearningRate; + cur.nRefChan1 = leg.nRefChan1; + cur.nRefChan2 = leg.nRefChan2; + return cur; +} + +::cbPKT_REFELECFILTINFO Adapter::fromLegacy(const cbPKT_REFELECFILTINFO& leg) const { + ::cbPKT_REFELECFILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.nRefChan = leg.nRefChan; + return cur; +} + +::cbSCALING Adapter::fromLegacy(const cbSCALING& leg) const { + ::cbSCALING cur{}; + cur.digmin = leg.digmin; + cur.digmax = leg.digmax; + cur.anamin = leg.anamin; + cur.anamax = leg.anamax; + cur.anagain = leg.anagain; + copyArr(cur.anaunit, leg.anaunit); + return cur; +} + +::cbFILTDESC Adapter::fromLegacy(const cbFILTDESC& leg) const { + ::cbFILTDESC cur{}; + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; + return cur; +} + +::cbMANUALUNITMAPPING Adapter::fromLegacy(const cbMANUALUNITMAPPING& leg) const { + ::cbMANUALUNITMAPPING cur{}; + cur.nOverride = leg.nOverride; + copyArr(cur.afOrigin, leg.afOrigin); + copyArr2D(cur.afShape, leg.afShape); + cur.aPhi = leg.aPhi; + cur.bValid = leg.bValid; + return cur; +} + +::cbHOOP Adapter::fromLegacy(const cbHOOP& leg) const { + ::cbHOOP cur{}; + cur.valid = leg.valid; + cur.time = leg.time; + cur.min = leg.min; + cur.max = leg.max; + return cur; +} + +::cbPKT_CHANINFO Adapter::fromLegacy(const cbPKT_CHANINFO& leg) const { + ::cbPKT_CHANINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.term = leg.term; + cur.chancaps = leg.chancaps; + cur.doutcaps = leg.doutcaps; + cur.dinpcaps = leg.dinpcaps; + cur.aoutcaps = leg.aoutcaps; + cur.ainpcaps = leg.ainpcaps; + cur.spkcaps = leg.spkcaps; + cur.physcalin = fromLegacy(leg.physcalin); + cur.phyfiltin = fromLegacy(leg.phyfiltin); + cur.physcalout = fromLegacy(leg.physcalout); + cur.phyfiltout = fromLegacy(leg.phyfiltout); + copyArr(cur.label, leg.label); + cur.userflags = leg.userflags; + copyArr(cur.position, leg.position); + cur.scalin = fromLegacy(leg.scalin); + cur.scalout = fromLegacy(leg.scalout); + cur.doutopts = leg.doutopts; + cur.dinpopts = leg.dinpopts; + cur.aoutopts = leg.aoutopts; + cur.eopchar = leg.eopchar; + cur.moninst = static_cast((leg.monsource >> 16) & 0xFFFF); // aka lowsamples + cur.monchan = static_cast(leg.monsource & 0xFFFF); // aka highsamples + cur.outvalue = leg.outvalue; // aka offset + cur.trigtype = leg.trigtype; + // skip reserved + cur.triginst = 0; // TODO: VERIFY + cur.trigchan = leg.trigchan; + cur.trigval = leg.trigval; + cur.ainpopts = leg.ainpopts; + cur.lncrate = leg.lncrate; + cur.smpfilter = leg.smpfilter; + cur.smpgroup = leg.smpgroup; + cur.smpdispmin = leg.smpdispmin; + cur.smpdispmax = leg.smpdispmax; + cur.spkfilter = leg.spkfilter; + cur.spkdispmax = leg.spkdispmax; + cur.lncdispmax = leg.lncdispmax; + cur.spkopts = leg.spkopts; + cur.spkthrlevel = leg.spkthrlevel; + cur.spkthrlimit = leg.spkthrlimit; + cur.spkgroup = leg.spkgroup; + cur.amplrejpos = leg.amplrejpos; + cur.amplrejneg = leg.amplrejneg; + cur.refelecchan = leg.refelecchan; + copyArr(cur.unitmapping, leg.unitmapping, this, &Adapter::fromLegacy); + copyArr2D(cur.spkhoops, leg.spkhoops, this, &Adapter::fromLegacy); + return cur; +} + +::cbPKT_FS_BASIS Adapter::fromLegacy(const cbPKT_FS_BASIS& leg) const { + ::cbPKT_FS_BASIS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.fs = leg.fs; + copyArr2D(cur.basis, leg.basis); + return cur; +} + +::cbPKT_SS_MODELSET Adapter::fromLegacy(const cbPKT_SS_MODELSET& leg) const { + ::cbPKT_SS_MODELSET cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.unit_number = leg.unit_number; + cur.valid = leg.valid; + cur.inverted = leg.inverted; + cur.num_samples = leg.num_samples; + copyArr(cur.mu_x, leg.mu_x); + copyArr2D(cur.Sigma_x, leg.Sigma_x); + cur.determinant_Sigma_x = leg.determinant_Sigma_x; + copyArr2D(cur.Sigma_x_inv, leg.Sigma_x_inv); + cur.log_determinant_Sigma_x = leg.log_determinant_Sigma_x; + cur.subcluster_spread_factor_numerator = leg.subcluster_spread_factor_numerator; + cur.subcluster_spread_factor_denominator = leg.subcluster_spread_factor_denominator; + cur.mu_e = leg.mu_e; + cur.sigma_e_squared = leg.sigma_e_squared; + return cur; +} + +::cbPKT_SS_DETECT Adapter::fromLegacy(const cbPKT_SS_DETECT& leg) const { + ::cbPKT_SS_DETECT cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.fThreshold = leg.fThreshold; + cur.fMultiplier = leg.fMultiplier; + return cur; +} + +::cbPKT_SS_ARTIF_REJECT Adapter::fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) const { + ::cbPKT_SS_ARTIF_REJECT cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.nMaxSimulChans = leg.nMaxSimulChans; + cur.nRefractoryCount = leg.nRefractoryCount; + return cur; +} + +::cbPKT_SS_NOISE_BOUNDARY Adapter::fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) const { + ::cbPKT_SS_NOISE_BOUNDARY cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + copyArr(cur.afc, leg.afc); + copyArr2D(cur.afS, leg.afS); + return cur; +} + +::cbPKT_SS_STATISTICS Adapter::fromLegacy(const cbPKT_SS_STATISTICS& leg) const { + ::cbPKT_SS_STATISTICS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.nUpdateSpikes = leg.nUpdateSpikes; + cur.nAutoalg = leg.nAutoalg; + cur.nMode = leg.nMode; + cur.fMinClusterPairSpreadFactor = leg.fMinClusterPairSpreadFactor; + cur.fMaxSubclusterSpreadFactor = leg.fMaxSubclusterSpreadFactor; + cur.fMinClusterHistCorrMajMeasure = leg.fMinClusterHistCorrMajMeasure; + cur.fMaxClusterPairHistCorrMajMeasure = leg.fMaxClusterPairHistCorrMajMeasure; + cur.fClusterHistValleyPercentage = leg.fClusterHistValleyPercentage; + cur.fClusterHistClosePeakPercentage = leg.fClusterHistClosePeakPercentage; + cur.fClusterHistMinPeakPercentage = leg.fClusterHistMinPeakPercentage; + cur.nWaveBasisSize = leg.nWaveBasisSize; + cur.nWaveSampleSize = leg.nWaveSampleSize; + return cur; +} + +::cbAdaptControl Adapter::fromLegacy(const cbAdaptControl& leg) const { + ::cbAdaptControl cur{}; + cur.nMode = leg.nMode; + cur.fTimeOutMinutes = leg.fTimeOutMinutes; + cur.fElapsedMinutes = leg.fElapsedMinutes; + return cur; +} + +::cbPKT_SS_STATUS Adapter::fromLegacy(const cbPKT_SS_STATUS& leg) const { + ::cbPKT_SS_STATUS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats); + cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits); + return cur; +} + +::cbproto::SpikeSorting Adapter::fromLegacy(const cbSPIKE_SORTING& leg) const { + ::cbproto::SpikeSorting cur{}; + copyArr(cur.basis, leg.asBasis, this, &Adapter::fromLegacy); + copyArr2D(cur.models, leg.asSortModel, this, &Adapter::fromLegacy); + cur.detect = fromLegacy(leg.pktDetect); + cur.artifact_reject = fromLegacy(leg.pktArtifReject); + copyArr(cur.noise_boundary, leg.pktNoiseBoundary, this, &Adapter::fromLegacy); + cur.statistics = fromLegacy(leg.pktStatistics); + cur.status = fromLegacy(leg.pktStatus); + return cur; +} + +::cbPKT_NTRODEINFO Adapter::fromLegacy(const cbPKT_NTRODEINFO& leg) const { + ::cbPKT_NTRODEINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.ntrode = leg.ntrode; + copyArr(cur.label, leg.label); + copyArr2D(cur.ellipses, leg.ellipses, this, &Adapter::fromLegacy); + cur.nSite = leg.nSite; + cur.fs = leg.fs; + copyArr(cur.nChan, leg.nChan); + return cur; +} + +::cbWaveformData Adapter::fromLegacy(const cbWaveformData& leg) const { + ::cbWaveformData cur{}; + cur.offset = leg.offset; // aka sineFrequency + cur.seq = leg.seq; // aka sineAmplitude + cur.seqTotal = leg.seqTotal; + cur.phases = leg.phases; + copyArr(cur.duration, leg.duration); + copyArr(cur.amplitude, leg.amplitude); + return cur; +} + +::cbPKT_AOUT_WAVEFORM Adapter::fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const { + ::cbPKT_AOUT_WAVEFORM cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.repeats = leg.repeats; + cur.trig = static_cast((leg.trig >> 8) & 0xFF); + cur.trigInst = static_cast(leg.trig & 0xFF); + cur.trigChan = leg.trigChan; + cur.trigValue = leg.trigValue; + cur.trigNum = leg.trigNum; + cur.active = leg.active; + cur.wave = fromLegacy(leg.wave); + return cur; +} + +::cbPKT_LNC Adapter::fromLegacy(const cbPKT_LNC& leg) const { + ::cbPKT_LNC cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.lncFreq = leg.lncFreq; + cur.lncRefChan = leg.lncRefChan; + cur.lncGlobalMode = leg.lncGlobalMode; + return cur; +} + +::cbPKT_NPLAY Adapter::fromLegacy(const cbPKT_NPLAY& leg) const { + ::cbPKT_NPLAY cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.ftime = leg.ftime; // aka opt + cur.stime = leg.stime; + cur.etime = leg.etime; + cur.val = leg.val; + cur.mode = leg.mode; + cur.flags = leg.flags; + cur.speed = leg.speed; + copyArr(cur.fname, leg.fname); + return cur; +} + +::cbVIDEOSOURCE Adapter::fromLegacy(const cbVIDEOSOURCE& leg) const { + ::cbVIDEOSOURCE cur{}; + copyArr(cur.name, leg.name); + cur.fps = leg.fps; + return cur; +} + +::cbTRACKOBJ Adapter::fromLegacy(const cbTRACKOBJ& leg) const { + ::cbTRACKOBJ cur{}; + copyArr(cur.name, leg.name); + cur.type = leg.type; + cur.pointCount = leg.pointCount; + return cur; +} + +::cbPKT_FILECFG Adapter::fromLegacy(const cbPKT_FILECFG& leg) const { + ::cbPKT_FILECFG cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.options = leg.options; + cur.duration = leg.duration; + cur.recording = leg.recording; + cur.extctrl = leg.extctrl; + copyArr(cur.username, leg.username); + copyArr(cur.filename, leg.filename); // aka datetime + copyArr(cur.comment, leg.comment); + return cur; +} + +NativeConfigBuffer Adapter::fromLegacy(const cbCFGBUFF& leg) const { + // TODO: VERIFY that each list that's assumed to be instrument-independent is in fact independent from any particular instrument. + NativeConfigBuffer cur{}; + cur.version = leg.version; + cur.sysflags = leg.sysflags; + cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); + cur.sysinfo = fromLegacy(leg.sysinfo); + cur.procinfo = fromLegacy(leg.procinfo[instrument_idx]); + copyArr(cur.bankinfo, leg.bankinfo[instrument_idx], this, &Adapter::fromLegacy); + copyArr(cur.groupinfo, leg.groupinfo[instrument_idx], this, &Adapter::fromLegacy); + copyArr(cur.filtinfo, leg.filtinfo[instrument_idx], this, &Adapter::fromLegacy); + cur.adaptinfo = fromLegacy(leg.adaptinfo[instrument_idx]); + cur.refelecinfo = fromLegacy(leg.refelecinfo[instrument_idx]); + copyArr(cur.chaninfo, leg.chaninfo, this, &Adapter::fromLegacy); + copyArr(cur.asBasis, leg.isSortingOptions.asBasis, this, &Adapter::fromLegacy); + copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); + // TODO: Move native isSortingOptions fields into a struct + cur.pktDetect = fromLegacy(leg.isSortingOptions.pktDetect); + cur.pktArtifReject = fromLegacy(leg.isSortingOptions.pktArtifReject); + copyArr(cur.pktNoiseBoundary, leg.isSortingOptions.pktNoiseBoundary, this, &Adapter::fromLegacy); + cur.pktStatistics = fromLegacy(leg.isSortingOptions.pktStatistics); + cur.pktStatus = fromLegacy(leg.isSortingOptions.pktStatus); + copyArr(cur.isNTrodeInfo, leg.isNTrodeInfo, this, &Adapter::fromLegacy); + copyArr2D(cur.isWaveform, leg.isWaveform, this, &Adapter::fromLegacy); + cur.isLnc = fromLegacy(leg.isLnc[instrument_idx]); + cur.isNPlay = fromLegacy(leg.isNPlay); + copyArr(cur.isVideoSource, leg.isVideoSource, this, &Adapter::fromLegacy); + copyArr(cur.isTrackObj, leg.isTrackObj, this, &Adapter::fromLegacy); + cur.fileinfo = fromLegacy(leg.fileinfo); + + return cur; +} + +NativeNSPStatus Adapter::fromLegacy(const NSPStatus& leg) const { + switch(leg) { + case NSPStatus::NSP_INIT: + return NativeNSPStatus::NSP_INIT; + case NSPStatus::NSP_NOIPADDR: + return NativeNSPStatus::NSP_NOIPADDR; + case NSPStatus::NSP_NOREPLY: + return NativeNSPStatus::NSP_NOREPLY; + case NSPStatus::NSP_FOUND: + return NativeNSPStatus::NSP_FOUND; + case NSPStatus::NSP_INVALID: + default: + return NativeNSPStatus::NSP_INVALID; + } +} + +::cbPKT_UNIT_SELECTION Adapter::fromLegacy(const cbPKT_UNIT_SELECTION& leg) const { + ::cbPKT_UNIT_SELECTION cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.lastchan = leg.lastchan; + copyArr(cur.abyUnitSelections, leg.abyUnitSelections); + return cur; +} + +NativePCStatus Adapter::fromLegacy(const cbPcStatus& leg) const { + NativePCStatus cur{}; + cur.isSelection = fromLegacy(leg.isSelection[instrument_idx]); + cur.m_iBlockRecording = leg.m_iBlockRecording; + cur.m_nPCStatusFlags = leg.m_nPCStatusFlags; + cur.m_nNumFEChans = leg.m_nNumFEChans; + cur.m_nNumAnainChans = leg.m_nNumAnainChans; + cur.m_nNumAnalogChans = leg.m_nNumAnalogChans; + cur.m_nNumAoutChans = leg.m_nNumAoutChans; + cur.m_nNumAudioChans = leg.m_nNumAudioChans; + cur.m_nNumAnalogoutChans = leg.m_nNumAnalogoutChans; + cur.m_nNumDiginChans = leg.m_nNumDiginChans; + cur.m_nNumSerialChans = leg.m_nNumSerialChans; + cur.m_nNumDigoutChans = leg.m_nNumDigoutChans; + cur.m_nNumTotalChans = leg.m_nNumTotalChans; + cur.m_nNspStatus = fromLegacy(leg.m_nNspStatus[instrument_idx]); + cur.m_nNumNTrodesPerInstrument = leg.m_nNumNTrodesPerInstrument[instrument_idx]; + cur.m_nGeminiSystem = leg.m_nGeminiSystem; + // ignore APP_WORKSPACE + return cur; +} + +NativeReceiveBuffer Adapter::fromLegacy(const cbRECBUFF& leg) const { + NativeReceiveBuffer cur{}; + cur.received = leg.received; + cur.lasttime = leg.lasttime; + cur.headwrap = leg.headwrap; + cur.headindex = leg.headindex; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +NativeTransmitBuffer Adapter::fromLegacy(const cbXMTBUFF& leg) const { + NativeTransmitBuffer cur{}; + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +NativeTransmitBufferLocal Adapter::fromLegacy(const cbXMTBUFFLOCAL& leg) const { + NativeTransmitBufferLocal cur{}; + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +cbPKT_HEADER Adapter::toLegacy(const ::cbPKT_HEADER& cur) const { + cbPKT_HEADER leg{}; + leg.time = cur.time; + leg.chid = cur.chid; + leg.type = static_cast(cur.type); + leg.dlen = cur.dlen; + leg.instrument = cur.instrument; + leg.reserved = cur.reserved; + return leg; +} + +cbPKT_SYSINFO Adapter::toLegacy(const ::cbPKT_SYSINFO& cur) const { + cbPKT_SYSINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.sysfreq = cur.sysfreq; + leg.spikelen = cur.spikelen; + leg.spikepre = cur.spikepre; + leg.resetque = cur.resetque; + leg.runlevel = cur.runlevel; + leg.runflags = cur.runflags; + return leg; +} + +cbPKT_PROCINFO Adapter::toLegacy(const ::cbPKT_PROCINFO& cur) const { + cbPKT_PROCINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.idcode = cur.idcode; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; + leg.bankcount = cur.bankcount; + leg.groupcount = cur.groupcount; + leg.filtcount = cur.filtcount; + leg.sortcount = cur.sortcount; + leg.unitcount = cur.unitcount; + leg.hoopcount = cur.hoopcount; + leg.reserved = cur.reserved; + leg.version = cur.version; + return leg; +} + +cbPKT_BANKINFO Adapter::toLegacy(const ::cbPKT_BANKINFO& cur) const { + cbPKT_BANKINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + copyArr(leg.label, cur.label); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; + return leg; +} + +cbPKT_GROUPINFO Adapter::toLegacy(const ::cbPKT_GROUPINFO& cur) const { + cbPKT_GROUPINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.group = cur.group; + copyArr(leg.label, cur.label); + leg.period = cur.period; + leg.length = cur.length; + copyArr(leg.list, cur.list); + return leg; +} + +cbPKT_FILTINFO Adapter::toLegacy(const ::cbPKT_FILTINFO& cur) const { + cbPKT_FILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.filt = cur.filt; + copyArr(leg.label, cur.label); + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; + leg.gain = cur.gain; + leg.sos1a1 = cur.sos1a1; + leg.sos1a2 = cur.sos1a2; + leg.sos1b1 = cur.sos1b1; + leg.sos1b2 = cur.sos1b2; + leg.sos2a1 = cur.sos2a1; + leg.sos2a2 = cur.sos2a2; + leg.sos2b1 = cur.sos2b1; + leg.sos2b2 = cur.sos2b2; + return leg; +} + +cbPKT_ADAPTFILTINFO Adapter::toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) const { + cbPKT_ADAPTFILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.dLearningRate = cur.dLearningRate; + leg.nRefChan1 = cur.nRefChan1; + leg.nRefChan2 = cur.nRefChan2; + return leg; +} + +cbPKT_REFELECFILTINFO Adapter::toLegacy(const ::cbPKT_REFELECFILTINFO& cur) const { + cbPKT_REFELECFILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.nRefChan = cur.nRefChan; + return leg; +} + +cbSCALING Adapter::toLegacy(const ::cbSCALING& cur) const { + cbSCALING leg{}; + leg.digmin = cur.digmin; + leg.digmax = cur.digmax; + leg.anamin = cur.anamin; + leg.anamax = cur.anamax; + leg.anagain = cur.anagain; + copyArr(leg.anaunit, cur.anaunit); + return leg; +} + +cbFILTDESC Adapter::toLegacy(const ::cbFILTDESC& cur) const { + cbFILTDESC leg{}; + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; + return leg; +} + +cbMANUALUNITMAPPING Adapter::toLegacy(const ::cbMANUALUNITMAPPING& cur) const { + cbMANUALUNITMAPPING leg{}; + leg.nOverride = cur.nOverride; + copyArr(leg.afOrigin, cur.afOrigin); + copyArr2D(leg.afShape, cur.afShape); + leg.aPhi = cur.aPhi; + leg.bValid = cur.bValid; + return leg; +} + +cbHOOP Adapter::toLegacy(const ::cbHOOP& cur) const { + cbHOOP leg{}; + leg.valid = cur.valid; + leg.time = cur.time; + leg.min = cur.min; + leg.max = cur.max; + return leg; +} + +cbPKT_CHANINFO Adapter::toLegacy(const ::cbPKT_CHANINFO& cur) const { + cbPKT_CHANINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.term = cur.term; + leg.chancaps = cur.chancaps; + leg.doutcaps = cur.doutcaps; + leg.dinpcaps = cur.dinpcaps; + leg.aoutcaps = cur.aoutcaps; + leg.ainpcaps = cur.ainpcaps; + leg.spkcaps = cur.spkcaps; + leg.physcalin = toLegacy(cur.physcalin); + leg.phyfiltin = toLegacy(cur.phyfiltin); + leg.physcalout = toLegacy(cur.physcalout); + leg.phyfiltout = toLegacy(cur.phyfiltout); + copyArr(leg.label, cur.label); + leg.userflags = cur.userflags; + copyArr(leg.position, cur.position); + leg.scalin = toLegacy(cur.scalin); + leg.scalout = toLegacy(cur.scalout); + leg.doutopts = cur.doutopts; + leg.dinpopts = cur.dinpopts; + leg.aoutopts = cur.aoutopts; + leg.eopchar = cur.eopchar; + leg.monsource = (static_cast(cur.moninst) << 16) | static_cast(cur.monchan); // aka highsamples and lowsamples + leg.outvalue = cur.outvalue; // aka offset + leg.trigtype = cur.trigtype; + leg.trigchan = cur.trigchan; + leg.trigval = cur.trigval; + leg.ainpopts = cur.ainpopts; + leg.lncrate = cur.lncrate; + leg.smpfilter = cur.smpfilter; + leg.smpgroup = cur.smpgroup; + leg.smpdispmin = cur.smpdispmin; + leg.smpdispmax = cur.smpdispmax; + leg.spkfilter = cur.spkfilter; + leg.spkdispmax = cur.spkdispmax; + leg.lncdispmax = cur.lncdispmax; + leg.spkopts = cur.spkopts; + leg.spkthrlevel = cur.spkthrlevel; + leg.spkthrlimit = cur.spkthrlimit; + leg.spkgroup = cur.spkgroup; + leg.amplrejpos = cur.amplrejpos; + leg.amplrejneg = cur.amplrejneg; + leg.refelecchan = cur.refelecchan; + copyArr(leg.unitmapping, cur.unitmapping, this, &Adapter::toLegacy); + copyArr2D(leg.spkhoops, cur.spkhoops, this, &Adapter::toLegacy); + return leg; +} + +cbPKT_FS_BASIS Adapter::toLegacy(const ::cbPKT_FS_BASIS& cur) const { + cbPKT_FS_BASIS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.fs = cur.fs; + copyArr2D(leg.basis, cur.basis); + return leg; +} + +cbPKT_SS_MODELSET Adapter::toLegacy(const ::cbPKT_SS_MODELSET& cur) const { + cbPKT_SS_MODELSET leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.unit_number = cur.unit_number; + leg.valid = cur.valid; + leg.inverted = cur.inverted; + leg.num_samples = cur.num_samples; + copyArr(leg.mu_x, cur.mu_x); + copyArr2D(leg.Sigma_x, cur.Sigma_x); + leg.determinant_Sigma_x = cur.determinant_Sigma_x; + copyArr2D(leg.Sigma_x_inv, cur.Sigma_x_inv); + leg.log_determinant_Sigma_x = cur.log_determinant_Sigma_x; + leg.subcluster_spread_factor_numerator = cur.subcluster_spread_factor_numerator; + leg.subcluster_spread_factor_denominator = cur.subcluster_spread_factor_denominator; + leg.mu_e = cur.mu_e; + leg.sigma_e_squared = cur.sigma_e_squared; + return leg; +} + +cbPKT_SS_DETECT Adapter::toLegacy(const ::cbPKT_SS_DETECT& cur) const { + cbPKT_SS_DETECT leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.fThreshold = cur.fThreshold; + leg.fMultiplier = cur.fMultiplier; + return leg; +} + +cbPKT_SS_ARTIF_REJECT Adapter::toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) const { + cbPKT_SS_ARTIF_REJECT leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.nMaxSimulChans = cur.nMaxSimulChans; + leg.nRefractoryCount = cur.nRefractoryCount; + return leg; +} + +cbPKT_SS_NOISE_BOUNDARY Adapter::toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) const { + cbPKT_SS_NOISE_BOUNDARY leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + copyArr(leg.afc, cur.afc); + copyArr2D(leg.afS, cur.afS); + return leg; +} + +cbPKT_SS_STATISTICS Adapter::toLegacy(const ::cbPKT_SS_STATISTICS& cur) const { + cbPKT_SS_STATISTICS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.nUpdateSpikes = cur.nUpdateSpikes; + leg.nAutoalg = cur.nAutoalg; + leg.nMode = cur.nMode; + leg.fMinClusterPairSpreadFactor = cur.fMinClusterPairSpreadFactor; + leg.fMaxSubclusterSpreadFactor = cur.fMaxSubclusterSpreadFactor; + leg.fMinClusterHistCorrMajMeasure = cur.fMinClusterHistCorrMajMeasure; + leg.fMaxClusterPairHistCorrMajMeasure = cur.fMaxClusterPairHistCorrMajMeasure; + leg.fClusterHistValleyPercentage = cur.fClusterHistValleyPercentage; + leg.fClusterHistClosePeakPercentage = cur.fClusterHistClosePeakPercentage; + leg.fClusterHistMinPeakPercentage = cur.fClusterHistMinPeakPercentage; + leg.nWaveBasisSize = cur.nWaveBasisSize; + leg.nWaveSampleSize = cur.nWaveSampleSize; + return leg; +} + +cbAdaptControl Adapter::toLegacy(const ::cbAdaptControl& cur) const { + cbAdaptControl leg{}; + leg.nMode = cur.nMode; + leg.fTimeOutMinutes = cur.fTimeOutMinutes; + leg.fElapsedMinutes = cur.fElapsedMinutes; + return leg; +} + +cbPKT_SS_STATUS Adapter::toLegacy(const ::cbPKT_SS_STATUS& cur) const { + cbPKT_SS_STATUS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cntlUnitStats = toLegacy(cur.cntlUnitStats); + leg.cntlNumUnits = toLegacy(cur.cntlNumUnits); + return leg; +} + +cbSPIKE_SORTING Adapter::toLegacy(const ::cbproto::SpikeSorting& cur) const { + cbSPIKE_SORTING leg{}; + copyArr(leg.asBasis, cur.basis, this, &Adapter::toLegacy); + copyArr2D(leg.asSortModel, cur.models, this, &Adapter::toLegacy); + leg.pktDetect = toLegacy(cur.detect); + leg.pktArtifReject = toLegacy(cur.artifact_reject); + copyArr(leg.pktNoiseBoundary, cur.noise_boundary, this, &Adapter::toLegacy); + leg.pktStatistics = toLegacy(cur.statistics); + leg.pktStatus = toLegacy(cur.status); + return leg; +} + +cbPKT_NTRODEINFO Adapter::toLegacy(const ::cbPKT_NTRODEINFO& cur) const { + cbPKT_NTRODEINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.ntrode = cur.ntrode; + copyArr(leg.label, cur.label); + copyArr2D(leg.ellipses, cur.ellipses, this, &Adapter::toLegacy); + leg.nSite = cur.nSite; + leg.fs = cur.fs; + copyArr(leg.nChan, cur.nChan); + return leg; +} + +cbWaveformData Adapter::toLegacy(const ::cbWaveformData& cur) const { + cbWaveformData leg{}; + leg.offset = cur.offset; // aka sineFrequency + leg.seq = cur.seq; // aka sineAmplitude + leg.seqTotal = cur.seqTotal; + leg.phases = cur.phases; + copyArr(leg.duration, cur.duration); + copyArr(leg.amplitude, cur.amplitude); + return leg; +} + +cbPKT_AOUT_WAVEFORM Adapter::toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const { + cbPKT_AOUT_WAVEFORM leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.repeats = cur.repeats; + leg.trig = (static_cast(cur.trig) << 8) | static_cast(cur.trigInst); + leg.trigChan = cur.trigChan; + leg.trigValue = cur.trigValue; + leg.trigNum = cur.trigNum; + leg.active = cur.active; + leg.wave = toLegacy(cur.wave); + return leg; +} + +cbPKT_LNC Adapter::toLegacy(const ::cbPKT_LNC& cur) const { + cbPKT_LNC leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.lncFreq = cur.lncFreq; + leg.lncRefChan = cur.lncRefChan; + leg.lncGlobalMode = cur.lncGlobalMode; + return leg; +} + +cbPKT_NPLAY Adapter::toLegacy(const ::cbPKT_NPLAY& cur) const { + cbPKT_NPLAY leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.ftime = cur.ftime; // aka opt + leg.stime = cur.stime; + leg.etime = cur.etime; + leg.val = cur.val; + leg.mode = cur.mode; + leg.flags = cur.flags; + leg.speed = cur.speed; + copyArr(leg.fname, cur.fname); + return leg; +} + +cbVIDEOSOURCE Adapter::toLegacy(const ::cbVIDEOSOURCE& cur) const { + cbVIDEOSOURCE leg{}; + copyArr(leg.name, cur.name); + leg.fps = cur.fps; + return leg; +} + +cbTRACKOBJ Adapter::toLegacy(const ::cbTRACKOBJ& cur) const { + cbTRACKOBJ leg{}; + copyArr(leg.name, cur.name); + leg.type = cur.type; + leg.pointCount = cur.pointCount; + return leg; +} + +cbPKT_FILECFG Adapter::toLegacy(const ::cbPKT_FILECFG& cur) const { + cbPKT_FILECFG leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.options = cur.options; + leg.duration = cur.duration; + leg.recording = cur.recording; + leg.extctrl = cur.extctrl; + copyArr(leg.username, cur.username); + copyArr(leg.filename, cur.filename); // aka datetime + copyArr(leg.comment, cur.comment); + return leg; +} + +NSPStatus Adapter::toLegacy(const NativeNSPStatus& cur) const { + switch(cur) { + case NativeNSPStatus::NSP_INIT: + return NSPStatus::NSP_INIT; + case NativeNSPStatus::NSP_NOIPADDR: + return NSPStatus::NSP_NOIPADDR; + case NativeNSPStatus::NSP_NOREPLY: + return NSPStatus::NSP_NOREPLY; + case NativeNSPStatus::NSP_FOUND: + return NSPStatus::NSP_FOUND; + case NativeNSPStatus::NSP_INVALID: + default: + return NSPStatus::NSP_INVALID; + } +} + +cbPKT_UNIT_SELECTION Adapter::toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const { + cbPKT_UNIT_SELECTION leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.lastchan = cur.lastchan; + copyArr(leg.abyUnitSelections, cur.abyUnitSelections); + return leg; +} + +cbPcStatus Adapter::toLegacy(const NativePCStatus& cur) const { + cbPcStatus leg{}; + leg.isSelection[instrument_idx] = toLegacy(cur.isSelection); + leg.m_iBlockRecording = cur.m_iBlockRecording; + leg.m_nPCStatusFlags = cur.m_nPCStatusFlags; + leg.m_nNumFEChans = cur.m_nNumFEChans; + leg.m_nNumAnainChans = cur.m_nNumAnainChans; + leg.m_nNumAnalogChans = cur.m_nNumAnalogChans; + leg.m_nNumAoutChans = cur.m_nNumAoutChans; + leg.m_nNumAudioChans = cur.m_nNumAudioChans; + leg.m_nNumAnalogoutChans = cur.m_nNumAnalogoutChans; + leg.m_nNumDiginChans = cur.m_nNumDiginChans; + leg.m_nNumSerialChans = cur.m_nNumSerialChans; + leg.m_nNumDigoutChans = cur.m_nNumDigoutChans; + leg.m_nNumTotalChans = cur.m_nNumTotalChans; + leg.m_nNspStatus[instrument_idx] = toLegacy(cur.m_nNspStatus); + leg.m_nNumNTrodesPerInstrument[instrument_idx] = cur.m_nNumNTrodesPerInstrument; + leg.m_nGeminiSystem = cur.m_nGeminiSystem; + // ignore APP_WORKSPACE + return leg; +} + +cbRECBUFF Adapter::toLegacy(const NativeReceiveBuffer& cur) const { + cbRECBUFF leg{}; + leg.received = cur.received; + leg.lasttime = cur.lasttime; + leg.headwrap = cur.headwrap; + leg.headindex = cur.headindex; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +cbXMTBUFF Adapter::toLegacy(const NativeTransmitBuffer& cur) const { + cbXMTBUFF leg{}; + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +cbXMTBUFFLOCAL Adapter::toLegacy(const NativeTransmitBufferLocal& cur) const { + cbXMTBUFFLOCAL leg{}; + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +Adapter::Adapter(uint8_t instrument_idx, void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) + : instrument_idx(instrument_idx) + , cfg(static_cast(cfg_ptr)) , rec(static_cast(rec_ptr)) , xmt(static_cast(xmt_ptr)) , xmt_local(static_cast(xmt_local_ptr)) @@ -52,6 +1035,10 @@ Adapter::Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_pt , spike(static_cast(spike_ptr)) {} +uint32_t Adapter::getMaxProcs() const { + return cbMAXPROCS; +} + uint32_t& Adapter::getRecReceived() { return rec->received; } @@ -124,14 +1111,14 @@ uint32_t* Adapter::getLocalXmtBufferPtr() { return xmt->buffer; } -Result<::cbPKT_PROCINFO> Adapter::getProcInfo(uint8_t instrument_idx) const { +Result<::cbPKT_PROCINFO> Adapter::getProcInfo() const { if (instrument_idx >= std::size(cfg->procinfo)) { return Result<::cbPKT_PROCINFO>::error("Instrument index out of range"); } - return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx], {})); + return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx])); } -Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const { +Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint32_t bank_num) const { if (instrument_idx >= std::size(cfg->bankinfo)) { return Result<::cbPKT_BANKINFO>::error("Instrument index out of range"); } @@ -139,10 +1126,10 @@ Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t b if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result<::cbPKT_BANKINFO>::error("Bank number out of range"); } - return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx], {})); + return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx])); } -Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const { +Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint32_t filter_num) const { if (instrument_idx >= std::size(cfg->filtinfo)) { return Result<::cbPKT_FILTINFO>::error("Instrument index out of range"); } @@ -150,53 +1137,53 @@ Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result<::cbPKT_FILTINFO>::error("Filter number out of range"); } - return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx], {})); + return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx])); } Result<::cbPKT_CHANINFO> Adapter::getChanInfo(uint32_t channel_idx) const { if (channel_idx >= std::size(cfg->chaninfo)) { return Result<::cbPKT_CHANINFO>::error("Channel number out of range"); } - return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx], {})); + return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx])); } Result<::cbPKT_SYSINFO> Adapter::getSysInfo() const { - return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo, {})); + return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo)); } -Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const { +Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint32_t group_idx) const { if (instrument_idx >= std::size(cfg->groupinfo)) { return Result<::cbPKT_GROUPINFO>::error("Instrument index out of range"); } if (group_idx >= std::size(cfg->groupinfo[0])) { return Result<::cbPKT_GROUPINFO>::error("Group index out of range"); } - return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx], {})); + return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx])); } -Result Adapter::getConfigBuffer(uint8_t instrument_idx) const { +Result Adapter::getConfigBuffer() const { if (instrument_idx >= std::size(cfg->procinfo)) { return Result::error("Instrument index out of range"); } - return Result::ok(fromLegacy(*cfg, { .instrument_idx = instrument_idx })); + return Result::ok(fromLegacy(*cfg)); } -Result Adapter::getPcStatus(uint8_t instrument_idx) const { +Result Adapter::getPcStatus() const { if (instrument_idx >= std::size(status->isSelection)) { return Result::error("Instrument index out of range"); } - return Result::ok(fromLegacy(*status, { .instrument_idx = instrument_idx })); + return Result::ok(fromLegacy(*status)); } -Result Adapter::setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) { +Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { if (instrument_idx >= std::size(cfg->procinfo)) { return Result::error("Instrument index out of range"); } - cfg->procinfo[instrument_idx] = toLegacy(info, {}); + cfg->procinfo[instrument_idx] = toLegacy(info); return Result::ok(); } -Result Adapter::setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) { +Result Adapter::setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) { if (instrument_idx >= std::size(cfg->bankinfo)) { return Result::error("Instrument index out of range"); } @@ -204,11 +1191,11 @@ Result Adapter::setBankInfo(uint8_t instrument_idx, uint32_t bank_num, con if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result::error("Bank number out of range"); } - cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info, {}); + cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info); return Result::ok(); } -Result Adapter::setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) { +Result Adapter::setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) { if (instrument_idx >= std::size(cfg->filtinfo)) { return Result::error("Instrument index out of range"); } @@ -216,7 +1203,7 @@ Result Adapter::setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result::error("Filter number out of range"); } - cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info, {}); + cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info); return Result::ok(); } @@ -224,31 +1211,31 @@ Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& if (channel_idx >= std::size(cfg->chaninfo)) { return Result::error("Channel number out of range"); } - cfg->chaninfo[channel_idx] = toLegacy(info, {}); + cfg->chaninfo[channel_idx] = toLegacy(info); return Result::ok(); } Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { - cfg->sysinfo = toLegacy(info, {}); + cfg->sysinfo = toLegacy(info); return Result::ok(); } -Result Adapter::setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { +Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { if (instrument_idx >= std::size(cfg->groupinfo)) { return Result::error("Instrument index out of range"); } if (group_idx >= std::size(cfg->groupinfo[0])) { return Result::error("Group index out of range"); } - cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info, {}); + cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info); return Result::ok(); } -Result Adapter::setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const { +Result Adapter::setPcStatus(const NativePCStatus& status) const { if (instrument_idx >= std::size(this->status->isSelection)) { return Result::error("Instrument index out of range"); } - *(this->status) = toLegacy(status, { .instrument_idx = instrument_idx }); + *(this->status) = this->toLegacy(status); return Result::ok(); } diff --git a/src/cbshm/src/central_adapters/v4_1.cpp b/src/cbshm/src/central_adapters/v4_1.cpp index 89634dc8..b0be6dd5 100644 --- a/src/cbshm/src/central_adapters/v4_1.cpp +++ b/src/cbshm/src/central_adapters/v4_1.cpp @@ -8,7 +8,6 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// #include -#include #include namespace cbshm { @@ -43,8 +42,996 @@ size_t BootstrapAdapter::getReceiveBufferLen() const { return sizeof(cbRECBUFFLEN); } -Adapter::Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) - : cfg(static_cast(cfg_ptr)) +::cbPKT_HEADER Adapter::fromLegacy(const cbPKT_HEADER& leg) const { + ::cbPKT_HEADER cur{}; + cur.time = leg.time; + cur.chid = leg.chid; + cur.type = leg.type; + cur.dlen = leg.dlen; + cur.instrument = leg.instrument; + cur.reserved = leg.reserved; + return cur; +} + +::cbPKT_SYSINFO Adapter::fromLegacy(const cbPKT_SYSINFO& leg) const { + ::cbPKT_SYSINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.sysfreq = leg.sysfreq; + cur.spikelen = leg.spikelen; + cur.spikepre = leg.spikepre; + cur.resetque = leg.resetque; + cur.runlevel = leg.runlevel; + cur.runflags = leg.runflags; + return cur; +} + +::cbPKT_PROCINFO Adapter::fromLegacy(const cbPKT_PROCINFO& leg) const { + ::cbPKT_PROCINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.idcode = leg.idcode; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; + cur.bankcount = leg.bankcount; + cur.groupcount = leg.groupcount; + cur.filtcount = leg.filtcount; + cur.sortcount = leg.sortcount; + cur.unitcount = leg.unitcount; + cur.hoopcount = leg.hoopcount; + cur.reserved = leg.reserved; + cur.version = leg.version; + return cur; +} + +::cbPKT_BANKINFO Adapter::fromLegacy(const cbPKT_BANKINFO& leg) const { + ::cbPKT_BANKINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + copyArr(cur.label, leg.label); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; + return cur; +} + +::cbPKT_GROUPINFO Adapter::fromLegacy(const cbPKT_GROUPINFO& leg) const { + ::cbPKT_GROUPINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.group = leg.group; + copyArr(cur.label, leg.label); + cur.period = leg.period; + cur.length = leg.length; + copyArr(cur.list, leg.list); + return cur; +} + +::cbPKT_FILTINFO Adapter::fromLegacy(const cbPKT_FILTINFO& leg) const { + ::cbPKT_FILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.filt = leg.filt; + copyArr(cur.label, leg.label); + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; + cur.gain = leg.gain; + cur.sos1a1 = leg.sos1a1; + cur.sos1a2 = leg.sos1a2; + cur.sos1b1 = leg.sos1b1; + cur.sos1b2 = leg.sos1b2; + cur.sos2a1 = leg.sos2a1; + cur.sos2a2 = leg.sos2a2; + cur.sos2b1 = leg.sos2b1; + cur.sos2b2 = leg.sos2b2; + return cur; +} + +::cbPKT_ADAPTFILTINFO Adapter::fromLegacy(const cbPKT_ADAPTFILTINFO& leg) const { + ::cbPKT_ADAPTFILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.dLearningRate = leg.dLearningRate; + cur.nRefChan1 = leg.nRefChan1; + cur.nRefChan2 = leg.nRefChan2; + return cur; +} + +::cbPKT_REFELECFILTINFO Adapter::fromLegacy(const cbPKT_REFELECFILTINFO& leg) const { + ::cbPKT_REFELECFILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.nRefChan = leg.nRefChan; + return cur; +} + +::cbSCALING Adapter::fromLegacy(const cbSCALING& leg) const { + ::cbSCALING cur{}; + cur.digmin = leg.digmin; + cur.digmax = leg.digmax; + cur.anamin = leg.anamin; + cur.anamax = leg.anamax; + cur.anagain = leg.anagain; + copyArr(cur.anaunit, leg.anaunit); + return cur; +} + +::cbFILTDESC Adapter::fromLegacy(const cbFILTDESC& leg) const { + ::cbFILTDESC cur{}; + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; + return cur; +} + +::cbMANUALUNITMAPPING Adapter::fromLegacy(const cbMANUALUNITMAPPING& leg) const { + ::cbMANUALUNITMAPPING cur{}; + cur.nOverride = leg.nOverride; + copyArr(cur.afOrigin, leg.afOrigin); + copyArr2D(cur.afShape, leg.afShape); + cur.aPhi = leg.aPhi; + cur.bValid = leg.bValid; + return cur; +} + +::cbHOOP Adapter::fromLegacy(const cbHOOP& leg) const { + ::cbHOOP cur{}; + cur.valid = leg.valid; + cur.time = leg.time; + cur.min = leg.min; + cur.max = leg.max; + return cur; +} + +::cbPKT_CHANINFO Adapter::fromLegacy(const cbPKT_CHANINFO& leg) const { + ::cbPKT_CHANINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.term = leg.term; + cur.chancaps = leg.chancaps; + cur.doutcaps = leg.doutcaps; + cur.dinpcaps = leg.dinpcaps; + cur.aoutcaps = leg.aoutcaps; + cur.ainpcaps = leg.ainpcaps; + cur.spkcaps = leg.spkcaps; + cur.physcalin = fromLegacy(leg.physcalin); + cur.phyfiltin = fromLegacy(leg.phyfiltin); + cur.physcalout = fromLegacy(leg.physcalout); + cur.phyfiltout = fromLegacy(leg.phyfiltout); + copyArr(cur.label, leg.label); + cur.userflags = leg.userflags; + copyArr(cur.position, leg.position); + cur.scalin = fromLegacy(leg.scalin); + cur.scalout = fromLegacy(leg.scalout); + cur.doutopts = leg.doutopts; + cur.dinpopts = leg.dinpopts; + cur.aoutopts = leg.aoutopts; + cur.eopchar = leg.eopchar; + cur.moninst = leg.moninst; // aka lowsamples + cur.monchan = leg.monchan; // aka highsamples + cur.outvalue = leg.outvalue; // aka offset + cur.trigtype = leg.trigtype; + copyArr(cur.reserved, leg.reserved); + cur.triginst = leg.triginst; + cur.trigchan = leg.trigchan; + cur.trigval = leg.trigval; + cur.ainpopts = leg.ainpopts; + cur.lncrate = leg.lncrate; + cur.smpfilter = leg.smpfilter; + cur.smpgroup = leg.smpgroup; + cur.smpdispmin = leg.smpdispmin; + cur.smpdispmax = leg.smpdispmax; + cur.spkfilter = leg.spkfilter; + cur.spkdispmax = leg.spkdispmax; + cur.lncdispmax = leg.lncdispmax; + cur.spkopts = leg.spkopts; + cur.spkthrlevel = leg.spkthrlevel; + cur.spkthrlimit = leg.spkthrlimit; + cur.spkgroup = leg.spkgroup; + cur.amplrejpos = leg.amplrejpos; + cur.amplrejneg = leg.amplrejneg; + cur.refelecchan = leg.refelecchan; + copyArr(cur.unitmapping, leg.unitmapping, this, &Adapter::fromLegacy); + copyArr2D(cur.spkhoops, leg.spkhoops, this, &Adapter::fromLegacy); + return cur; +} + +::cbPKT_FS_BASIS Adapter::fromLegacy(const cbPKT_FS_BASIS& leg) const { + ::cbPKT_FS_BASIS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.fs = leg.fs; + copyArr2D(cur.basis, leg.basis); + return cur; +} + +::cbPKT_SS_MODELSET Adapter::fromLegacy(const cbPKT_SS_MODELSET& leg) const { + ::cbPKT_SS_MODELSET cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.unit_number = leg.unit_number; + cur.valid = leg.valid; + cur.inverted = leg.inverted; + cur.num_samples = leg.num_samples; + copyArr(cur.mu_x, leg.mu_x); + copyArr2D(cur.Sigma_x, leg.Sigma_x); + cur.determinant_Sigma_x = leg.determinant_Sigma_x; + copyArr2D(cur.Sigma_x_inv, leg.Sigma_x_inv); + cur.log_determinant_Sigma_x = leg.log_determinant_Sigma_x; + cur.subcluster_spread_factor_numerator = leg.subcluster_spread_factor_numerator; + cur.subcluster_spread_factor_denominator = leg.subcluster_spread_factor_denominator; + cur.mu_e = leg.mu_e; + cur.sigma_e_squared = leg.sigma_e_squared; + return cur; +} + +::cbPKT_SS_DETECT Adapter::fromLegacy(const cbPKT_SS_DETECT& leg) const { + ::cbPKT_SS_DETECT cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.fThreshold = leg.fThreshold; + cur.fMultiplier = leg.fMultiplier; + return cur; +} + +::cbPKT_SS_ARTIF_REJECT Adapter::fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) const { + ::cbPKT_SS_ARTIF_REJECT cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.nMaxSimulChans = leg.nMaxSimulChans; + cur.nRefractoryCount = leg.nRefractoryCount; + return cur; +} + +::cbPKT_SS_NOISE_BOUNDARY Adapter::fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) const { + ::cbPKT_SS_NOISE_BOUNDARY cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + copyArr(cur.afc, leg.afc); + copyArr2D(cur.afS, leg.afS); + return cur; +} + +::cbPKT_SS_STATISTICS Adapter::fromLegacy(const cbPKT_SS_STATISTICS& leg) const { + ::cbPKT_SS_STATISTICS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.nUpdateSpikes = leg.nUpdateSpikes; + cur.nAutoalg = leg.nAutoalg; + cur.nMode = leg.nMode; + cur.fMinClusterPairSpreadFactor = leg.fMinClusterPairSpreadFactor; + cur.fMaxSubclusterSpreadFactor = leg.fMaxSubclusterSpreadFactor; + cur.fMinClusterHistCorrMajMeasure = leg.fMinClusterHistCorrMajMeasure; + cur.fMaxClusterPairHistCorrMajMeasure = leg.fMaxClusterPairHistCorrMajMeasure; + cur.fClusterHistValleyPercentage = leg.fClusterHistValleyPercentage; + cur.fClusterHistClosePeakPercentage = leg.fClusterHistClosePeakPercentage; + cur.fClusterHistMinPeakPercentage = leg.fClusterHistMinPeakPercentage; + cur.nWaveBasisSize = leg.nWaveBasisSize; + cur.nWaveSampleSize = leg.nWaveSampleSize; + return cur; +} + +::cbAdaptControl Adapter::fromLegacy(const cbAdaptControl& leg) const { + ::cbAdaptControl cur{}; + cur.nMode = leg.nMode; + cur.fTimeOutMinutes = leg.fTimeOutMinutes; + cur.fElapsedMinutes = leg.fElapsedMinutes; + return cur; +} + +::cbPKT_SS_STATUS Adapter::fromLegacy(const cbPKT_SS_STATUS& leg) const { + ::cbPKT_SS_STATUS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats); + cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits); + return cur; +} + +::cbproto::SpikeSorting Adapter::fromLegacy(const cbSPIKE_SORTING& leg) const { + ::cbproto::SpikeSorting cur{}; + copyArr(cur.basis, leg.asBasis, this, &Adapter::fromLegacy); + copyArr2D(cur.models, leg.asSortModel, this, &Adapter::fromLegacy); + cur.detect = fromLegacy(leg.pktDetect); + cur.artifact_reject = fromLegacy(leg.pktArtifReject); + copyArr(cur.noise_boundary, leg.pktNoiseBoundary, this, &Adapter::fromLegacy); + cur.statistics = fromLegacy(leg.pktStatistics); + cur.status = fromLegacy(leg.pktStatus); + return cur; +} + +::cbPKT_NTRODEINFO Adapter::fromLegacy(const cbPKT_NTRODEINFO& leg) const { + ::cbPKT_NTRODEINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.ntrode = leg.ntrode; + copyArr(cur.label, leg.label); + copyArr2D(cur.ellipses, leg.ellipses, this, &Adapter::fromLegacy); + cur.nSite = leg.nSite; + cur.fs = leg.fs; + copyArr(cur.nChan, leg.nChan); + return cur; +} + +::cbWaveformData Adapter::fromLegacy(const cbWaveformData& leg) const { + ::cbWaveformData cur{}; + cur.offset = leg.offset; // aka sineFrequency + cur.seq = leg.seq; // aka sineAmplitude + cur.seqTotal = leg.seqTotal; + cur.phases = leg.phases; + copyArr(cur.duration, leg.duration); + copyArr(cur.amplitude, leg.amplitude); + return cur; +} + +::cbPKT_AOUT_WAVEFORM Adapter::fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const { + ::cbPKT_AOUT_WAVEFORM cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.repeats = leg.repeats; + cur.trig = leg.trig; + cur.trigInst = leg.trigInst; + cur.trigChan = leg.trigChan; + cur.trigValue = leg.trigValue; + cur.trigNum = leg.trigNum; + cur.active = leg.active; + cur.wave = fromLegacy(leg.wave); + return cur; +} + +::cbPKT_LNC Adapter::fromLegacy(const cbPKT_LNC& leg) const { + ::cbPKT_LNC cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.lncFreq = leg.lncFreq; + cur.lncRefChan = leg.lncRefChan; + cur.lncGlobalMode = leg.lncGlobalMode; + return cur; +} + +::cbPKT_NPLAY Adapter::fromLegacy(const cbPKT_NPLAY& leg) const { + ::cbPKT_NPLAY cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.ftime = leg.ftime; // aka opt + cur.stime = leg.stime; + cur.etime = leg.etime; + cur.val = leg.val; + cur.mode = leg.mode; + cur.flags = leg.flags; + cur.speed = leg.speed; + copyArr(cur.fname, leg.fname); + return cur; +} + +::cbVIDEOSOURCE Adapter::fromLegacy(const cbVIDEOSOURCE& leg) const { + ::cbVIDEOSOURCE cur{}; + copyArr(cur.name, leg.name); + cur.fps = leg.fps; + return cur; +} + +::cbTRACKOBJ Adapter::fromLegacy(const cbTRACKOBJ& leg) const { + ::cbTRACKOBJ cur{}; + copyArr(cur.name, leg.name); + cur.type = leg.type; + cur.pointCount = leg.pointCount; + return cur; +} + +::cbPKT_FILECFG Adapter::fromLegacy(const cbPKT_FILECFG& leg) const { + ::cbPKT_FILECFG cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.options = leg.options; + cur.duration = leg.duration; + cur.recording = leg.recording; + cur.extctrl = leg.extctrl; + copyArr(cur.username, leg.username); + copyArr(cur.filename, leg.filename); // aka datetime + copyArr(cur.comment, leg.comment); + return cur; +} + +NativeConfigBuffer Adapter::fromLegacy(const cbCFGBUFF& leg) const { + // TODO: VERIFY that each list that's assumed to be instrument-independent is in fact independent from any particular instrument. + NativeConfigBuffer cur{}; + cur.version = leg.version; + cur.sysflags = leg.sysflags; + cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); + cur.sysinfo = fromLegacy(leg.sysinfo); + cur.procinfo = fromLegacy(leg.procinfo[instrument_idx]); + copyArr(cur.bankinfo, leg.bankinfo[instrument_idx], this, &Adapter::fromLegacy); + copyArr(cur.groupinfo, leg.groupinfo[instrument_idx], this, &Adapter::fromLegacy); + copyArr(cur.filtinfo, leg.filtinfo[instrument_idx], this, &Adapter::fromLegacy); + cur.adaptinfo = fromLegacy(leg.adaptinfo[instrument_idx]); + cur.refelecinfo = fromLegacy(leg.refelecinfo[instrument_idx]); + copyArr(cur.chaninfo, leg.chaninfo, this, &Adapter::fromLegacy); + copyArr(cur.asBasis, leg.isSortingOptions.asBasis, this, &Adapter::fromLegacy); + copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); + // TODO: Move native isSortingOptions fields into a struct + cur.pktDetect = fromLegacy(leg.isSortingOptions.pktDetect); + cur.pktArtifReject = fromLegacy(leg.isSortingOptions.pktArtifReject); + copyArr(cur.pktNoiseBoundary, leg.isSortingOptions.pktNoiseBoundary, this, &Adapter::fromLegacy); + cur.pktStatistics = fromLegacy(leg.isSortingOptions.pktStatistics); + cur.pktStatus = fromLegacy(leg.isSortingOptions.pktStatus); + copyArr(cur.isNTrodeInfo, leg.isNTrodeInfo, this, &Adapter::fromLegacy); + copyArr2D(cur.isWaveform, leg.isWaveform, this, &Adapter::fromLegacy); + cur.isLnc = fromLegacy(leg.isLnc[instrument_idx]); + cur.isNPlay = fromLegacy(leg.isNPlay); + copyArr(cur.isVideoSource, leg.isVideoSource, this, &Adapter::fromLegacy); + copyArr(cur.isTrackObj, leg.isTrackObj, this, &Adapter::fromLegacy); + cur.fileinfo = fromLegacy(leg.fileinfo); + + return cur; +} + +NativeNSPStatus Adapter::fromLegacy(const NSPStatus& leg) const { + switch(leg) { + case NSPStatus::NSP_INIT: + return NativeNSPStatus::NSP_INIT; + case NSPStatus::NSP_NOIPADDR: + return NativeNSPStatus::NSP_NOIPADDR; + case NSPStatus::NSP_NOREPLY: + return NativeNSPStatus::NSP_NOREPLY; + case NSPStatus::NSP_FOUND: + return NativeNSPStatus::NSP_FOUND; + case NSPStatus::NSP_INVALID: + default: + return NativeNSPStatus::NSP_INVALID; + } +} + +::cbPKT_UNIT_SELECTION Adapter::fromLegacy(const cbPKT_UNIT_SELECTION& leg) const { + ::cbPKT_UNIT_SELECTION cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.lastchan = leg.lastchan; + copyArr(cur.abyUnitSelections, leg.abyUnitSelections); + return cur; +} + +NativePCStatus Adapter::fromLegacy(const cbPcStatus& leg) const { + NativePCStatus cur{}; + cur.isSelection = fromLegacy(leg.isSelection[instrument_idx]); + cur.m_iBlockRecording = leg.m_iBlockRecording; + cur.m_nPCStatusFlags = leg.m_nPCStatusFlags; + cur.m_nNumFEChans = leg.m_nNumFEChans; + cur.m_nNumAnainChans = leg.m_nNumAnainChans; + cur.m_nNumAnalogChans = leg.m_nNumAnalogChans; + cur.m_nNumAoutChans = leg.m_nNumAoutChans; + cur.m_nNumAudioChans = leg.m_nNumAudioChans; + cur.m_nNumAnalogoutChans = leg.m_nNumAnalogoutChans; + cur.m_nNumDiginChans = leg.m_nNumDiginChans; + cur.m_nNumSerialChans = leg.m_nNumSerialChans; + cur.m_nNumDigoutChans = leg.m_nNumDigoutChans; + cur.m_nNumTotalChans = leg.m_nNumTotalChans; + cur.m_nNspStatus = fromLegacy(leg.m_nNspStatus[instrument_idx]); + cur.m_nNumNTrodesPerInstrument = leg.m_nNumNTrodesPerInstrument[instrument_idx]; + cur.m_nGeminiSystem = leg.m_nGeminiSystem; + // ignore APP_WORKSPACE + return cur; +} + +NativeReceiveBuffer Adapter::fromLegacy(const cbRECBUFF& leg) const { + NativeReceiveBuffer cur{}; + cur.received = leg.received; + cur.lasttime = leg.lasttime; + cur.headwrap = leg.headwrap; + cur.headindex = leg.headindex; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +NativeTransmitBuffer Adapter::fromLegacy(const cbXMTBUFF& leg) const { + NativeTransmitBuffer cur{}; + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +NativeTransmitBufferLocal Adapter::fromLegacy(const cbXMTBUFFLOCAL& leg) const { + NativeTransmitBufferLocal cur{}; + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +cbPKT_HEADER Adapter::toLegacy(const ::cbPKT_HEADER& cur) const { + cbPKT_HEADER leg{}; + leg.time = cur.time; + leg.chid = cur.chid; + leg.type = cur.type; + leg.dlen = cur.dlen; + leg.instrument = cur.instrument; + leg.reserved = cur.reserved; + return leg; +} + +cbPKT_SYSINFO Adapter::toLegacy(const ::cbPKT_SYSINFO& cur) const { + cbPKT_SYSINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.sysfreq = cur.sysfreq; + leg.spikelen = cur.spikelen; + leg.spikepre = cur.spikepre; + leg.resetque = cur.resetque; + leg.runlevel = cur.runlevel; + leg.runflags = cur.runflags; + return leg; +} + +cbPKT_PROCINFO Adapter::toLegacy(const ::cbPKT_PROCINFO& cur) const { + cbPKT_PROCINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.idcode = cur.idcode; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; + leg.bankcount = cur.bankcount; + leg.groupcount = cur.groupcount; + leg.filtcount = cur.filtcount; + leg.sortcount = cur.sortcount; + leg.unitcount = cur.unitcount; + leg.hoopcount = cur.hoopcount; + leg.reserved = cur.reserved; + leg.version = cur.version; + return leg; +} + +cbPKT_BANKINFO Adapter::toLegacy(const ::cbPKT_BANKINFO& cur) const { + cbPKT_BANKINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + copyArr(leg.label, cur.label); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; + return leg; +} + +cbPKT_GROUPINFO Adapter::toLegacy(const ::cbPKT_GROUPINFO& cur) const { + cbPKT_GROUPINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.group = cur.group; + copyArr(leg.label, cur.label); + leg.period = cur.period; + leg.length = cur.length; + copyArr(leg.list, cur.list); + return leg; +} + +cbPKT_FILTINFO Adapter::toLegacy(const ::cbPKT_FILTINFO& cur) const { + cbPKT_FILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.filt = cur.filt; + copyArr(leg.label, cur.label); + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; + leg.gain = cur.gain; + leg.sos1a1 = cur.sos1a1; + leg.sos1a2 = cur.sos1a2; + leg.sos1b1 = cur.sos1b1; + leg.sos1b2 = cur.sos1b2; + leg.sos2a1 = cur.sos2a1; + leg.sos2a2 = cur.sos2a2; + leg.sos2b1 = cur.sos2b1; + leg.sos2b2 = cur.sos2b2; + return leg; +} + +cbPKT_ADAPTFILTINFO Adapter::toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) const { + cbPKT_ADAPTFILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.dLearningRate = cur.dLearningRate; + leg.nRefChan1 = cur.nRefChan1; + leg.nRefChan2 = cur.nRefChan2; + return leg; +} + +cbPKT_REFELECFILTINFO Adapter::toLegacy(const ::cbPKT_REFELECFILTINFO& cur) const { + cbPKT_REFELECFILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.nRefChan = cur.nRefChan; + return leg; +} + +cbSCALING Adapter::toLegacy(const ::cbSCALING& cur) const { + cbSCALING leg{}; + leg.digmin = cur.digmin; + leg.digmax = cur.digmax; + leg.anamin = cur.anamin; + leg.anamax = cur.anamax; + leg.anagain = cur.anagain; + copyArr(leg.anaunit, cur.anaunit); + return leg; +} + +cbFILTDESC Adapter::toLegacy(const ::cbFILTDESC& cur) const { + cbFILTDESC leg{}; + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; + return leg; +} + +cbMANUALUNITMAPPING Adapter::toLegacy(const ::cbMANUALUNITMAPPING& cur) const { + cbMANUALUNITMAPPING leg{}; + leg.nOverride = cur.nOverride; + copyArr(leg.afOrigin, cur.afOrigin); + copyArr2D(leg.afShape, cur.afShape); + leg.aPhi = cur.aPhi; + leg.bValid = cur.bValid; + return leg; +} + +cbHOOP Adapter::toLegacy(const ::cbHOOP& cur) const { + cbHOOP leg{}; + leg.valid = cur.valid; + leg.time = cur.time; + leg.min = cur.min; + leg.max = cur.max; + return leg; +} + +cbPKT_CHANINFO Adapter::toLegacy(const ::cbPKT_CHANINFO& cur) const { + cbPKT_CHANINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.term = cur.term; + leg.chancaps = cur.chancaps; + leg.doutcaps = cur.doutcaps; + leg.dinpcaps = cur.dinpcaps; + leg.aoutcaps = cur.aoutcaps; + leg.ainpcaps = cur.ainpcaps; + leg.spkcaps = cur.spkcaps; + leg.physcalin = toLegacy(cur.physcalin); + leg.phyfiltin = toLegacy(cur.phyfiltin); + leg.physcalout = toLegacy(cur.physcalout); + leg.phyfiltout = toLegacy(cur.phyfiltout); + copyArr(leg.label, cur.label); + leg.userflags = cur.userflags; + copyArr(leg.position, cur.position); + leg.scalin = toLegacy(cur.scalin); + leg.scalout = toLegacy(cur.scalout); + leg.doutopts = cur.doutopts; + leg.dinpopts = cur.dinpopts; + leg.aoutopts = cur.aoutopts; + leg.eopchar = cur.eopchar; + leg.moninst = cur.moninst; // aka lowsamples + leg.monchan = cur.monchan; // aka highsamples + leg.outvalue = cur.outvalue; // aka offset + leg.trigtype = cur.trigtype; + copyArr(leg.reserved, cur.reserved); + leg.triginst = cur.triginst; + leg.trigchan = cur.trigchan; + leg.trigval = cur.trigval; + leg.ainpopts = cur.ainpopts; + leg.lncrate = cur.lncrate; + leg.smpfilter = cur.smpfilter; + leg.smpgroup = cur.smpgroup; + leg.smpdispmin = cur.smpdispmin; + leg.smpdispmax = cur.smpdispmax; + leg.spkfilter = cur.spkfilter; + leg.spkdispmax = cur.spkdispmax; + leg.lncdispmax = cur.lncdispmax; + leg.spkopts = cur.spkopts; + leg.spkthrlevel = cur.spkthrlevel; + leg.spkthrlimit = cur.spkthrlimit; + leg.spkgroup = cur.spkgroup; + leg.amplrejpos = cur.amplrejpos; + leg.amplrejneg = cur.amplrejneg; + leg.refelecchan = cur.refelecchan; + copyArr(leg.unitmapping, cur.unitmapping, this, &Adapter::toLegacy); + copyArr2D(leg.spkhoops, cur.spkhoops, this, &Adapter::toLegacy); + return leg; +} + +cbPKT_FS_BASIS Adapter::toLegacy(const ::cbPKT_FS_BASIS& cur) const { + cbPKT_FS_BASIS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.fs = cur.fs; + copyArr2D(leg.basis, cur.basis); + return leg; +} + +cbPKT_SS_MODELSET Adapter::toLegacy(const ::cbPKT_SS_MODELSET& cur) const { + cbPKT_SS_MODELSET leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.unit_number = cur.unit_number; + leg.valid = cur.valid; + leg.inverted = cur.inverted; + leg.num_samples = cur.num_samples; + copyArr(leg.mu_x, cur.mu_x); + copyArr2D(leg.Sigma_x, cur.Sigma_x); + leg.determinant_Sigma_x = cur.determinant_Sigma_x; + copyArr2D(leg.Sigma_x_inv, cur.Sigma_x_inv); + leg.log_determinant_Sigma_x = cur.log_determinant_Sigma_x; + leg.subcluster_spread_factor_numerator = cur.subcluster_spread_factor_numerator; + leg.subcluster_spread_factor_denominator = cur.subcluster_spread_factor_denominator; + leg.mu_e = cur.mu_e; + leg.sigma_e_squared = cur.sigma_e_squared; + return leg; +} + +cbPKT_SS_DETECT Adapter::toLegacy(const ::cbPKT_SS_DETECT& cur) const { + cbPKT_SS_DETECT leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.fThreshold = cur.fThreshold; + leg.fMultiplier = cur.fMultiplier; + return leg; +} + +cbPKT_SS_ARTIF_REJECT Adapter::toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) const { + cbPKT_SS_ARTIF_REJECT leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.nMaxSimulChans = cur.nMaxSimulChans; + leg.nRefractoryCount = cur.nRefractoryCount; + return leg; +} + +cbPKT_SS_NOISE_BOUNDARY Adapter::toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) const { + cbPKT_SS_NOISE_BOUNDARY leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + copyArr(leg.afc, cur.afc); + copyArr2D(leg.afS, cur.afS); + return leg; +} + +cbPKT_SS_STATISTICS Adapter::toLegacy(const ::cbPKT_SS_STATISTICS& cur) const { + cbPKT_SS_STATISTICS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.nUpdateSpikes = cur.nUpdateSpikes; + leg.nAutoalg = cur.nAutoalg; + leg.nMode = cur.nMode; + leg.fMinClusterPairSpreadFactor = cur.fMinClusterPairSpreadFactor; + leg.fMaxSubclusterSpreadFactor = cur.fMaxSubclusterSpreadFactor; + leg.fMinClusterHistCorrMajMeasure = cur.fMinClusterHistCorrMajMeasure; + leg.fMaxClusterPairHistCorrMajMeasure = cur.fMaxClusterPairHistCorrMajMeasure; + leg.fClusterHistValleyPercentage = cur.fClusterHistValleyPercentage; + leg.fClusterHistClosePeakPercentage = cur.fClusterHistClosePeakPercentage; + leg.fClusterHistMinPeakPercentage = cur.fClusterHistMinPeakPercentage; + leg.nWaveBasisSize = cur.nWaveBasisSize; + leg.nWaveSampleSize = cur.nWaveSampleSize; + return leg; +} + +cbAdaptControl Adapter::toLegacy(const ::cbAdaptControl& cur) const { + cbAdaptControl leg{}; + leg.nMode = cur.nMode; + leg.fTimeOutMinutes = cur.fTimeOutMinutes; + leg.fElapsedMinutes = cur.fElapsedMinutes; + return leg; +} + +cbPKT_SS_STATUS Adapter::toLegacy(const ::cbPKT_SS_STATUS& cur) const { + cbPKT_SS_STATUS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cntlUnitStats = toLegacy(cur.cntlUnitStats); + leg.cntlNumUnits = toLegacy(cur.cntlNumUnits); + return leg; +} + +cbSPIKE_SORTING Adapter::toLegacy(const ::cbproto::SpikeSorting& cur) const { + cbSPIKE_SORTING leg{}; + copyArr(leg.asBasis, cur.basis, this, &Adapter::toLegacy); + copyArr2D(leg.asSortModel, cur.models, this, &Adapter::toLegacy); + leg.pktDetect = toLegacy(cur.detect); + leg.pktArtifReject = toLegacy(cur.artifact_reject); + copyArr(leg.pktNoiseBoundary, cur.noise_boundary, this, &Adapter::toLegacy); + leg.pktStatistics = toLegacy(cur.statistics); + leg.pktStatus = toLegacy(cur.status); + return leg; +} + +cbPKT_NTRODEINFO Adapter::toLegacy(const ::cbPKT_NTRODEINFO& cur) const { + cbPKT_NTRODEINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.ntrode = cur.ntrode; + copyArr(leg.label, cur.label); + copyArr2D(leg.ellipses, cur.ellipses, this, &Adapter::toLegacy); + leg.nSite = cur.nSite; + leg.fs = cur.fs; + copyArr(leg.nChan, cur.nChan); + return leg; +} + +cbWaveformData Adapter::toLegacy(const ::cbWaveformData& cur) const { + cbWaveformData leg{}; + leg.offset = cur.offset; // aka sineFrequency + leg.seq = cur.seq; // aka sineAmplitude + leg.seqTotal = cur.seqTotal; + leg.phases = cur.phases; + copyArr(leg.duration, cur.duration); + copyArr(leg.amplitude, cur.amplitude); + return leg; +} + +cbPKT_AOUT_WAVEFORM Adapter::toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const { + cbPKT_AOUT_WAVEFORM leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.repeats = cur.repeats; + leg.trig = cur.trig; + leg.trigInst = cur.trigInst; + leg.trigChan = cur.trigChan; + leg.trigValue = cur.trigValue; + leg.trigNum = cur.trigNum; + leg.active = cur.active; + leg.wave = toLegacy(cur.wave); + return leg; +} + +cbPKT_LNC Adapter::toLegacy(const ::cbPKT_LNC& cur) const { + cbPKT_LNC leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.lncFreq = cur.lncFreq; + leg.lncRefChan = cur.lncRefChan; + leg.lncGlobalMode = cur.lncGlobalMode; + return leg; +} + +cbPKT_NPLAY Adapter::toLegacy(const ::cbPKT_NPLAY& cur) const { + cbPKT_NPLAY leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.ftime = cur.ftime; // aka opt + leg.stime = cur.stime; + leg.etime = cur.etime; + leg.val = cur.val; + leg.mode = cur.mode; + leg.flags = cur.flags; + leg.speed = cur.speed; + copyArr(leg.fname, cur.fname); + return leg; +} + +cbVIDEOSOURCE Adapter::toLegacy(const ::cbVIDEOSOURCE& cur) const { + cbVIDEOSOURCE leg{}; + copyArr(leg.name, cur.name); + leg.fps = cur.fps; + return leg; +} + +cbTRACKOBJ Adapter::toLegacy(const ::cbTRACKOBJ& cur) const { + cbTRACKOBJ leg{}; + copyArr(leg.name, cur.name); + leg.type = cur.type; + leg.pointCount = cur.pointCount; + return leg; +} + +cbPKT_FILECFG Adapter::toLegacy(const ::cbPKT_FILECFG& cur) const { + cbPKT_FILECFG leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.options = cur.options; + leg.duration = cur.duration; + leg.recording = cur.recording; + leg.extctrl = cur.extctrl; + copyArr(leg.username, cur.username); + copyArr(leg.filename, cur.filename); // aka datetime + copyArr(leg.comment, cur.comment); + return leg; +} + +NSPStatus Adapter::toLegacy(const NativeNSPStatus& cur) const { + switch(cur) { + case NativeNSPStatus::NSP_INIT: + return NSPStatus::NSP_INIT; + case NativeNSPStatus::NSP_NOIPADDR: + return NSPStatus::NSP_NOIPADDR; + case NativeNSPStatus::NSP_NOREPLY: + return NSPStatus::NSP_NOREPLY; + case NativeNSPStatus::NSP_FOUND: + return NSPStatus::NSP_FOUND; + case NativeNSPStatus::NSP_INVALID: + default: + return NSPStatus::NSP_INVALID; + } +} + +cbPKT_UNIT_SELECTION Adapter::toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const { + cbPKT_UNIT_SELECTION leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.lastchan = cur.lastchan; + copyArr(leg.abyUnitSelections, cur.abyUnitSelections); + return leg; +} + +cbPcStatus Adapter::toLegacy(const NativePCStatus& cur) const { + cbPcStatus leg{}; + leg.isSelection[instrument_idx] = toLegacy(cur.isSelection); + leg.m_iBlockRecording = cur.m_iBlockRecording; + leg.m_nPCStatusFlags = cur.m_nPCStatusFlags; + leg.m_nNumFEChans = cur.m_nNumFEChans; + leg.m_nNumAnainChans = cur.m_nNumAnainChans; + leg.m_nNumAnalogChans = cur.m_nNumAnalogChans; + leg.m_nNumAoutChans = cur.m_nNumAoutChans; + leg.m_nNumAudioChans = cur.m_nNumAudioChans; + leg.m_nNumAnalogoutChans = cur.m_nNumAnalogoutChans; + leg.m_nNumDiginChans = cur.m_nNumDiginChans; + leg.m_nNumSerialChans = cur.m_nNumSerialChans; + leg.m_nNumDigoutChans = cur.m_nNumDigoutChans; + leg.m_nNumTotalChans = cur.m_nNumTotalChans; + leg.m_nNspStatus[instrument_idx] = toLegacy(cur.m_nNspStatus); + leg.m_nNumNTrodesPerInstrument[instrument_idx] = cur.m_nNumNTrodesPerInstrument; + leg.m_nGeminiSystem = cur.m_nGeminiSystem; + // ignore APP_WORKSPACE + return leg; +} + +cbRECBUFF Adapter::toLegacy(const NativeReceiveBuffer& cur) const { + cbRECBUFF leg{}; + leg.received = cur.received; + leg.lasttime = cur.lasttime; + leg.headwrap = cur.headwrap; + leg.headindex = cur.headindex; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +cbXMTBUFF Adapter::toLegacy(const NativeTransmitBuffer& cur) const { + cbXMTBUFF leg{}; + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +cbXMTBUFFLOCAL Adapter::toLegacy(const NativeTransmitBufferLocal& cur) const { + cbXMTBUFFLOCAL leg{}; + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +Adapter::Adapter(uint8_t instrument_idx, void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) + : instrument_idx(instrument_idx) + , cfg(static_cast(cfg_ptr)) , rec(static_cast(rec_ptr)) , xmt(static_cast(xmt_ptr)) , xmt_local(static_cast(xmt_local_ptr)) @@ -52,6 +1039,10 @@ Adapter::Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_pt , spike(static_cast(spike_ptr)) {} +uint32_t Adapter::getMaxProcs() const { + return cbMAXPROCS; +} + uint32_t& Adapter::getRecReceived() { return rec->received; } @@ -124,14 +1115,14 @@ uint32_t* Adapter::getLocalXmtBufferPtr() { return xmt->buffer; } -Result<::cbPKT_PROCINFO> Adapter::getProcInfo(uint8_t instrument_idx) const { +Result<::cbPKT_PROCINFO> Adapter::getProcInfo() const { if (instrument_idx >= std::size(cfg->procinfo)) { return Result<::cbPKT_PROCINFO>::error("Instrument index out of range"); } - return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx], {})); + return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx])); } -Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const { +Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint32_t bank_num) const { if (instrument_idx >= std::size(cfg->bankinfo)) { return Result<::cbPKT_BANKINFO>::error("Instrument index out of range"); } @@ -139,10 +1130,10 @@ Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t b if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result<::cbPKT_BANKINFO>::error("Bank number out of range"); } - return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx], {})); + return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx])); } -Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const { +Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint32_t filter_num) const { if (instrument_idx >= std::size(cfg->filtinfo)) { return Result<::cbPKT_FILTINFO>::error("Instrument index out of range"); } @@ -150,53 +1141,53 @@ Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result<::cbPKT_FILTINFO>::error("Filter number out of range"); } - return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx], {})); + return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx])); } Result<::cbPKT_CHANINFO> Adapter::getChanInfo(uint32_t channel_idx) const { if (channel_idx >= std::size(cfg->chaninfo)) { return Result<::cbPKT_CHANINFO>::error("Channel number out of range"); } - return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx], {})); + return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx])); } Result<::cbPKT_SYSINFO> Adapter::getSysInfo() const { - return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo, {})); + return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo)); } -Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const { +Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint32_t group_idx) const { if (instrument_idx >= std::size(cfg->groupinfo)) { return Result<::cbPKT_GROUPINFO>::error("Instrument index out of range"); } if (group_idx >= std::size(cfg->groupinfo[0])) { return Result<::cbPKT_GROUPINFO>::error("Group index out of range"); } - return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx], {})); + return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx])); } -Result Adapter::getConfigBuffer(uint8_t instrument_idx) const { +Result Adapter::getConfigBuffer() const { if (instrument_idx >= std::size(cfg->procinfo)) { return Result::error("Instrument index out of range"); } - return Result::ok(fromLegacy(*cfg, { .instrument_idx = instrument_idx })); + return Result::ok(fromLegacy(*cfg)); } -Result Adapter::getPcStatus(uint8_t instrument_idx) const { +Result Adapter::getPcStatus() const { if (instrument_idx >= std::size(status->isSelection)) { return Result::error("Instrument index out of range"); } - return Result::ok(fromLegacy(*status, { .instrument_idx = instrument_idx })); + return Result::ok(fromLegacy(*status)); } -Result Adapter::setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) { +Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { if (instrument_idx >= std::size(cfg->procinfo)) { return Result::error("Instrument index out of range"); } - cfg->procinfo[instrument_idx] = toLegacy(info, {}); + cfg->procinfo[instrument_idx] = toLegacy(info); return Result::ok(); } -Result Adapter::setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) { +Result Adapter::setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) { if (instrument_idx >= std::size(cfg->bankinfo)) { return Result::error("Instrument index out of range"); } @@ -204,11 +1195,11 @@ Result Adapter::setBankInfo(uint8_t instrument_idx, uint32_t bank_num, con if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result::error("Bank number out of range"); } - cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info, {}); + cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info); return Result::ok(); } -Result Adapter::setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) { +Result Adapter::setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) { if (instrument_idx >= std::size(cfg->filtinfo)) { return Result::error("Instrument index out of range"); } @@ -216,7 +1207,7 @@ Result Adapter::setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result::error("Filter number out of range"); } - cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info, {}); + cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info); return Result::ok(); } @@ -224,31 +1215,31 @@ Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& if (channel_idx >= std::size(cfg->chaninfo)) { return Result::error("Channel number out of range"); } - cfg->chaninfo[channel_idx] = toLegacy(info, {}); + cfg->chaninfo[channel_idx] = toLegacy(info); return Result::ok(); } Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { - cfg->sysinfo = toLegacy(info, {}); + cfg->sysinfo = toLegacy(info); return Result::ok(); } -Result Adapter::setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { +Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { if (instrument_idx >= std::size(cfg->groupinfo)) { return Result::error("Instrument index out of range"); } if (group_idx >= std::size(cfg->groupinfo[0])) { return Result::error("Group index out of range"); } - cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info, {}); + cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info); return Result::ok(); } -Result Adapter::setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const { +Result Adapter::setPcStatus(const NativePCStatus& status) const { if (instrument_idx >= std::size(this->status->isSelection)) { return Result::error("Instrument index out of range"); } - *(this->status) = toLegacy(status, { .instrument_idx = instrument_idx }); + *(this->status) = toLegacy(status); return Result::ok(); } diff --git a/src/cbshm/src/central_adapters/v4_2.cpp b/src/cbshm/src/central_adapters/v4_2.cpp index 414cc09c..b58e79a9 100644 --- a/src/cbshm/src/central_adapters/v4_2.cpp +++ b/src/cbshm/src/central_adapters/v4_2.cpp @@ -8,7 +8,6 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// #include -#include #include namespace cbshm { @@ -43,8 +42,996 @@ size_t BootstrapAdapter::getReceiveBufferLen() const { return sizeof(cbRECBUFFLEN); } -Adapter::Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) - : cfg(static_cast(cfg_ptr)) +::cbPKT_HEADER Adapter::fromLegacy(const cbPKT_HEADER& leg) const { + ::cbPKT_HEADER cur{}; + cur.time = leg.time; + cur.chid = leg.chid; + cur.type = leg.type; + cur.dlen = leg.dlen; + cur.instrument = leg.instrument; + cur.reserved = leg.reserved; + return cur; +} + +::cbPKT_SYSINFO Adapter::fromLegacy(const cbPKT_SYSINFO& leg) const { + ::cbPKT_SYSINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.sysfreq = leg.sysfreq; + cur.spikelen = leg.spikelen; + cur.spikepre = leg.spikepre; + cur.resetque = leg.resetque; + cur.runlevel = leg.runlevel; + cur.runflags = leg.runflags; + return cur; +} + +::cbPKT_PROCINFO Adapter::fromLegacy(const cbPKT_PROCINFO& leg) const { + ::cbPKT_PROCINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.idcode = leg.idcode; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; + cur.bankcount = leg.bankcount; + cur.groupcount = leg.groupcount; + cur.filtcount = leg.filtcount; + cur.sortcount = leg.sortcount; + cur.unitcount = leg.unitcount; + cur.hoopcount = leg.hoopcount; + cur.reserved = leg.reserved; + cur.version = leg.version; + return cur; +} + +::cbPKT_BANKINFO Adapter::fromLegacy(const cbPKT_BANKINFO& leg) const { + ::cbPKT_BANKINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + copyArr(cur.label, leg.label); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; + return cur; +} + +::cbPKT_GROUPINFO Adapter::fromLegacy(const cbPKT_GROUPINFO& leg) const { + ::cbPKT_GROUPINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.group = leg.group; + copyArr(cur.label, leg.label); + cur.period = leg.period; + cur.length = leg.length; + copyArr(cur.list, leg.list); + return cur; +} + +::cbPKT_FILTINFO Adapter::fromLegacy(const cbPKT_FILTINFO& leg) const { + ::cbPKT_FILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.proc = leg.proc; + cur.filt = leg.filt; + copyArr(cur.label, leg.label); + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; + cur.gain = leg.gain; + cur.sos1a1 = leg.sos1a1; + cur.sos1a2 = leg.sos1a2; + cur.sos1b1 = leg.sos1b1; + cur.sos1b2 = leg.sos1b2; + cur.sos2a1 = leg.sos2a1; + cur.sos2a2 = leg.sos2a2; + cur.sos2b1 = leg.sos2b1; + cur.sos2b2 = leg.sos2b2; + return cur; +} + +::cbPKT_ADAPTFILTINFO Adapter::fromLegacy(const cbPKT_ADAPTFILTINFO& leg) const { + ::cbPKT_ADAPTFILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.dLearningRate = leg.dLearningRate; + cur.nRefChan1 = leg.nRefChan1; + cur.nRefChan2 = leg.nRefChan2; + return cur; +} + +::cbPKT_REFELECFILTINFO Adapter::fromLegacy(const cbPKT_REFELECFILTINFO& leg) const { + ::cbPKT_REFELECFILTINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.nRefChan = leg.nRefChan; + return cur; +} + +::cbSCALING Adapter::fromLegacy(const cbSCALING& leg) const { + ::cbSCALING cur{}; + cur.digmin = leg.digmin; + cur.digmax = leg.digmax; + cur.anamin = leg.anamin; + cur.anamax = leg.anamax; + cur.anagain = leg.anagain; + copyArr(cur.anaunit, leg.anaunit); + return cur; +} + +::cbFILTDESC Adapter::fromLegacy(const cbFILTDESC& leg) const { + ::cbFILTDESC cur{}; + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; + return cur; +} + +::cbMANUALUNITMAPPING Adapter::fromLegacy(const cbMANUALUNITMAPPING& leg) const { + ::cbMANUALUNITMAPPING cur{}; + cur.nOverride = leg.nOverride; + copyArr(cur.afOrigin, leg.afOrigin); + copyArr2D(cur.afShape, leg.afShape); + cur.aPhi = leg.aPhi; + cur.bValid = leg.bValid; + return cur; +} + +::cbHOOP Adapter::fromLegacy(const cbHOOP& leg) const { + ::cbHOOP cur{}; + cur.valid = leg.valid; + cur.time = leg.time; + cur.min = leg.min; + cur.max = leg.max; + return cur; +} + +::cbPKT_CHANINFO Adapter::fromLegacy(const cbPKT_CHANINFO& leg) const { + ::cbPKT_CHANINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.term = leg.term; + cur.chancaps = leg.chancaps; + cur.doutcaps = leg.doutcaps; + cur.dinpcaps = leg.dinpcaps; + cur.aoutcaps = leg.aoutcaps; + cur.ainpcaps = leg.ainpcaps; + cur.spkcaps = leg.spkcaps; + cur.physcalin = fromLegacy(leg.physcalin); + cur.phyfiltin = fromLegacy(leg.phyfiltin); + cur.physcalout = fromLegacy(leg.physcalout); + cur.phyfiltout = fromLegacy(leg.phyfiltout); + copyArr(cur.label, leg.label); + cur.userflags = leg.userflags; + copyArr(cur.position, leg.position); + cur.scalin = fromLegacy(leg.scalin); + cur.scalout = fromLegacy(leg.scalout); + cur.doutopts = leg.doutopts; + cur.dinpopts = leg.dinpopts; + cur.aoutopts = leg.aoutopts; + cur.eopchar = leg.eopchar; + cur.moninst = leg.moninst; // aka lowsamples + cur.monchan = leg.monchan; // aka highsamples + cur.outvalue = leg.outvalue; // aka offset + cur.trigtype = leg.trigtype; + copyArr(cur.reserved, leg.reserved); + cur.triginst = leg.triginst; + cur.trigchan = leg.trigchan; + cur.trigval = leg.trigval; + cur.ainpopts = leg.ainpopts; + cur.lncrate = leg.lncrate; + cur.smpfilter = leg.smpfilter; + cur.smpgroup = leg.smpgroup; + cur.smpdispmin = leg.smpdispmin; + cur.smpdispmax = leg.smpdispmax; + cur.spkfilter = leg.spkfilter; + cur.spkdispmax = leg.spkdispmax; + cur.lncdispmax = leg.lncdispmax; + cur.spkopts = leg.spkopts; + cur.spkthrlevel = leg.spkthrlevel; + cur.spkthrlimit = leg.spkthrlimit; + cur.spkgroup = leg.spkgroup; + cur.amplrejpos = leg.amplrejpos; + cur.amplrejneg = leg.amplrejneg; + cur.refelecchan = leg.refelecchan; + copyArr(cur.unitmapping, leg.unitmapping, this, &Adapter::fromLegacy); + copyArr2D(cur.spkhoops, leg.spkhoops, this, &Adapter::fromLegacy); + return cur; +} + +::cbPKT_FS_BASIS Adapter::fromLegacy(const cbPKT_FS_BASIS& leg) const { + ::cbPKT_FS_BASIS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.fs = leg.fs; + copyArr2D(cur.basis, leg.basis); + return cur; +} + +::cbPKT_SS_MODELSET Adapter::fromLegacy(const cbPKT_SS_MODELSET& leg) const { + ::cbPKT_SS_MODELSET cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.unit_number = leg.unit_number; + cur.valid = leg.valid; + cur.inverted = leg.inverted; + cur.num_samples = leg.num_samples; + copyArr(cur.mu_x, leg.mu_x); + copyArr2D(cur.Sigma_x, leg.Sigma_x); + cur.determinant_Sigma_x = leg.determinant_Sigma_x; + copyArr2D(cur.Sigma_x_inv, leg.Sigma_x_inv); + cur.log_determinant_Sigma_x = leg.log_determinant_Sigma_x; + cur.subcluster_spread_factor_numerator = leg.subcluster_spread_factor_numerator; + cur.subcluster_spread_factor_denominator = leg.subcluster_spread_factor_denominator; + cur.mu_e = leg.mu_e; + cur.sigma_e_squared = leg.sigma_e_squared; + return cur; +} + +::cbPKT_SS_DETECT Adapter::fromLegacy(const cbPKT_SS_DETECT& leg) const { + ::cbPKT_SS_DETECT cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.fThreshold = leg.fThreshold; + cur.fMultiplier = leg.fMultiplier; + return cur; +} + +::cbPKT_SS_ARTIF_REJECT Adapter::fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) const { + ::cbPKT_SS_ARTIF_REJECT cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.nMaxSimulChans = leg.nMaxSimulChans; + cur.nRefractoryCount = leg.nRefractoryCount; + return cur; +} + +::cbPKT_SS_NOISE_BOUNDARY Adapter::fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) const { + ::cbPKT_SS_NOISE_BOUNDARY cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + copyArr(cur.afc, leg.afc); + copyArr2D(cur.afS, leg.afS); + return cur; +} + +::cbPKT_SS_STATISTICS Adapter::fromLegacy(const cbPKT_SS_STATISTICS& leg) const { + ::cbPKT_SS_STATISTICS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.nUpdateSpikes = leg.nUpdateSpikes; + cur.nAutoalg = leg.nAutoalg; + cur.nMode = leg.nMode; + cur.fMinClusterPairSpreadFactor = leg.fMinClusterPairSpreadFactor; + cur.fMaxSubclusterSpreadFactor = leg.fMaxSubclusterSpreadFactor; + cur.fMinClusterHistCorrMajMeasure = leg.fMinClusterHistCorrMajMeasure; + cur.fMaxClusterPairHistCorrMajMeasure = leg.fMaxClusterPairHistCorrMajMeasure; + cur.fClusterHistValleyPercentage = leg.fClusterHistValleyPercentage; + cur.fClusterHistClosePeakPercentage = leg.fClusterHistClosePeakPercentage; + cur.fClusterHistMinPeakPercentage = leg.fClusterHistMinPeakPercentage; + cur.nWaveBasisSize = leg.nWaveBasisSize; + cur.nWaveSampleSize = leg.nWaveSampleSize; + return cur; +} + +::cbAdaptControl Adapter::fromLegacy(const cbAdaptControl& leg) const { + ::cbAdaptControl cur{}; + cur.nMode = leg.nMode; + cur.fTimeOutMinutes = leg.fTimeOutMinutes; + cur.fElapsedMinutes = leg.fElapsedMinutes; + return cur; +} + +::cbPKT_SS_STATUS Adapter::fromLegacy(const cbPKT_SS_STATUS& leg) const { + ::cbPKT_SS_STATUS cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats); + cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits); + return cur; +} + +::cbproto::SpikeSorting Adapter::fromLegacy(const cbSPIKE_SORTING& leg) const { + ::cbproto::SpikeSorting cur{}; + copyArr(cur.basis, leg.asBasis, this, &Adapter::fromLegacy); + copyArr2D(cur.models, leg.asSortModel, this, &Adapter::fromLegacy); + cur.detect = fromLegacy(leg.pktDetect); + cur.artifact_reject = fromLegacy(leg.pktArtifReject); + copyArr(cur.noise_boundary, leg.pktNoiseBoundary, this, &Adapter::fromLegacy); + cur.statistics = fromLegacy(leg.pktStatistics); + cur.status = fromLegacy(leg.pktStatus); + return cur; +} + +::cbPKT_NTRODEINFO Adapter::fromLegacy(const cbPKT_NTRODEINFO& leg) const { + ::cbPKT_NTRODEINFO cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.ntrode = leg.ntrode; + copyArr(cur.label, leg.label); + copyArr2D(cur.ellipses, leg.ellipses, this, &Adapter::fromLegacy); + cur.nSite = leg.nSite; + cur.fs = leg.fs; + copyArr(cur.nChan, leg.nChan); + return cur; +} + +::cbWaveformData Adapter::fromLegacy(const cbWaveformData& leg) const { + ::cbWaveformData cur{}; + cur.offset = leg.offset; // aka sineFrequency + cur.seq = leg.seq; // aka sineAmplitude + cur.seqTotal = leg.seqTotal; + cur.phases = leg.phases; + copyArr(cur.duration, leg.duration); + copyArr(cur.amplitude, leg.amplitude); + return cur; +} + +::cbPKT_AOUT_WAVEFORM Adapter::fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const { + ::cbPKT_AOUT_WAVEFORM cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.repeats = leg.repeats; + cur.trig = leg.trig; + cur.trigInst = leg.trigInst; + cur.trigChan = leg.trigChan; + cur.trigValue = leg.trigValue; + cur.trigNum = leg.trigNum; + cur.active = leg.active; + cur.wave = fromLegacy(leg.wave); + return cur; +} + +::cbPKT_LNC Adapter::fromLegacy(const cbPKT_LNC& leg) const { + ::cbPKT_LNC cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.lncFreq = leg.lncFreq; + cur.lncRefChan = leg.lncRefChan; + cur.lncGlobalMode = leg.lncGlobalMode; + return cur; +} + +::cbPKT_NPLAY Adapter::fromLegacy(const cbPKT_NPLAY& leg) const { + ::cbPKT_NPLAY cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.ftime = leg.ftime; // aka opt + cur.stime = leg.stime; + cur.etime = leg.etime; + cur.val = leg.val; + cur.mode = leg.mode; + cur.flags = leg.flags; + cur.speed = leg.speed; + copyArr(cur.fname, leg.fname); + return cur; +} + +::cbVIDEOSOURCE Adapter::fromLegacy(const cbVIDEOSOURCE& leg) const { + ::cbVIDEOSOURCE cur{}; + copyArr(cur.name, leg.name); + cur.fps = leg.fps; + return cur; +} + +::cbTRACKOBJ Adapter::fromLegacy(const cbTRACKOBJ& leg) const { + ::cbTRACKOBJ cur{}; + copyArr(cur.name, leg.name); + cur.type = leg.type; + cur.pointCount = leg.pointCount; + return cur; +} + +::cbPKT_FILECFG Adapter::fromLegacy(const cbPKT_FILECFG& leg) const { + ::cbPKT_FILECFG cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.options = leg.options; + cur.duration = leg.duration; + cur.recording = leg.recording; + cur.extctrl = leg.extctrl; + copyArr(cur.username, leg.username); + copyArr(cur.filename, leg.filename); // aka datetime + copyArr(cur.comment, leg.comment); + return cur; +} + +NativeConfigBuffer Adapter::fromLegacy(const cbCFGBUFF& leg) const { + // TODO: VERIFY that each list that's assumed to be instrument-independent is in fact independent from any particular instrument. + NativeConfigBuffer cur{}; + cur.version = leg.version; + cur.sysflags = leg.sysflags; + cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); + cur.sysinfo = fromLegacy(leg.sysinfo); + cur.procinfo = fromLegacy(leg.procinfo[instrument_idx]); + copyArr(cur.bankinfo, leg.bankinfo[instrument_idx], this, &Adapter::fromLegacy); + copyArr(cur.groupinfo, leg.groupinfo[instrument_idx], this, &Adapter::fromLegacy); + copyArr(cur.filtinfo, leg.filtinfo[instrument_idx], this, &Adapter::fromLegacy); + cur.adaptinfo = fromLegacy(leg.adaptinfo[instrument_idx]); + cur.refelecinfo = fromLegacy(leg.refelecinfo[instrument_idx]); + copyArr(cur.chaninfo, leg.chaninfo, this, &Adapter::fromLegacy); + copyArr(cur.asBasis, leg.isSortingOptions.asBasis, this, &Adapter::fromLegacy); + copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); + // TODO: Move native isSortingOptions fields into a struct + cur.pktDetect = fromLegacy(leg.isSortingOptions.pktDetect); + cur.pktArtifReject = fromLegacy(leg.isSortingOptions.pktArtifReject); + copyArr(cur.pktNoiseBoundary, leg.isSortingOptions.pktNoiseBoundary, this, &Adapter::fromLegacy); + cur.pktStatistics = fromLegacy(leg.isSortingOptions.pktStatistics); + cur.pktStatus = fromLegacy(leg.isSortingOptions.pktStatus); + copyArr(cur.isNTrodeInfo, leg.isNTrodeInfo, this, &Adapter::fromLegacy); + copyArr2D(cur.isWaveform, leg.isWaveform, this, &Adapter::fromLegacy); + cur.isLnc = fromLegacy(leg.isLnc[instrument_idx]); + cur.isNPlay = fromLegacy(leg.isNPlay); + copyArr(cur.isVideoSource, leg.isVideoSource, this, &Adapter::fromLegacy); + copyArr(cur.isTrackObj, leg.isTrackObj, this, &Adapter::fromLegacy); + cur.fileinfo = fromLegacy(leg.fileinfo); + + return cur; +} + +NativeNSPStatus Adapter::fromLegacy(const NSPStatus& leg) const { + switch(leg) { + case NSPStatus::NSP_INIT: + return NativeNSPStatus::NSP_INIT; + case NSPStatus::NSP_NOIPADDR: + return NativeNSPStatus::NSP_NOIPADDR; + case NSPStatus::NSP_NOREPLY: + return NativeNSPStatus::NSP_NOREPLY; + case NSPStatus::NSP_FOUND: + return NativeNSPStatus::NSP_FOUND; + case NSPStatus::NSP_INVALID: + default: + return NativeNSPStatus::NSP_INVALID; + } +} + +::cbPKT_UNIT_SELECTION Adapter::fromLegacy(const cbPKT_UNIT_SELECTION& leg) const { + ::cbPKT_UNIT_SELECTION cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + cur.lastchan = leg.lastchan; + copyArr(cur.abyUnitSelections, leg.abyUnitSelections); + return cur; +} + +NativePCStatus Adapter::fromLegacy(const cbPcStatus& leg) const { + NativePCStatus cur{}; + cur.isSelection = fromLegacy(leg.isSelection[instrument_idx]); + cur.m_iBlockRecording = leg.m_iBlockRecording; + cur.m_nPCStatusFlags = leg.m_nPCStatusFlags; + cur.m_nNumFEChans = leg.m_nNumFEChans; + cur.m_nNumAnainChans = leg.m_nNumAnainChans; + cur.m_nNumAnalogChans = leg.m_nNumAnalogChans; + cur.m_nNumAoutChans = leg.m_nNumAoutChans; + cur.m_nNumAudioChans = leg.m_nNumAudioChans; + cur.m_nNumAnalogoutChans = leg.m_nNumAnalogoutChans; + cur.m_nNumDiginChans = leg.m_nNumDiginChans; + cur.m_nNumSerialChans = leg.m_nNumSerialChans; + cur.m_nNumDigoutChans = leg.m_nNumDigoutChans; + cur.m_nNumTotalChans = leg.m_nNumTotalChans; + cur.m_nNspStatus = fromLegacy(leg.m_nNspStatus[instrument_idx]); + cur.m_nNumNTrodesPerInstrument = leg.m_nNumNTrodesPerInstrument[instrument_idx]; + cur.m_nGeminiSystem = leg.m_nGeminiSystem; + // ignore APP_WORKSPACE + return cur; +} + +NativeReceiveBuffer Adapter::fromLegacy(const cbRECBUFF& leg) const { + NativeReceiveBuffer cur{}; + cur.received = leg.received; + cur.lasttime = leg.lasttime; + cur.headwrap = leg.headwrap; + cur.headindex = leg.headindex; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +NativeTransmitBuffer Adapter::fromLegacy(const cbXMTBUFF& leg) const { + NativeTransmitBuffer cur{}; + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +NativeTransmitBufferLocal Adapter::fromLegacy(const cbXMTBUFFLOCAL& leg) const { + NativeTransmitBufferLocal cur{}; + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); + return cur; +} + +cbPKT_HEADER Adapter::toLegacy(const ::cbPKT_HEADER& cur) const { + cbPKT_HEADER leg{}; + leg.time = cur.time; + leg.chid = cur.chid; + leg.type = cur.type; + leg.dlen = cur.dlen; + leg.instrument = cur.instrument; + leg.reserved = cur.reserved; + return leg; +} + +cbPKT_SYSINFO Adapter::toLegacy(const ::cbPKT_SYSINFO& cur) const { + cbPKT_SYSINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.sysfreq = cur.sysfreq; + leg.spikelen = cur.spikelen; + leg.spikepre = cur.spikepre; + leg.resetque = cur.resetque; + leg.runlevel = cur.runlevel; + leg.runflags = cur.runflags; + return leg; +} + +cbPKT_PROCINFO Adapter::toLegacy(const ::cbPKT_PROCINFO& cur) const { + cbPKT_PROCINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.idcode = cur.idcode; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; + leg.bankcount = cur.bankcount; + leg.groupcount = cur.groupcount; + leg.filtcount = cur.filtcount; + leg.sortcount = cur.sortcount; + leg.unitcount = cur.unitcount; + leg.hoopcount = cur.hoopcount; + leg.reserved = cur.reserved; + leg.version = cur.version; + return leg; +} + +cbPKT_BANKINFO Adapter::toLegacy(const ::cbPKT_BANKINFO& cur) const { + cbPKT_BANKINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + copyArr(leg.label, cur.label); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; + return leg; +} + +cbPKT_GROUPINFO Adapter::toLegacy(const ::cbPKT_GROUPINFO& cur) const { + cbPKT_GROUPINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.group = cur.group; + copyArr(leg.label, cur.label); + leg.period = cur.period; + leg.length = cur.length; + copyArr(leg.list, cur.list); + return leg; +} + +cbPKT_FILTINFO Adapter::toLegacy(const ::cbPKT_FILTINFO& cur) const { + cbPKT_FILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.proc = cur.proc; + leg.filt = cur.filt; + copyArr(leg.label, cur.label); + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; + leg.gain = cur.gain; + leg.sos1a1 = cur.sos1a1; + leg.sos1a2 = cur.sos1a2; + leg.sos1b1 = cur.sos1b1; + leg.sos1b2 = cur.sos1b2; + leg.sos2a1 = cur.sos2a1; + leg.sos2a2 = cur.sos2a2; + leg.sos2b1 = cur.sos2b1; + leg.sos2b2 = cur.sos2b2; + return leg; +} + +cbPKT_ADAPTFILTINFO Adapter::toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) const { + cbPKT_ADAPTFILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.dLearningRate = cur.dLearningRate; + leg.nRefChan1 = cur.nRefChan1; + leg.nRefChan2 = cur.nRefChan2; + return leg; +} + +cbPKT_REFELECFILTINFO Adapter::toLegacy(const ::cbPKT_REFELECFILTINFO& cur) const { + cbPKT_REFELECFILTINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.nRefChan = cur.nRefChan; + return leg; +} + +cbSCALING Adapter::toLegacy(const ::cbSCALING& cur) const { + cbSCALING leg{}; + leg.digmin = cur.digmin; + leg.digmax = cur.digmax; + leg.anamin = cur.anamin; + leg.anamax = cur.anamax; + leg.anagain = cur.anagain; + copyArr(leg.anaunit, cur.anaunit); + return leg; +} + +cbFILTDESC Adapter::toLegacy(const ::cbFILTDESC& cur) const { + cbFILTDESC leg{}; + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; + return leg; +} + +cbMANUALUNITMAPPING Adapter::toLegacy(const ::cbMANUALUNITMAPPING& cur) const { + cbMANUALUNITMAPPING leg{}; + leg.nOverride = cur.nOverride; + copyArr(leg.afOrigin, cur.afOrigin); + copyArr2D(leg.afShape, cur.afShape); + leg.aPhi = cur.aPhi; + leg.bValid = cur.bValid; + return leg; +} + +cbHOOP Adapter::toLegacy(const ::cbHOOP& cur) const { + cbHOOP leg{}; + leg.valid = cur.valid; + leg.time = cur.time; + leg.min = cur.min; + leg.max = cur.max; + return leg; +} + +cbPKT_CHANINFO Adapter::toLegacy(const ::cbPKT_CHANINFO& cur) const { + cbPKT_CHANINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.term = cur.term; + leg.chancaps = cur.chancaps; + leg.doutcaps = cur.doutcaps; + leg.dinpcaps = cur.dinpcaps; + leg.aoutcaps = cur.aoutcaps; + leg.ainpcaps = cur.ainpcaps; + leg.spkcaps = cur.spkcaps; + leg.physcalin = toLegacy(cur.physcalin); + leg.phyfiltin = toLegacy(cur.phyfiltin); + leg.physcalout = toLegacy(cur.physcalout); + leg.phyfiltout = toLegacy(cur.phyfiltout); + copyArr(leg.label, cur.label); + leg.userflags = cur.userflags; + copyArr(leg.position, cur.position); + leg.scalin = toLegacy(cur.scalin); + leg.scalout = toLegacy(cur.scalout); + leg.doutopts = cur.doutopts; + leg.dinpopts = cur.dinpopts; + leg.aoutopts = cur.aoutopts; + leg.eopchar = cur.eopchar; + leg.moninst = cur.moninst; // aka lowsamples + leg.monchan = cur.monchan; // aka highsamples + leg.outvalue = cur.outvalue; // aka offset + leg.trigtype = cur.trigtype; + copyArr(leg.reserved, cur.reserved); + leg.triginst = cur.triginst; + leg.trigchan = cur.trigchan; + leg.trigval = cur.trigval; + leg.ainpopts = cur.ainpopts; + leg.lncrate = cur.lncrate; + leg.smpfilter = cur.smpfilter; + leg.smpgroup = cur.smpgroup; + leg.smpdispmin = cur.smpdispmin; + leg.smpdispmax = cur.smpdispmax; + leg.spkfilter = cur.spkfilter; + leg.spkdispmax = cur.spkdispmax; + leg.lncdispmax = cur.lncdispmax; + leg.spkopts = cur.spkopts; + leg.spkthrlevel = cur.spkthrlevel; + leg.spkthrlimit = cur.spkthrlimit; + leg.spkgroup = cur.spkgroup; + leg.amplrejpos = cur.amplrejpos; + leg.amplrejneg = cur.amplrejneg; + leg.refelecchan = cur.refelecchan; + copyArr(leg.unitmapping, cur.unitmapping, this, &Adapter::toLegacy); + copyArr2D(leg.spkhoops, cur.spkhoops, this, &Adapter::toLegacy); + return leg; +} + +cbPKT_FS_BASIS Adapter::toLegacy(const ::cbPKT_FS_BASIS& cur) const { + cbPKT_FS_BASIS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.fs = cur.fs; + copyArr2D(leg.basis, cur.basis); + return leg; +} + +cbPKT_SS_MODELSET Adapter::toLegacy(const ::cbPKT_SS_MODELSET& cur) const { + cbPKT_SS_MODELSET leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.unit_number = cur.unit_number; + leg.valid = cur.valid; + leg.inverted = cur.inverted; + leg.num_samples = cur.num_samples; + copyArr(leg.mu_x, cur.mu_x); + copyArr2D(leg.Sigma_x, cur.Sigma_x); + leg.determinant_Sigma_x = cur.determinant_Sigma_x; + copyArr2D(leg.Sigma_x_inv, cur.Sigma_x_inv); + leg.log_determinant_Sigma_x = cur.log_determinant_Sigma_x; + leg.subcluster_spread_factor_numerator = cur.subcluster_spread_factor_numerator; + leg.subcluster_spread_factor_denominator = cur.subcluster_spread_factor_denominator; + leg.mu_e = cur.mu_e; + leg.sigma_e_squared = cur.sigma_e_squared; + return leg; +} + +cbPKT_SS_DETECT Adapter::toLegacy(const ::cbPKT_SS_DETECT& cur) const { + cbPKT_SS_DETECT leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.fThreshold = cur.fThreshold; + leg.fMultiplier = cur.fMultiplier; + return leg; +} + +cbPKT_SS_ARTIF_REJECT Adapter::toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) const { + cbPKT_SS_ARTIF_REJECT leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.nMaxSimulChans = cur.nMaxSimulChans; + leg.nRefractoryCount = cur.nRefractoryCount; + return leg; +} + +cbPKT_SS_NOISE_BOUNDARY Adapter::toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) const { + cbPKT_SS_NOISE_BOUNDARY leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + copyArr(leg.afc, cur.afc); + copyArr2D(leg.afS, cur.afS); + return leg; +} + +cbPKT_SS_STATISTICS Adapter::toLegacy(const ::cbPKT_SS_STATISTICS& cur) const { + cbPKT_SS_STATISTICS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.nUpdateSpikes = cur.nUpdateSpikes; + leg.nAutoalg = cur.nAutoalg; + leg.nMode = cur.nMode; + leg.fMinClusterPairSpreadFactor = cur.fMinClusterPairSpreadFactor; + leg.fMaxSubclusterSpreadFactor = cur.fMaxSubclusterSpreadFactor; + leg.fMinClusterHistCorrMajMeasure = cur.fMinClusterHistCorrMajMeasure; + leg.fMaxClusterPairHistCorrMajMeasure = cur.fMaxClusterPairHistCorrMajMeasure; + leg.fClusterHistValleyPercentage = cur.fClusterHistValleyPercentage; + leg.fClusterHistClosePeakPercentage = cur.fClusterHistClosePeakPercentage; + leg.fClusterHistMinPeakPercentage = cur.fClusterHistMinPeakPercentage; + leg.nWaveBasisSize = cur.nWaveBasisSize; + leg.nWaveSampleSize = cur.nWaveSampleSize; + return leg; +} + +cbAdaptControl Adapter::toLegacy(const ::cbAdaptControl& cur) const { + cbAdaptControl leg{}; + leg.nMode = cur.nMode; + leg.fTimeOutMinutes = cur.fTimeOutMinutes; + leg.fElapsedMinutes = cur.fElapsedMinutes; + return leg; +} + +cbPKT_SS_STATUS Adapter::toLegacy(const ::cbPKT_SS_STATUS& cur) const { + cbPKT_SS_STATUS leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.cntlUnitStats = toLegacy(cur.cntlUnitStats); + leg.cntlNumUnits = toLegacy(cur.cntlNumUnits); + return leg; +} + +cbSPIKE_SORTING Adapter::toLegacy(const ::cbproto::SpikeSorting& cur) const { + cbSPIKE_SORTING leg{}; + copyArr(leg.asBasis, cur.basis, this, &Adapter::toLegacy); + copyArr2D(leg.asSortModel, cur.models, this, &Adapter::toLegacy); + leg.pktDetect = toLegacy(cur.detect); + leg.pktArtifReject = toLegacy(cur.artifact_reject); + copyArr(leg.pktNoiseBoundary, cur.noise_boundary, this, &Adapter::toLegacy); + leg.pktStatistics = toLegacy(cur.statistics); + leg.pktStatus = toLegacy(cur.status); + return leg; +} + +cbPKT_NTRODEINFO Adapter::toLegacy(const ::cbPKT_NTRODEINFO& cur) const { + cbPKT_NTRODEINFO leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.ntrode = cur.ntrode; + copyArr(leg.label, cur.label); + copyArr2D(leg.ellipses, cur.ellipses, this, &Adapter::toLegacy); + leg.nSite = cur.nSite; + leg.fs = cur.fs; + copyArr(leg.nChan, cur.nChan); + return leg; +} + +cbWaveformData Adapter::toLegacy(const ::cbWaveformData& cur) const { + cbWaveformData leg{}; + leg.offset = cur.offset; // aka sineFrequency + leg.seq = cur.seq; // aka sineAmplitude + leg.seqTotal = cur.seqTotal; + leg.phases = cur.phases; + copyArr(leg.duration, cur.duration); + copyArr(leg.amplitude, cur.amplitude); + return leg; +} + +cbPKT_AOUT_WAVEFORM Adapter::toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const { + cbPKT_AOUT_WAVEFORM leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.repeats = cur.repeats; + leg.trig = cur.trig; + leg.trigInst = cur.trigInst; + leg.trigChan = cur.trigChan; + leg.trigValue = cur.trigValue; + leg.trigNum = cur.trigNum; + leg.active = cur.active; + leg.wave = toLegacy(cur.wave); + return leg; +} + +cbPKT_LNC Adapter::toLegacy(const ::cbPKT_LNC& cur) const { + cbPKT_LNC leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.lncFreq = cur.lncFreq; + leg.lncRefChan = cur.lncRefChan; + leg.lncGlobalMode = cur.lncGlobalMode; + return leg; +} + +cbPKT_NPLAY Adapter::toLegacy(const ::cbPKT_NPLAY& cur) const { + cbPKT_NPLAY leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.ftime = cur.ftime; // aka opt + leg.stime = cur.stime; + leg.etime = cur.etime; + leg.val = cur.val; + leg.mode = cur.mode; + leg.flags = cur.flags; + leg.speed = cur.speed; + copyArr(leg.fname, cur.fname); + return leg; +} + +cbVIDEOSOURCE Adapter::toLegacy(const ::cbVIDEOSOURCE& cur) const { + cbVIDEOSOURCE leg{}; + copyArr(leg.name, cur.name); + leg.fps = cur.fps; + return leg; +} + +cbTRACKOBJ Adapter::toLegacy(const ::cbTRACKOBJ& cur) const { + cbTRACKOBJ leg{}; + copyArr(leg.name, cur.name); + leg.type = cur.type; + leg.pointCount = cur.pointCount; + return leg; +} + +cbPKT_FILECFG Adapter::toLegacy(const ::cbPKT_FILECFG& cur) const { + cbPKT_FILECFG leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.options = cur.options; + leg.duration = cur.duration; + leg.recording = cur.recording; + leg.extctrl = cur.extctrl; + copyArr(leg.username, cur.username); + copyArr(leg.filename, cur.filename); // aka datetime + copyArr(leg.comment, cur.comment); + return leg; +} + +NSPStatus Adapter::toLegacy(const NativeNSPStatus& cur) const { + switch(cur) { + case NativeNSPStatus::NSP_INIT: + return NSPStatus::NSP_INIT; + case NativeNSPStatus::NSP_NOIPADDR: + return NSPStatus::NSP_NOIPADDR; + case NativeNSPStatus::NSP_NOREPLY: + return NSPStatus::NSP_NOREPLY; + case NativeNSPStatus::NSP_FOUND: + return NSPStatus::NSP_FOUND; + case NativeNSPStatus::NSP_INVALID: + default: + return NSPStatus::NSP_INVALID; + } +} + +cbPKT_UNIT_SELECTION Adapter::toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const { + cbPKT_UNIT_SELECTION leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + leg.lastchan = cur.lastchan; + copyArr(leg.abyUnitSelections, cur.abyUnitSelections); + return leg; +} + +cbPcStatus Adapter::toLegacy(const NativePCStatus& cur) const { + cbPcStatus leg{}; + leg.isSelection[instrument_idx] = toLegacy(cur.isSelection); + leg.m_iBlockRecording = cur.m_iBlockRecording; + leg.m_nPCStatusFlags = cur.m_nPCStatusFlags; + leg.m_nNumFEChans = cur.m_nNumFEChans; + leg.m_nNumAnainChans = cur.m_nNumAnainChans; + leg.m_nNumAnalogChans = cur.m_nNumAnalogChans; + leg.m_nNumAoutChans = cur.m_nNumAoutChans; + leg.m_nNumAudioChans = cur.m_nNumAudioChans; + leg.m_nNumAnalogoutChans = cur.m_nNumAnalogoutChans; + leg.m_nNumDiginChans = cur.m_nNumDiginChans; + leg.m_nNumSerialChans = cur.m_nNumSerialChans; + leg.m_nNumDigoutChans = cur.m_nNumDigoutChans; + leg.m_nNumTotalChans = cur.m_nNumTotalChans; + leg.m_nNspStatus[instrument_idx] = toLegacy(cur.m_nNspStatus); + leg.m_nNumNTrodesPerInstrument[instrument_idx] = cur.m_nNumNTrodesPerInstrument; + leg.m_nGeminiSystem = cur.m_nGeminiSystem; + // ignore APP_WORKSPACE + return leg; +} + +cbRECBUFF Adapter::toLegacy(const NativeReceiveBuffer& cur) const { + cbRECBUFF leg{}; + leg.received = cur.received; + leg.lasttime = cur.lasttime; + leg.headwrap = cur.headwrap; + leg.headindex = cur.headindex; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +cbXMTBUFF Adapter::toLegacy(const NativeTransmitBuffer& cur) const { + cbXMTBUFF leg{}; + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +cbXMTBUFFLOCAL Adapter::toLegacy(const NativeTransmitBufferLocal& cur) const { + cbXMTBUFFLOCAL leg{}; + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); + return leg; +} + +Adapter::Adapter(uint8_t instrument_idx, void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) + : instrument_idx(instrument_idx) + , cfg(static_cast(cfg_ptr)) , rec(static_cast(rec_ptr)) , xmt(static_cast(xmt_ptr)) , xmt_local(static_cast(xmt_local_ptr)) @@ -52,6 +1039,10 @@ Adapter::Adapter(void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_pt , spike(static_cast(spike_ptr)) {} +uint32_t Adapter::getMaxProcs() const { + return cbMAXPROCS; +} + uint32_t& Adapter::getRecReceived() { return rec->received; } @@ -100,6 +1091,7 @@ uint32_t* Adapter::getXmtBufferPtr() { return xmt->buffer; } + uint32_t& Adapter::getLocalXmtTransmittedPtr() { return xmt->transmitted; } @@ -124,14 +1116,14 @@ uint32_t* Adapter::getLocalXmtBufferPtr() { return xmt->buffer; } -Result<::cbPKT_PROCINFO> Adapter::getProcInfo(uint8_t instrument_idx) const { +Result<::cbPKT_PROCINFO> Adapter::getProcInfo() const { if (instrument_idx >= std::size(cfg->procinfo)) { return Result<::cbPKT_PROCINFO>::error("Instrument index out of range"); } - return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx], { .instrument_idx = instrument_idx })); + return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx])); } -Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t bank_num) const { +Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint32_t bank_num) const { if (instrument_idx >= std::size(cfg->bankinfo)) { return Result<::cbPKT_BANKINFO>::error("Instrument index out of range"); } @@ -139,10 +1131,10 @@ Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint8_t instrument_idx, uint32_t b if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result<::cbPKT_BANKINFO>::error("Bank number out of range"); } - return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx], {})); + return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx])); } -Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t filter_num) const { +Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint32_t filter_num) const { if (instrument_idx >= std::size(cfg->filtinfo)) { return Result<::cbPKT_FILTINFO>::error("Instrument index out of range"); } @@ -150,53 +1142,53 @@ Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint8_t instrument_idx, uint32_t if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result<::cbPKT_FILTINFO>::error("Filter number out of range"); } - return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx], {})); + return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx])); } Result<::cbPKT_CHANINFO> Adapter::getChanInfo(uint32_t channel_idx) const { if (channel_idx >= std::size(cfg->chaninfo)) { return Result<::cbPKT_CHANINFO>::error("Channel number out of range"); } - return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx], {})); + return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx])); } Result<::cbPKT_SYSINFO> Adapter::getSysInfo() const { - return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo, {})); + return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo)); } -Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint8_t instrument_idx, uint32_t group_idx) const { +Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint32_t group_idx) const { if (instrument_idx >= std::size(cfg->groupinfo)) { return Result<::cbPKT_GROUPINFO>::error("Instrument index out of range"); } if (group_idx >= std::size(cfg->groupinfo[0])) { return Result<::cbPKT_GROUPINFO>::error("Group index out of range"); } - return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx], {})); + return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx])); } -Result Adapter::getConfigBuffer(uint8_t instrument_idx) const { +Result Adapter::getConfigBuffer() const { if (instrument_idx >= std::size(cfg->procinfo)) { return Result::error("Instrument index out of range"); } - return Result::ok(fromLegacy(*cfg, { .instrument_idx = instrument_idx })); + return Result::ok(fromLegacy(*cfg)); } -Result Adapter::getPcStatus(uint8_t instrument_idx) const { +Result Adapter::getPcStatus() const { if (instrument_idx >= std::size(status->isSelection)) { return Result::error("Instrument index out of range"); } - return Result::ok(fromLegacy(*status, { .instrument_idx = instrument_idx })); + return Result::ok(fromLegacy(*status)); } -Result Adapter::setProcInfo(uint8_t instrument_idx, const ::cbPKT_PROCINFO& info) { +Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { if (instrument_idx >= std::size(cfg->procinfo)) { return Result::error("Instrument index out of range"); } - cfg->procinfo[instrument_idx] = toLegacy(info, {}); + cfg->procinfo[instrument_idx] = toLegacy(info); return Result::ok(); } -Result Adapter::setBankInfo(uint8_t instrument_idx, uint32_t bank_num, const ::cbPKT_BANKINFO& info) { +Result Adapter::setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) { if (instrument_idx >= std::size(cfg->bankinfo)) { return Result::error("Instrument index out of range"); } @@ -204,11 +1196,11 @@ Result Adapter::setBankInfo(uint8_t instrument_idx, uint32_t bank_num, con if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result::error("Bank number out of range"); } - cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info, {}); + cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info); return Result::ok(); } -Result Adapter::setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, const ::cbPKT_FILTINFO& info) { +Result Adapter::setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) { if (instrument_idx >= std::size(cfg->filtinfo)) { return Result::error("Instrument index out of range"); } @@ -216,7 +1208,7 @@ Result Adapter::setFilterInfo(uint8_t instrument_idx, uint32_t filter_num, if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result::error("Filter number out of range"); } - cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info, {}); + cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info); return Result::ok(); } @@ -224,31 +1216,31 @@ Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& if (channel_idx >= std::size(cfg->chaninfo)) { return Result::error("Channel number out of range"); } - cfg->chaninfo[channel_idx] = toLegacy(info, {}); + cfg->chaninfo[channel_idx] = toLegacy(info); return Result::ok(); } Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { - cfg->sysinfo = toLegacy(info, {}); + cfg->sysinfo = toLegacy(info); return Result::ok(); } -Result Adapter::setGroupInfo(uint8_t instrument_idx, uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { +Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { if (instrument_idx >= std::size(cfg->groupinfo)) { return Result::error("Instrument index out of range"); } if (group_idx >= std::size(cfg->groupinfo[0])) { return Result::error("Group index out of range"); } - cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info, {}); + cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info); return Result::ok(); } -Result Adapter::setPcStatus(uint8_t instrument_idx, const NativePCStatus& status) const { +Result Adapter::setPcStatus(const NativePCStatus& status) const { if (instrument_idx >= std::size(this->status->isSelection)) { return Result::error("Instrument index out of range"); } - *(this->status) = toLegacy(status, { .instrument_idx = instrument_idx }); + *(this->status) = toLegacy(status); return Result::ok(); } diff --git a/src/cbshm/src/central_translators/utils.h b/src/cbshm/src/central_translators/utils.h deleted file mode 100644 index 4062964a..00000000 --- a/src/cbshm/src/central_translators/utils.h +++ /dev/null @@ -1,83 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file utils.h -/// @author Caden Shmookler -/// @date 2025-05-22 -/// -/// @brief Common utilities for the Central-compatible object translators -/// -/// lhs -> left-hand side (copy to) -/// rhs -> right-hand side (copy from) -/// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#ifndef CBSHM_CENTRAL_TRANSLATORS_UTILS_H -#define CBSHM_CENTRAL_TRANSLATORS_UTILS_H - -#include -#include - -namespace cbshm { - -template -void copyArr(T(&lhs)[lhs_n], const T(&rhs)[rhs_n]) { - if (lhs_n <= rhs_n) { - std::memcpy(lhs, rhs, lhs_n * sizeof(T)); - } else { - std::memcpy(lhs, rhs, rhs_n * sizeof(T)); - std::memset(lhs + rhs_n, 0, (lhs_n - rhs_n) * sizeof(T)); - } -} - -template -void copyArr(LHS_T(&lhs)[lhs_n], const RHS_T(&rhs)[rhs_n], LHS_T(*translation_func)(const RHS_T&, const TranslationContext&), const TranslationContext& ctx) { - if (lhs_n <= rhs_n) { - for (size_t i = 0; i < lhs_n; ++i) { - lhs[i] = translation_func(rhs[i], ctx); - } - } else { - for (size_t i = 0; i < rhs_n; ++i) { - lhs[i] = translation_func(rhs[i], ctx); - } - std::memset(lhs + rhs_n, 0, (lhs_n - rhs_n) * sizeof(LHS_T)); - } -} - -template -void copyArr2D(T(&lhs)[lhs_ny][lhs_nx], const T(&rhs)[rhs_ny][rhs_nx]) { - if (lhs_ny <= rhs_ny) { - if (lhs_nx == rhs_nx) { - std::memcpy(lhs, rhs, (lhs_ny * lhs_nx) * sizeof(T)); - } else { - for (size_t i = 0; i < lhs_ny; ++i) { - copyArr(lhs[i], rhs[i]); - } - } - } else { - if (lhs_nx == rhs_nx) { - std::memcpy(lhs, rhs, (rhs_ny * rhs_nx) * sizeof(T)); - } else { - for (size_t i = 0; i < rhs_ny; ++i) { - copyArr(lhs[i], rhs[i]); - } - } - std::memset(lhs + rhs_ny, 0, ((lhs_ny - rhs_ny) * lhs_nx) * sizeof(T)); - } -} - -template -void copyArr2D(LHS_T(&lhs)[lhs_ny][lhs_nx], const RHS_T(&rhs)[rhs_ny][rhs_nx], LHS_T(*translation_func)(const RHS_T&, const TranslationContext&), const TranslationContext& ctx) { - if (lhs_ny <= rhs_ny) { - for (size_t i = 0; i < lhs_ny; ++i) { - copyArr(lhs[i], rhs[i], translation_func, ctx); - } - } else { - for (size_t i = 0; i < rhs_ny; ++i) { - copyArr(lhs[i], rhs[i], translation_func, ctx); - } - std::memset(lhs + rhs_ny, 0, ((lhs_ny - rhs_ny) * lhs_nx) * sizeof(LHS_T)); - } -} - -} // namespace cbshm - -#endif // CBSHM_CENTRAL_TRANSLATORS_UTILS_H diff --git a/src/cbshm/src/central_translators/v3_11.cpp b/src/cbshm/src/central_translators/v3_11.cpp deleted file mode 100644 index a6025b2f..00000000 --- a/src/cbshm/src/central_translators/v3_11.cpp +++ /dev/null @@ -1,998 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file v3_11.cpp -/// @author Caden Shmookler -/// @date 2026-05-22 -/// -/// @brief Central translator implementations -/// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#include "utils.h" -#include -#include - -namespace cbshm { - -namespace central_v3_11 { - -::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg, const TranslationContext& ctx) { - ::cbPKT_HEADER cur{}; - cur.time = leg.time; // TODO: explicit or implicit conversion here (?) (and for all PROCTIME) - cur.chid = leg.chid; - cur.type = static_cast(leg.type); - cur.dlen = static_cast(leg.dlen); - cur.instrument = 0; - cur.reserved = 0; - return cur; -} - -::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg, const TranslationContext& ctx) { - ::cbPKT_SYSINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.sysfreq = leg.sysfreq; - cur.spikelen = leg.spikelen; - cur.spikepre = leg.spikepre; - cur.resetque = leg.resetque; - cur.runlevel = leg.runlevel; - cur.runflags = leg.runflags; - return cur; -} - -::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg, const TranslationContext& ctx) { - ::cbPKT_PROCINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.proc = leg.proc; - cur.idcode = leg.idcode; - cur.idcode = leg.idcode; - copyArr(cur.ident, leg.ident); - cur.chanbase = leg.chanbase; - cur.chancount = leg.chancount; - cur.bankcount = leg.bankcount; - cur.groupcount = leg.groupcount; - cur.filtcount = leg.filtcount; - cur.sortcount = leg.sortcount; - cur.unitcount = leg.unitcount; - cur.hoopcount = leg.hoopcount; - cur.reserved = leg.sortmethod; - cur.version = leg.version; - return cur; -} - -::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg, const TranslationContext& ctx) { - ::cbPKT_BANKINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.proc = leg.proc; - cur.bank = leg.bank; - cur.idcode = leg.idcode; - copyArr(cur.ident, leg.ident); - copyArr(cur.label, leg.label); - cur.chanbase = leg.chanbase; - cur.chancount = leg.chancount; - return cur; -} - -::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg, const TranslationContext& ctx) { - ::cbPKT_GROUPINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.proc = leg.proc; - cur.group = leg.group; - copyArr(cur.label, leg.label); - cur.period = leg.period; - cur.length = leg.length; - copyArr(cur.list, leg.list); - return cur; -} - -::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg, const TranslationContext& ctx) { - ::cbPKT_FILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.proc = leg.proc; - cur.filt = leg.filt; - copyArr(cur.label, leg.label); - cur.hpfreq = leg.hpfreq; - cur.hporder = leg.hporder; - cur.hptype = leg.hptype; - cur.lpfreq = leg.lpfreq; - cur.lporder = leg.lporder; - cur.lptype = leg.lptype; - cur.gain = leg.gain; - cur.sos1a1 = leg.sos1a1; - cur.sos1a2 = leg.sos1a2; - cur.sos1b1 = leg.sos1b1; - cur.sos1b2 = leg.sos1b2; - cur.sos2a1 = leg.sos2a1; - cur.sos2a2 = leg.sos2a2; - cur.sos2b1 = leg.sos2b1; - cur.sos2b2 = leg.sos2b2; - return cur; -} - -::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg, const TranslationContext& ctx) { - ::cbPKT_ADAPTFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.nMode = leg.nMode; - cur.dLearningRate = leg.dLearningRate; - cur.nRefChan1 = leg.nRefChan1; - cur.nRefChan2 = leg.nRefChan2; - return cur; -} - -::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg, const TranslationContext& ctx) { - ::cbPKT_REFELECFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.nMode = leg.nMode; - cur.nRefChan = leg.nRefChan; - return cur; -} - -::cbSCALING fromLegacy(const cbSCALING& leg, const TranslationContext& ctx) { - ::cbSCALING cur{}; - cur.digmin = leg.digmin; - cur.digmax = leg.digmax; - cur.anamin = leg.anamin; - cur.anamax = leg.anamax; - cur.anagain = leg.anagain; - copyArr(cur.anaunit, leg.anaunit); - return cur; -} - -::cbFILTDESC fromLegacy(const cbFILTDESC& leg, const TranslationContext& ctx) { - ::cbFILTDESC cur{}; - cur.hpfreq = leg.hpfreq; - cur.hporder = leg.hporder; - cur.hptype = leg.hptype; - cur.lpfreq = leg.lpfreq; - cur.lporder = leg.lporder; - cur.lptype = leg.lptype; - return cur; -} - -::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg, const TranslationContext& ctx) { - ::cbMANUALUNITMAPPING cur{}; - cur.nOverride = leg.nOverride; - copyArr(cur.afOrigin, leg.afOrigin); - copyArr2D(cur.afShape, leg.afShape); - cur.aPhi = leg.aPhi; - cur.bValid = leg.bValid; - return cur; -} - -::cbHOOP fromLegacy(const cbHOOP& leg, const TranslationContext& ctx) { - ::cbHOOP cur{}; - cur.valid = leg.valid; - cur.time = leg.time; - cur.min = leg.min; - cur.max = leg.max; - return cur; -} - -::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg, const TranslationContext& ctx) { - ::cbPKT_CHANINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.proc = leg.proc; - cur.bank = leg.bank; - cur.term = leg.term; - cur.chancaps = leg.chancaps; - cur.doutcaps = leg.doutcaps; - cur.dinpcaps = leg.dinpcaps; - cur.aoutcaps = leg.aoutcaps; - cur.ainpcaps = leg.ainpcaps; - cur.spkcaps = leg.spkcaps; - cur.physcalin = fromLegacy(leg.physcalin, ctx); - cur.phyfiltin = fromLegacy(leg.phyfiltin, ctx); - cur.physcalout = fromLegacy(leg.physcalout, ctx); - cur.phyfiltout = fromLegacy(leg.phyfiltout, ctx); - copyArr(cur.label, leg.label); - cur.userflags = leg.userflags; - copyArr(cur.position, leg.position); - cur.scalin = fromLegacy(leg.scalin, ctx); - cur.scalout = fromLegacy(leg.scalout, ctx); - cur.doutopts = leg.doutopts; - cur.dinpopts = leg.dinpopts; - cur.aoutopts = leg.aoutopts; - cur.eopchar = leg.eopchar; - cur.moninst = static_cast((leg.monsource >> 16) & 0xFFFF); // aka lowsamples - cur.monchan = static_cast(leg.monsource & 0xFFFF); // aka highsamples - cur.outvalue = leg.outvalue; // aka offset - cur.trigtype = leg.trigtype; - // skip reserved - cur.triginst = 0; // TODO: VERIFY - cur.trigchan = leg.trigchan; - cur.trigval = leg.trigval; - cur.ainpopts = leg.ainpopts; - cur.lncrate = leg.lncrate; - cur.smpfilter = leg.smpfilter; - cur.smpgroup = leg.smpgroup; - cur.smpdispmin = leg.smpdispmin; - cur.smpdispmax = leg.smpdispmax; - cur.spkfilter = leg.spkfilter; - cur.spkdispmax = leg.spkdispmax; - cur.lncdispmax = leg.lncdispmax; - cur.spkopts = leg.spkopts; - cur.spkthrlevel = leg.spkthrlevel; - cur.spkthrlimit = leg.spkthrlimit; - cur.spkgroup = leg.spkgroup; - cur.amplrejpos = leg.amplrejpos; - cur.amplrejneg = leg.amplrejneg; - cur.refelecchan = leg.refelecchan; - copyArr(cur.unitmapping, leg.unitmapping, fromLegacy, ctx); - copyArr2D(cur.spkhoops, leg.spkhoops, fromLegacy, ctx); - return cur; -} - -::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg, const TranslationContext& ctx) { - ::cbPKT_FS_BASIS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.mode = leg.mode; - cur.fs = leg.fs; - copyArr2D(cur.basis, leg.basis); - return cur; -} - -::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg, const TranslationContext& ctx) { - ::cbPKT_SS_MODELSET cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.unit_number = leg.unit_number; - cur.valid = leg.valid; - cur.inverted = leg.inverted; - cur.num_samples = leg.num_samples; - copyArr(cur.mu_x, leg.mu_x); - copyArr2D(cur.Sigma_x, leg.Sigma_x); - cur.determinant_Sigma_x = leg.determinant_Sigma_x; - copyArr2D(cur.Sigma_x_inv, leg.Sigma_x_inv); - cur.log_determinant_Sigma_x = leg.log_determinant_Sigma_x; - cur.subcluster_spread_factor_numerator = leg.subcluster_spread_factor_numerator; - cur.subcluster_spread_factor_denominator = leg.subcluster_spread_factor_denominator; - cur.mu_e = leg.mu_e; - cur.sigma_e_squared = leg.sigma_e_squared; - return cur; -} - -::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg, const TranslationContext& ctx) { - ::cbPKT_SS_DETECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.fThreshold = leg.fThreshold; - cur.fMultiplier = leg.fMultiplier; - return cur; -} - -::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg, const TranslationContext& ctx) { - ::cbPKT_SS_ARTIF_REJECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.nMaxSimulChans = leg.nMaxSimulChans; - cur.nRefractoryCount = leg.nRefractoryCount; - return cur; -} - -::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg, const TranslationContext& ctx) { - ::cbPKT_SS_NOISE_BOUNDARY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - copyArr(cur.afc, leg.afc); - copyArr2D(cur.afS, leg.afS); - return cur; -} - -::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg, const TranslationContext& ctx) { - ::cbPKT_SS_STATISTICS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.nUpdateSpikes = leg.nUpdateSpikes; - cur.nAutoalg = leg.nAutoalg; - cur.nMode = leg.nMode; - cur.fMinClusterPairSpreadFactor = leg.fMinClusterPairSpreadFactor; - cur.fMaxSubclusterSpreadFactor = leg.fMaxSubclusterSpreadFactor; - cur.fMinClusterHistCorrMajMeasure = leg.fMinClusterHistCorrMajMeasure; - cur.fMaxClusterPairHistCorrMajMeasure = leg.fMaxClusterPairHistCorrMajMeasure; - cur.fClusterHistValleyPercentage = leg.fClusterHistValleyPercentage; - cur.fClusterHistClosePeakPercentage = leg.fClusterHistClosePeakPercentage; - cur.fClusterHistMinPeakPercentage = leg.fClusterHistMinPeakPercentage; - cur.nWaveBasisSize = leg.nWaveBasisSize; - cur.nWaveSampleSize = leg.nWaveSampleSize; - return cur; -} - -::cbAdaptControl fromLegacy(const cbAdaptControl& leg, const TranslationContext& ctx) { - ::cbAdaptControl cur{}; - cur.nMode = leg.nMode; - cur.fTimeOutMinutes = leg.fTimeOutMinutes; - cur.fElapsedMinutes = leg.fElapsedMinutes; - return cur; -} - -::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg, const TranslationContext& ctx) { - ::cbPKT_SS_STATUS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats, ctx); - cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits, ctx); - return cur; -} - -::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg, const TranslationContext& ctx) { - ::cbproto::SpikeSorting cur{}; - copyArr(cur.basis, leg.asBasis, fromLegacy, ctx); - copyArr2D(cur.models, leg.asSortModel, fromLegacy, ctx); - cur.detect = fromLegacy(leg.pktDetect, ctx); - cur.artifact_reject = fromLegacy(leg.pktArtifReject, ctx); - copyArr(cur.noise_boundary, leg.pktNoiseBoundary, fromLegacy, ctx); - cur.statistics = fromLegacy(leg.pktStatistics, ctx); - cur.status = fromLegacy(leg.pktStatus, ctx); - return cur; -} - -::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg, const TranslationContext& ctx) { - ::cbPKT_NTRODEINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.ntrode = leg.ntrode; - copyArr(cur.label, leg.label); - copyArr2D(cur.ellipses, leg.ellipses, fromLegacy, ctx); - cur.nSite = leg.nSite; - cur.fs = leg.fs; - copyArr(cur.nChan, leg.nChan); - return cur; -} - -::cbWaveformData fromLegacy(const cbWaveformData& leg, const TranslationContext& ctx) { - ::cbWaveformData cur{}; - cur.offset = leg.offset; // aka sineFrequency - cur.seq = leg.seq; // aka sineAmplitude - cur.seqTotal = leg.seqTotal; - cur.phases = leg.phases; - copyArr(cur.duration, leg.duration); - copyArr(cur.amplitude, leg.amplitude); - return cur; -} - -::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg, const TranslationContext& ctx) { - ::cbPKT_AOUT_WAVEFORM cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.mode = leg.mode; - cur.repeats = leg.repeats; - cur.trig = static_cast((leg.trig >> 8) & 0xFF); - cur.trigInst = static_cast(leg.trig & 0xFF); - cur.trigChan = leg.trigChan; - cur.trigValue = leg.trigValue; - cur.trigNum = leg.trigNum; - cur.active = leg.active; - cur.wave = fromLegacy(leg.wave, ctx); - return cur; -} - -::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg, const TranslationContext& ctx) { - ::cbPKT_LNC cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.lncFreq = leg.lncFreq; - cur.lncRefChan = leg.lncRefChan; - cur.lncGlobalMode = leg.lncGlobalMode; - return cur; -} - -::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg, const TranslationContext& ctx) { - ::cbPKT_NPLAY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.ftime = leg.ftime; // aka opt - cur.stime = leg.stime; - cur.etime = leg.etime; - cur.val = leg.val; - cur.mode = leg.mode; - cur.flags = leg.flags; - cur.speed = leg.speed; - copyArr(cur.fname, leg.fname); - return cur; -} - -::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg, const TranslationContext& ctx) { - ::cbVIDEOSOURCE cur{}; - copyArr(cur.name, leg.name); - cur.fps = leg.fps; - return cur; -} - -::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg, const TranslationContext& ctx) { - ::cbTRACKOBJ cur{}; - copyArr(cur.name, leg.name); - cur.type = leg.type; - cur.pointCount = leg.pointCount; - return cur; -} - -::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg, const TranslationContext& ctx) { - ::cbPKT_FILECFG cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.options = leg.options; - cur.duration = leg.duration; - cur.recording = leg.recording; - cur.extctrl = leg.extctrl; - copyArr(cur.username, leg.username); - copyArr(cur.filename, leg.filename); // aka datetime - copyArr(cur.comment, leg.comment); - return cur; -} - -NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg, const TranslationContext& ctx) { - // TODO: VERIFY that each list that's assumed to be instrument-independent is in fact independent from any particular instrument. - NativeConfigBuffer cur{}; - cur.version = leg.version; - cur.sysflags = leg.sysflags; - cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); - cur.sysinfo = fromLegacy(leg.sysinfo, ctx); - cur.procinfo = fromLegacy(leg.procinfo[ctx.instrument_idx], ctx); - copyArr(cur.bankinfo, leg.bankinfo[ctx.instrument_idx], fromLegacy, ctx); - copyArr(cur.groupinfo, leg.groupinfo[ctx.instrument_idx], fromLegacy, ctx); - copyArr(cur.filtinfo, leg.filtinfo[ctx.instrument_idx], fromLegacy, ctx); - cur.adaptinfo = fromLegacy(leg.adaptinfo[ctx.instrument_idx], ctx); - cur.refelecinfo = fromLegacy(leg.refelecinfo[ctx.instrument_idx], ctx); - copyArr(cur.chaninfo, leg.chaninfo, fromLegacy, ctx); - copyArr(cur.asBasis, leg.isSortingOptions.asBasis, fromLegacy, ctx); - copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, fromLegacy, ctx); - // TODO: Move native isSortingOptions fields into a struct - cur.pktDetect = fromLegacy(leg.isSortingOptions.pktDetect, ctx); - cur.pktArtifReject = fromLegacy(leg.isSortingOptions.pktArtifReject, ctx); - copyArr(cur.pktNoiseBoundary, leg.isSortingOptions.pktNoiseBoundary, fromLegacy, ctx); - cur.pktStatistics = fromLegacy(leg.isSortingOptions.pktStatistics, ctx); - cur.pktStatus = fromLegacy(leg.isSortingOptions.pktStatus, ctx); - copyArr(cur.isNTrodeInfo, leg.isNTrodeInfo, fromLegacy, ctx); - copyArr2D(cur.isWaveform, leg.isWaveform, fromLegacy, ctx); - cur.isLnc = fromLegacy(leg.isLnc[ctx.instrument_idx], ctx); - cur.isNPlay = fromLegacy(leg.isNPlay, ctx); - copyArr(cur.isVideoSource, leg.isVideoSource, fromLegacy, ctx); - copyArr(cur.isTrackObj, leg.isTrackObj, fromLegacy, ctx); - cur.fileinfo = fromLegacy(leg.fileinfo, ctx); - - return cur; -} - -NativeNSPStatus fromLegacy(const NSPStatus& leg, const TranslationContext& ctx) { - switch(leg) { - case NSPStatus::NSP_INIT: - return NativeNSPStatus::NSP_INIT; - case NSPStatus::NSP_NOIPADDR: - return NativeNSPStatus::NSP_NOIPADDR; - case NSPStatus::NSP_NOREPLY: - return NativeNSPStatus::NSP_NOREPLY; - case NSPStatus::NSP_FOUND: - return NativeNSPStatus::NSP_FOUND; - case NSPStatus::NSP_INVALID: - default: - return NativeNSPStatus::NSP_INVALID; - } -} - -::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg, const TranslationContext& ctx) { - ::cbPKT_UNIT_SELECTION cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.lastchan = leg.lastchan; - copyArr(cur.abyUnitSelections, leg.abyUnitSelections); - return cur; -} - -NativePCStatus fromLegacy(const cbPcStatus& leg, const TranslationContext& ctx) { - NativePCStatus cur{}; - cur.isSelection = fromLegacy(leg.isSelection[ctx.instrument_idx], ctx); - cur.m_iBlockRecording = leg.m_iBlockRecording; - cur.m_nPCStatusFlags = leg.m_nPCStatusFlags; - cur.m_nNumFEChans = leg.m_nNumFEChans; - cur.m_nNumAnainChans = leg.m_nNumAnainChans; - cur.m_nNumAnalogChans = leg.m_nNumAnalogChans; - cur.m_nNumAoutChans = leg.m_nNumAoutChans; - cur.m_nNumAudioChans = leg.m_nNumAudioChans; - cur.m_nNumAnalogoutChans = leg.m_nNumAnalogoutChans; - cur.m_nNumDiginChans = leg.m_nNumDiginChans; - cur.m_nNumSerialChans = leg.m_nNumSerialChans; - cur.m_nNumDigoutChans = leg.m_nNumDigoutChans; - cur.m_nNumTotalChans = leg.m_nNumTotalChans; - cur.m_nNspStatus = NativeNSPStatus::NSP_FOUND; // TODO: VERIFY - cur.m_nNumNTrodesPerInstrument = cbMAXNTRODES; // TODO: VERIFY - cur.m_nGeminiSystem = 1; // TODO: VERIFY - // ignore APP_WORKSPACE - return cur; -} - -NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg, const TranslationContext& ctx) { - NativeReceiveBuffer cur{}; - cur.received = leg.received; - cur.lasttime = leg.lasttime; - cur.headwrap = leg.headwrap; - cur.headindex = leg.headindex; - copyArr(cur.buffer, leg.buffer); - return cur; -} - -NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg, const TranslationContext& ctx) { - NativeTransmitBuffer cur{}; - cur.transmitted = leg.transmitted; - cur.headindex = leg.headindex; - cur.tailindex = leg.tailindex; - cur.last_valid_index = leg.last_valid_index; - cur.bufferlen = leg.bufferlen; - copyArr(cur.buffer, leg.buffer); - return cur; -} - -NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg, const TranslationContext& ctx) { - NativeTransmitBufferLocal cur{}; - cur.transmitted = leg.transmitted; - cur.headindex = leg.headindex; - cur.tailindex = leg.tailindex; - cur.last_valid_index = leg.last_valid_index; - cur.bufferlen = leg.bufferlen; - copyArr(cur.buffer, leg.buffer); - return cur; -} - -cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur, const TranslationContext& ctx) { - cbPKT_HEADER leg{}; - leg.time = cur.time; - leg.chid = cur.chid; - leg.type = static_cast(cur.type); - leg.dlen = static_cast(cur.dlen); - return leg; -} - -cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur, const TranslationContext& ctx) { - cbPKT_SYSINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.sysfreq = cur.sysfreq; - leg.spikelen = cur.spikelen; - leg.spikepre = cur.spikepre; - leg.resetque = cur.resetque; - leg.runlevel = cur.runlevel; - leg.runflags = cur.runflags; - return leg; -} - -cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur, const TranslationContext& ctx) { - cbPKT_PROCINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.proc = cur.proc; - leg.idcode = cur.idcode; - leg.idcode = cur.idcode; - copyArr(leg.ident, cur.ident); - leg.chanbase = cur.chanbase; - leg.chancount = cur.chancount; - leg.bankcount = cur.bankcount; - leg.groupcount = cur.groupcount; - leg.filtcount = cur.filtcount; - leg.sortcount = cur.sortcount; - leg.unitcount = cur.unitcount; - leg.hoopcount = cur.hoopcount; - leg.sortmethod = cur.reserved; - leg.version = cur.version; - return leg; -} - -cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur, const TranslationContext& ctx) { - cbPKT_BANKINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.proc = cur.proc; - leg.bank = cur.bank; - leg.idcode = cur.idcode; - copyArr(leg.ident, cur.ident); - copyArr(leg.label, cur.label); - leg.chanbase = cur.chanbase; - leg.chancount = cur.chancount; - return leg; -} - -cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur, const TranslationContext& ctx) { - cbPKT_GROUPINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.proc = cur.proc; - leg.group = cur.group; - copyArr(leg.label, cur.label); - leg.period = cur.period; - leg.length = cur.length; - copyArr(leg.list, cur.list); - return leg; -} - -cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur, const TranslationContext& ctx) { - cbPKT_FILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.proc = cur.proc; - leg.filt = cur.filt; - copyArr(leg.label, cur.label); - leg.hpfreq = cur.hpfreq; - leg.hporder = cur.hporder; - leg.hptype = cur.hptype; - leg.lpfreq = cur.lpfreq; - leg.lporder = cur.lporder; - leg.lptype = cur.lptype; - leg.gain = cur.gain; - leg.sos1a1 = cur.sos1a1; - leg.sos1a2 = cur.sos1a2; - leg.sos1b1 = cur.sos1b1; - leg.sos1b2 = cur.sos1b2; - leg.sos2a1 = cur.sos2a1; - leg.sos2a2 = cur.sos2a2; - leg.sos2b1 = cur.sos2b1; - leg.sos2b2 = cur.sos2b2; - return leg; -} - -cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur, const TranslationContext& ctx) { - cbPKT_ADAPTFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.nMode = cur.nMode; - leg.dLearningRate = cur.dLearningRate; - leg.nRefChan1 = cur.nRefChan1; - leg.nRefChan2 = cur.nRefChan2; - return leg; -} - -cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur, const TranslationContext& ctx) { - cbPKT_REFELECFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.nMode = cur.nMode; - leg.nRefChan = cur.nRefChan; - return leg; -} - -cbSCALING toLegacy(const ::cbSCALING& cur, const TranslationContext& ctx) { - cbSCALING leg{}; - leg.digmin = cur.digmin; - leg.digmax = cur.digmax; - leg.anamin = cur.anamin; - leg.anamax = cur.anamax; - leg.anagain = cur.anagain; - copyArr(leg.anaunit, cur.anaunit); - return leg; -} - -cbFILTDESC toLegacy(const ::cbFILTDESC& cur, const TranslationContext& ctx) { - cbFILTDESC leg{}; - leg.hpfreq = cur.hpfreq; - leg.hporder = cur.hporder; - leg.hptype = cur.hptype; - leg.lpfreq = cur.lpfreq; - leg.lporder = cur.lporder; - leg.lptype = cur.lptype; - return leg; -} - -cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur, const TranslationContext& ctx) { - cbMANUALUNITMAPPING leg{}; - leg.nOverride = cur.nOverride; - copyArr(leg.afOrigin, cur.afOrigin); - copyArr2D(leg.afShape, cur.afShape); - leg.aPhi = cur.aPhi; - leg.bValid = cur.bValid; - return leg; -} - -cbHOOP toLegacy(const ::cbHOOP& cur, const TranslationContext& ctx) { - cbHOOP leg{}; - leg.valid = cur.valid; - leg.time = cur.time; - leg.min = cur.min; - leg.max = cur.max; - return leg; -} - -cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur, const TranslationContext& ctx) { - cbPKT_CHANINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.proc = cur.proc; - leg.bank = cur.bank; - leg.term = cur.term; - leg.chancaps = cur.chancaps; - leg.doutcaps = cur.doutcaps; - leg.dinpcaps = cur.dinpcaps; - leg.aoutcaps = cur.aoutcaps; - leg.ainpcaps = cur.ainpcaps; - leg.spkcaps = cur.spkcaps; - leg.physcalin = toLegacy(cur.physcalin, ctx); - leg.phyfiltin = toLegacy(cur.phyfiltin, ctx); - leg.physcalout = toLegacy(cur.physcalout, ctx); - leg.phyfiltout = toLegacy(cur.phyfiltout, ctx); - copyArr(leg.label, cur.label); - leg.userflags = cur.userflags; - copyArr(leg.position, cur.position); - leg.scalin = toLegacy(cur.scalin, ctx); - leg.scalout = toLegacy(cur.scalout, ctx); - leg.doutopts = cur.doutopts; - leg.dinpopts = cur.dinpopts; - leg.aoutopts = cur.aoutopts; - leg.eopchar = cur.eopchar; - leg.monsource = (static_cast(cur.moninst) << 16) | static_cast(cur.monchan); // aka highsamples and lowsamples - leg.outvalue = cur.outvalue; // aka offset - leg.trigtype = cur.trigtype; - leg.trigchan = cur.trigchan; - leg.trigval = cur.trigval; - leg.ainpopts = cur.ainpopts; - leg.lncrate = cur.lncrate; - leg.smpfilter = cur.smpfilter; - leg.smpgroup = cur.smpgroup; - leg.smpdispmin = cur.smpdispmin; - leg.smpdispmax = cur.smpdispmax; - leg.spkfilter = cur.spkfilter; - leg.spkdispmax = cur.spkdispmax; - leg.lncdispmax = cur.lncdispmax; - leg.spkopts = cur.spkopts; - leg.spkthrlevel = cur.spkthrlevel; - leg.spkthrlimit = cur.spkthrlimit; - leg.spkgroup = cur.spkgroup; - leg.amplrejpos = cur.amplrejpos; - leg.amplrejneg = cur.amplrejneg; - leg.refelecchan = cur.refelecchan; - copyArr(leg.unitmapping, cur.unitmapping, toLegacy, ctx); - copyArr2D(leg.spkhoops, cur.spkhoops, toLegacy, ctx); - return leg; -} - -cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur, const TranslationContext& ctx) { - cbPKT_FS_BASIS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.mode = cur.mode; - leg.fs = cur.fs; - copyArr2D(leg.basis, cur.basis); - return leg; -} - -cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur, const TranslationContext& ctx) { - cbPKT_SS_MODELSET leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.unit_number = cur.unit_number; - leg.valid = cur.valid; - leg.inverted = cur.inverted; - leg.num_samples = cur.num_samples; - copyArr(leg.mu_x, cur.mu_x); - copyArr2D(leg.Sigma_x, cur.Sigma_x); - leg.determinant_Sigma_x = cur.determinant_Sigma_x; - copyArr2D(leg.Sigma_x_inv, cur.Sigma_x_inv); - leg.log_determinant_Sigma_x = cur.log_determinant_Sigma_x; - leg.subcluster_spread_factor_numerator = cur.subcluster_spread_factor_numerator; - leg.subcluster_spread_factor_denominator = cur.subcluster_spread_factor_denominator; - leg.mu_e = cur.mu_e; - leg.sigma_e_squared = cur.sigma_e_squared; - return leg; -} - -cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur, const TranslationContext& ctx) { - cbPKT_SS_DETECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.fThreshold = cur.fThreshold; - leg.fMultiplier = cur.fMultiplier; - return leg; -} - -cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur, const TranslationContext& ctx) { - cbPKT_SS_ARTIF_REJECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.nMaxSimulChans = cur.nMaxSimulChans; - leg.nRefractoryCount = cur.nRefractoryCount; - return leg; -} - -cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur, const TranslationContext& ctx) { - cbPKT_SS_NOISE_BOUNDARY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - copyArr(leg.afc, cur.afc); - copyArr2D(leg.afS, cur.afS); - return leg; -} - -cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur, const TranslationContext& ctx) { - cbPKT_SS_STATISTICS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.nUpdateSpikes = cur.nUpdateSpikes; - leg.nAutoalg = cur.nAutoalg; - leg.nMode = cur.nMode; - leg.fMinClusterPairSpreadFactor = cur.fMinClusterPairSpreadFactor; - leg.fMaxSubclusterSpreadFactor = cur.fMaxSubclusterSpreadFactor; - leg.fMinClusterHistCorrMajMeasure = cur.fMinClusterHistCorrMajMeasure; - leg.fMaxClusterPairHistCorrMajMeasure = cur.fMaxClusterPairHistCorrMajMeasure; - leg.fClusterHistValleyPercentage = cur.fClusterHistValleyPercentage; - leg.fClusterHistClosePeakPercentage = cur.fClusterHistClosePeakPercentage; - leg.fClusterHistMinPeakPercentage = cur.fClusterHistMinPeakPercentage; - leg.nWaveBasisSize = cur.nWaveBasisSize; - leg.nWaveSampleSize = cur.nWaveSampleSize; - return leg; -} - -cbAdaptControl toLegacy(const ::cbAdaptControl& cur, const TranslationContext& ctx) { - cbAdaptControl leg{}; - leg.nMode = cur.nMode; - leg.fTimeOutMinutes = cur.fTimeOutMinutes; - leg.fElapsedMinutes = cur.fElapsedMinutes; - return leg; -} - -cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur, const TranslationContext& ctx) { - cbPKT_SS_STATUS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.cntlUnitStats = toLegacy(cur.cntlUnitStats, ctx); - leg.cntlNumUnits = toLegacy(cur.cntlNumUnits, ctx); - return leg; -} - -cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur, const TranslationContext& ctx) { - cbSPIKE_SORTING leg{}; - copyArr(leg.asBasis, cur.basis, toLegacy, ctx); - copyArr2D(leg.asSortModel, cur.models, toLegacy, ctx); - leg.pktDetect = toLegacy(cur.detect, ctx); - leg.pktArtifReject = toLegacy(cur.artifact_reject, ctx); - copyArr(leg.pktNoiseBoundary, cur.noise_boundary, toLegacy, ctx); - leg.pktStatistics = toLegacy(cur.statistics, ctx); - leg.pktStatus = toLegacy(cur.status, ctx); - return leg; -} - -cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur, const TranslationContext& ctx) { - cbPKT_NTRODEINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.ntrode = cur.ntrode; - copyArr(leg.label, cur.label); - copyArr2D(leg.ellipses, cur.ellipses, toLegacy, ctx); - leg.nSite = cur.nSite; - leg.fs = cur.fs; - copyArr(leg.nChan, cur.nChan); - return leg; -} - -cbWaveformData toLegacy(const ::cbWaveformData& cur, const TranslationContext& ctx) { - cbWaveformData leg{}; - leg.offset = cur.offset; // aka sineFrequency - leg.seq = cur.seq; // aka sineAmplitude - leg.seqTotal = cur.seqTotal; - leg.phases = cur.phases; - copyArr(leg.duration, cur.duration); - copyArr(leg.amplitude, cur.amplitude); - return leg; -} - -cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur, const TranslationContext& ctx) { - cbPKT_AOUT_WAVEFORM leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.mode = cur.mode; - leg.repeats = cur.repeats; - leg.trig = (static_cast(cur.trig) << 8) | static_cast(cur.trigInst); - leg.trigChan = cur.trigChan; - leg.trigValue = cur.trigValue; - leg.trigNum = cur.trigNum; - leg.active = cur.active; - leg.wave = toLegacy(cur.wave, ctx); - return leg; -} - -cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur, const TranslationContext& ctx) { - cbPKT_LNC leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.lncFreq = cur.lncFreq; - leg.lncRefChan = cur.lncRefChan; - leg.lncGlobalMode = cur.lncGlobalMode; - return leg; -} - -cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur, const TranslationContext& ctx) { - cbPKT_NPLAY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.ftime = cur.ftime; // aka opt - leg.stime = cur.stime; - leg.etime = cur.etime; - leg.val = cur.val; - leg.mode = cur.mode; - leg.flags = cur.flags; - leg.speed = cur.speed; - copyArr(leg.fname, cur.fname); - return leg; -} - -cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur, const TranslationContext& ctx) { - cbVIDEOSOURCE leg{}; - copyArr(leg.name, cur.name); - leg.fps = cur.fps; - return leg; -} - -cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur, const TranslationContext& ctx) { - cbTRACKOBJ leg{}; - copyArr(leg.name, cur.name); - leg.type = cur.type; - leg.pointCount = cur.pointCount; - return leg; -} - -cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur, const TranslationContext& ctx) { - cbPKT_FILECFG leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.options = cur.options; - leg.duration = cur.duration; - leg.recording = cur.recording; - leg.extctrl = cur.extctrl; - copyArr(leg.username, cur.username); - copyArr(leg.filename, cur.filename); // aka datetime - copyArr(leg.comment, cur.comment); - return leg; -} - -NSPStatus toLegacy(const NativeNSPStatus& cur, const TranslationContext& ctx) { - switch(cur) { - case NativeNSPStatus::NSP_INIT: - return NSPStatus::NSP_INIT; - case NativeNSPStatus::NSP_NOIPADDR: - return NSPStatus::NSP_NOIPADDR; - case NativeNSPStatus::NSP_NOREPLY: - return NSPStatus::NSP_NOREPLY; - case NativeNSPStatus::NSP_FOUND: - return NSPStatus::NSP_FOUND; - case NativeNSPStatus::NSP_INVALID: - default: - return NSPStatus::NSP_INVALID; - } -} - -cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur, const TranslationContext& ctx) { - cbPKT_UNIT_SELECTION leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.lastchan = cur.lastchan; - copyArr(leg.abyUnitSelections, cur.abyUnitSelections); - return leg; -} - -cbPcStatus toLegacy(const NativePCStatus& cur, const TranslationContext& ctx) { - cbPcStatus leg{}; - leg.isSelection[ctx.instrument_idx] = toLegacy(cur.isSelection, ctx); - leg.m_iBlockRecording = cur.m_iBlockRecording; - leg.m_nPCStatusFlags = cur.m_nPCStatusFlags; - leg.m_nNumFEChans = cur.m_nNumFEChans; - leg.m_nNumAnainChans = cur.m_nNumAnainChans; - leg.m_nNumAnalogChans = cur.m_nNumAnalogChans; - leg.m_nNumAoutChans = cur.m_nNumAoutChans; - leg.m_nNumAudioChans = cur.m_nNumAudioChans; - leg.m_nNumAnalogoutChans = cur.m_nNumAnalogoutChans; - leg.m_nNumDiginChans = cur.m_nNumDiginChans; - leg.m_nNumSerialChans = cur.m_nNumSerialChans; - leg.m_nNumDigoutChans = cur.m_nNumDigoutChans; - leg.m_nNumTotalChans = cur.m_nNumTotalChans; - // ignore APP_WORKSPACE - return leg; -} - -cbRECBUFF toLegacy(const NativeReceiveBuffer& cur, const TranslationContext& ctx) { - cbRECBUFF leg{}; - leg.received = cur.received; - leg.lasttime = cur.lasttime; - leg.headwrap = cur.headwrap; - leg.headindex = cur.headindex; - copyArr(leg.buffer, cur.buffer); - return leg; -} - -cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur, const TranslationContext& ctx) { - cbXMTBUFF leg{}; - leg.transmitted = cur.transmitted; - leg.headindex = cur.headindex; - leg.tailindex = cur.tailindex; - leg.last_valid_index = cur.last_valid_index; - leg.bufferlen = cur.bufferlen; - copyArr(leg.buffer, cur.buffer); - return leg; -} - -cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur, const TranslationContext& ctx) { - cbXMTBUFFLOCAL leg{}; - leg.transmitted = cur.transmitted; - leg.headindex = cur.headindex; - leg.tailindex = cur.tailindex; - leg.last_valid_index = cur.last_valid_index; - leg.bufferlen = cur.bufferlen; - copyArr(leg.buffer, cur.buffer); - return leg; -} - -} // namespace central_v3_11 - -} // namespace cbshm diff --git a/src/cbshm/src/central_translators/v4_0.cpp b/src/cbshm/src/central_translators/v4_0.cpp deleted file mode 100644 index 7867dc11..00000000 --- a/src/cbshm/src/central_translators/v4_0.cpp +++ /dev/null @@ -1,1003 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file v4_0.cpp -/// @author Caden Shmookler -/// @date 2026-05-22 -/// -/// @brief Central translator implementations -/// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#include "utils.h" -#include -#include - -namespace cbshm { - -namespace central_v4_0 { - -::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg, const TranslationContext& ctx) { - ::cbPKT_HEADER cur{}; - cur.time = leg.time; - cur.chid = leg.chid; - cur.type = static_cast(leg.type); - cur.dlen = leg.dlen; - cur.instrument = leg.instrument; - cur.reserved = leg.reserved; - return cur; -} - -::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg, const TranslationContext& ctx) { - ::cbPKT_SYSINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.sysfreq = leg.sysfreq; - cur.spikelen = leg.spikelen; - cur.spikepre = leg.spikepre; - cur.resetque = leg.resetque; - cur.runlevel = leg.runlevel; - cur.runflags = leg.runflags; - return cur; -} - -::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg, const TranslationContext& ctx) { - ::cbPKT_PROCINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.proc = leg.proc; - cur.idcode = leg.idcode; - cur.idcode = leg.idcode; - copyArr(cur.ident, leg.ident); - cur.chanbase = leg.chanbase; - cur.chancount = leg.chancount; - cur.bankcount = leg.bankcount; - cur.groupcount = leg.groupcount; - cur.filtcount = leg.filtcount; - cur.sortcount = leg.sortcount; - cur.unitcount = leg.unitcount; - cur.hoopcount = leg.hoopcount; - cur.reserved = leg.reserved; - cur.version = leg.version; - return cur; -} - -::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg, const TranslationContext& ctx) { - ::cbPKT_BANKINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.proc = leg.proc; - cur.bank = leg.bank; - cur.idcode = leg.idcode; - copyArr(cur.ident, leg.ident); - copyArr(cur.label, leg.label); - cur.chanbase = leg.chanbase; - cur.chancount = leg.chancount; - return cur; -} - -::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg, const TranslationContext& ctx) { - ::cbPKT_GROUPINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.proc = leg.proc; - cur.group = leg.group; - copyArr(cur.label, leg.label); - cur.period = leg.period; - cur.length = leg.length; - copyArr(cur.list, leg.list); - return cur; -} - -::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg, const TranslationContext& ctx) { - ::cbPKT_FILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.proc = leg.proc; - cur.filt = leg.filt; - copyArr(cur.label, leg.label); - cur.hpfreq = leg.hpfreq; - cur.hporder = leg.hporder; - cur.hptype = leg.hptype; - cur.lpfreq = leg.lpfreq; - cur.lporder = leg.lporder; - cur.lptype = leg.lptype; - cur.gain = leg.gain; - cur.sos1a1 = leg.sos1a1; - cur.sos1a2 = leg.sos1a2; - cur.sos1b1 = leg.sos1b1; - cur.sos1b2 = leg.sos1b2; - cur.sos2a1 = leg.sos2a1; - cur.sos2a2 = leg.sos2a2; - cur.sos2b1 = leg.sos2b1; - cur.sos2b2 = leg.sos2b2; - return cur; -} - -::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg, const TranslationContext& ctx) { - ::cbPKT_ADAPTFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.nMode = leg.nMode; - cur.dLearningRate = leg.dLearningRate; - cur.nRefChan1 = leg.nRefChan1; - cur.nRefChan2 = leg.nRefChan2; - return cur; -} - -::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg, const TranslationContext& ctx) { - ::cbPKT_REFELECFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.nMode = leg.nMode; - cur.nRefChan = leg.nRefChan; - return cur; -} - -::cbSCALING fromLegacy(const cbSCALING& leg, const TranslationContext& ctx) { - ::cbSCALING cur{}; - cur.digmin = leg.digmin; - cur.digmax = leg.digmax; - cur.anamin = leg.anamin; - cur.anamax = leg.anamax; - cur.anagain = leg.anagain; - copyArr(cur.anaunit, leg.anaunit); - return cur; -} - -::cbFILTDESC fromLegacy(const cbFILTDESC& leg, const TranslationContext& ctx) { - ::cbFILTDESC cur{}; - cur.hpfreq = leg.hpfreq; - cur.hporder = leg.hporder; - cur.hptype = leg.hptype; - cur.lpfreq = leg.lpfreq; - cur.lporder = leg.lporder; - cur.lptype = leg.lptype; - return cur; -} - -::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg, const TranslationContext& ctx) { - ::cbMANUALUNITMAPPING cur{}; - cur.nOverride = leg.nOverride; - copyArr(cur.afOrigin, leg.afOrigin); - copyArr2D(cur.afShape, leg.afShape); - cur.aPhi = leg.aPhi; - cur.bValid = leg.bValid; - return cur; -} - -::cbHOOP fromLegacy(const cbHOOP& leg, const TranslationContext& ctx) { - ::cbHOOP cur{}; - cur.valid = leg.valid; - cur.time = leg.time; - cur.min = leg.min; - cur.max = leg.max; - return cur; -} - -::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg, const TranslationContext& ctx) { - ::cbPKT_CHANINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.proc = leg.proc; - cur.bank = leg.bank; - cur.term = leg.term; - cur.chancaps = leg.chancaps; - cur.doutcaps = leg.doutcaps; - cur.dinpcaps = leg.dinpcaps; - cur.aoutcaps = leg.aoutcaps; - cur.ainpcaps = leg.ainpcaps; - cur.spkcaps = leg.spkcaps; - cur.physcalin = fromLegacy(leg.physcalin, ctx); - cur.phyfiltin = fromLegacy(leg.phyfiltin, ctx); - cur.physcalout = fromLegacy(leg.physcalout, ctx); - cur.phyfiltout = fromLegacy(leg.phyfiltout, ctx); - copyArr(cur.label, leg.label); - cur.userflags = leg.userflags; - copyArr(cur.position, leg.position); - cur.scalin = fromLegacy(leg.scalin, ctx); - cur.scalout = fromLegacy(leg.scalout, ctx); - cur.doutopts = leg.doutopts; - cur.dinpopts = leg.dinpopts; - cur.aoutopts = leg.aoutopts; - cur.eopchar = leg.eopchar; - cur.moninst = static_cast((leg.monsource >> 16) & 0xFFFF); // aka lowsamples - cur.monchan = static_cast(leg.monsource & 0xFFFF); // aka highsamples - cur.outvalue = leg.outvalue; // aka offset - cur.trigtype = leg.trigtype; - // skip reserved - cur.triginst = 0; // TODO: VERIFY - cur.trigchan = leg.trigchan; - cur.trigval = leg.trigval; - cur.ainpopts = leg.ainpopts; - cur.lncrate = leg.lncrate; - cur.smpfilter = leg.smpfilter; - cur.smpgroup = leg.smpgroup; - cur.smpdispmin = leg.smpdispmin; - cur.smpdispmax = leg.smpdispmax; - cur.spkfilter = leg.spkfilter; - cur.spkdispmax = leg.spkdispmax; - cur.lncdispmax = leg.lncdispmax; - cur.spkopts = leg.spkopts; - cur.spkthrlevel = leg.spkthrlevel; - cur.spkthrlimit = leg.spkthrlimit; - cur.spkgroup = leg.spkgroup; - cur.amplrejpos = leg.amplrejpos; - cur.amplrejneg = leg.amplrejneg; - cur.refelecchan = leg.refelecchan; - copyArr(cur.unitmapping, leg.unitmapping, fromLegacy, ctx); - copyArr2D(cur.spkhoops, leg.spkhoops, fromLegacy, ctx); - return cur; -} - -::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg, const TranslationContext& ctx) { - ::cbPKT_FS_BASIS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.mode = leg.mode; - cur.fs = leg.fs; - copyArr2D(cur.basis, leg.basis); - return cur; -} - -::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg, const TranslationContext& ctx) { - ::cbPKT_SS_MODELSET cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.unit_number = leg.unit_number; - cur.valid = leg.valid; - cur.inverted = leg.inverted; - cur.num_samples = leg.num_samples; - copyArr(cur.mu_x, leg.mu_x); - copyArr2D(cur.Sigma_x, leg.Sigma_x); - cur.determinant_Sigma_x = leg.determinant_Sigma_x; - copyArr2D(cur.Sigma_x_inv, leg.Sigma_x_inv); - cur.log_determinant_Sigma_x = leg.log_determinant_Sigma_x; - cur.subcluster_spread_factor_numerator = leg.subcluster_spread_factor_numerator; - cur.subcluster_spread_factor_denominator = leg.subcluster_spread_factor_denominator; - cur.mu_e = leg.mu_e; - cur.sigma_e_squared = leg.sigma_e_squared; - return cur; -} - -::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg, const TranslationContext& ctx) { - ::cbPKT_SS_DETECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.fThreshold = leg.fThreshold; - cur.fMultiplier = leg.fMultiplier; - return cur; -} - -::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg, const TranslationContext& ctx) { - ::cbPKT_SS_ARTIF_REJECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.nMaxSimulChans = leg.nMaxSimulChans; - cur.nRefractoryCount = leg.nRefractoryCount; - return cur; -} - -::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg, const TranslationContext& ctx) { - ::cbPKT_SS_NOISE_BOUNDARY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - copyArr(cur.afc, leg.afc); - copyArr2D(cur.afS, leg.afS); - return cur; -} - -::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg, const TranslationContext& ctx) { - ::cbPKT_SS_STATISTICS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.nUpdateSpikes = leg.nUpdateSpikes; - cur.nAutoalg = leg.nAutoalg; - cur.nMode = leg.nMode; - cur.fMinClusterPairSpreadFactor = leg.fMinClusterPairSpreadFactor; - cur.fMaxSubclusterSpreadFactor = leg.fMaxSubclusterSpreadFactor; - cur.fMinClusterHistCorrMajMeasure = leg.fMinClusterHistCorrMajMeasure; - cur.fMaxClusterPairHistCorrMajMeasure = leg.fMaxClusterPairHistCorrMajMeasure; - cur.fClusterHistValleyPercentage = leg.fClusterHistValleyPercentage; - cur.fClusterHistClosePeakPercentage = leg.fClusterHistClosePeakPercentage; - cur.fClusterHistMinPeakPercentage = leg.fClusterHistMinPeakPercentage; - cur.nWaveBasisSize = leg.nWaveBasisSize; - cur.nWaveSampleSize = leg.nWaveSampleSize; - return cur; -} - -::cbAdaptControl fromLegacy(const cbAdaptControl& leg, const TranslationContext& ctx) { - ::cbAdaptControl cur{}; - cur.nMode = leg.nMode; - cur.fTimeOutMinutes = leg.fTimeOutMinutes; - cur.fElapsedMinutes = leg.fElapsedMinutes; - return cur; -} - -::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg, const TranslationContext& ctx) { - ::cbPKT_SS_STATUS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats, ctx); - cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits, ctx); - return cur; -} - -::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg, const TranslationContext& ctx) { - ::cbproto::SpikeSorting cur{}; - copyArr(cur.basis, leg.asBasis, fromLegacy, ctx); - copyArr2D(cur.models, leg.asSortModel, fromLegacy, ctx); - cur.detect = fromLegacy(leg.pktDetect, ctx); - cur.artifact_reject = fromLegacy(leg.pktArtifReject, ctx); - copyArr(cur.noise_boundary, leg.pktNoiseBoundary, fromLegacy, ctx); - cur.statistics = fromLegacy(leg.pktStatistics, ctx); - cur.status = fromLegacy(leg.pktStatus, ctx); - return cur; -} - -::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg, const TranslationContext& ctx) { - ::cbPKT_NTRODEINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.ntrode = leg.ntrode; - copyArr(cur.label, leg.label); - copyArr2D(cur.ellipses, leg.ellipses, fromLegacy, ctx); - cur.nSite = leg.nSite; - cur.fs = leg.fs; - copyArr(cur.nChan, leg.nChan); - return cur; -} - -::cbWaveformData fromLegacy(const cbWaveformData& leg, const TranslationContext& ctx) { - ::cbWaveformData cur{}; - cur.offset = leg.offset; // aka sineFrequency - cur.seq = leg.seq; // aka sineAmplitude - cur.seqTotal = leg.seqTotal; - cur.phases = leg.phases; - copyArr(cur.duration, leg.duration); - copyArr(cur.amplitude, leg.amplitude); - return cur; -} - -::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg, const TranslationContext& ctx) { - ::cbPKT_AOUT_WAVEFORM cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.mode = leg.mode; - cur.repeats = leg.repeats; - cur.trig = static_cast((leg.trig >> 8) & 0xFF); - cur.trigInst = static_cast(leg.trig & 0xFF); - cur.trigChan = leg.trigChan; - cur.trigValue = leg.trigValue; - cur.trigNum = leg.trigNum; - cur.active = leg.active; - cur.wave = fromLegacy(leg.wave, ctx); - return cur; -} - -::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg, const TranslationContext& ctx) { - ::cbPKT_LNC cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.lncFreq = leg.lncFreq; - cur.lncRefChan = leg.lncRefChan; - cur.lncGlobalMode = leg.lncGlobalMode; - return cur; -} - -::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg, const TranslationContext& ctx) { - ::cbPKT_NPLAY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.ftime = leg.ftime; // aka opt - cur.stime = leg.stime; - cur.etime = leg.etime; - cur.val = leg.val; - cur.mode = leg.mode; - cur.flags = leg.flags; - cur.speed = leg.speed; - copyArr(cur.fname, leg.fname); - return cur; -} - -::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg, const TranslationContext& ctx) { - ::cbVIDEOSOURCE cur{}; - copyArr(cur.name, leg.name); - cur.fps = leg.fps; - return cur; -} - -::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg, const TranslationContext& ctx) { - ::cbTRACKOBJ cur{}; - copyArr(cur.name, leg.name); - cur.type = leg.type; - cur.pointCount = leg.pointCount; - return cur; -} - -::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg, const TranslationContext& ctx) { - ::cbPKT_FILECFG cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.options = leg.options; - cur.duration = leg.duration; - cur.recording = leg.recording; - cur.extctrl = leg.extctrl; - copyArr(cur.username, leg.username); - copyArr(cur.filename, leg.filename); // aka datetime - copyArr(cur.comment, leg.comment); - return cur; -} - -NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg, const TranslationContext& ctx) { - // TODO: VERIFY that each list that's assumed to be instrument-independent is in fact independent from any particular instrument. - NativeConfigBuffer cur{}; - cur.version = leg.version; - cur.sysflags = leg.sysflags; - cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); - cur.sysinfo = fromLegacy(leg.sysinfo, ctx); - cur.procinfo = fromLegacy(leg.procinfo[ctx.instrument_idx], ctx); - copyArr(cur.bankinfo, leg.bankinfo[ctx.instrument_idx], fromLegacy, ctx); - copyArr(cur.groupinfo, leg.groupinfo[ctx.instrument_idx], fromLegacy, ctx); - copyArr(cur.filtinfo, leg.filtinfo[ctx.instrument_idx], fromLegacy, ctx); - cur.adaptinfo = fromLegacy(leg.adaptinfo[ctx.instrument_idx], ctx); - cur.refelecinfo = fromLegacy(leg.refelecinfo[ctx.instrument_idx], ctx); - copyArr(cur.chaninfo, leg.chaninfo, fromLegacy, ctx); - copyArr(cur.asBasis, leg.isSortingOptions.asBasis, fromLegacy, ctx); - copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, fromLegacy, ctx); - // TODO: Move native isSortingOptions fields into a struct - cur.pktDetect = fromLegacy(leg.isSortingOptions.pktDetect, ctx); - cur.pktArtifReject = fromLegacy(leg.isSortingOptions.pktArtifReject, ctx); - copyArr(cur.pktNoiseBoundary, leg.isSortingOptions.pktNoiseBoundary, fromLegacy, ctx); - cur.pktStatistics = fromLegacy(leg.isSortingOptions.pktStatistics, ctx); - cur.pktStatus = fromLegacy(leg.isSortingOptions.pktStatus, ctx); - copyArr(cur.isNTrodeInfo, leg.isNTrodeInfo, fromLegacy, ctx); - copyArr2D(cur.isWaveform, leg.isWaveform, fromLegacy, ctx); - cur.isLnc = fromLegacy(leg.isLnc[ctx.instrument_idx], ctx); - cur.isNPlay = fromLegacy(leg.isNPlay, ctx); - copyArr(cur.isVideoSource, leg.isVideoSource, fromLegacy, ctx); - copyArr(cur.isTrackObj, leg.isTrackObj, fromLegacy, ctx); - cur.fileinfo = fromLegacy(leg.fileinfo, ctx); - - return cur; -} - -NativeNSPStatus fromLegacy(const NSPStatus& leg, const TranslationContext& ctx) { - switch(leg) { - case NSPStatus::NSP_INIT: - return NativeNSPStatus::NSP_INIT; - case NSPStatus::NSP_NOIPADDR: - return NativeNSPStatus::NSP_NOIPADDR; - case NSPStatus::NSP_NOREPLY: - return NativeNSPStatus::NSP_NOREPLY; - case NSPStatus::NSP_FOUND: - return NativeNSPStatus::NSP_FOUND; - case NSPStatus::NSP_INVALID: - default: - return NativeNSPStatus::NSP_INVALID; - } -} - -::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg, const TranslationContext& ctx) { - ::cbPKT_UNIT_SELECTION cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.lastchan = leg.lastchan; - copyArr(cur.abyUnitSelections, leg.abyUnitSelections); - return cur; -} - -NativePCStatus fromLegacy(const cbPcStatus& leg, const TranslationContext& ctx) { - NativePCStatus cur{}; - cur.isSelection = fromLegacy(leg.isSelection[ctx.instrument_idx], ctx); - cur.m_iBlockRecording = leg.m_iBlockRecording; - cur.m_nPCStatusFlags = leg.m_nPCStatusFlags; - cur.m_nNumFEChans = leg.m_nNumFEChans; - cur.m_nNumAnainChans = leg.m_nNumAnainChans; - cur.m_nNumAnalogChans = leg.m_nNumAnalogChans; - cur.m_nNumAoutChans = leg.m_nNumAoutChans; - cur.m_nNumAudioChans = leg.m_nNumAudioChans; - cur.m_nNumAnalogoutChans = leg.m_nNumAnalogoutChans; - cur.m_nNumDiginChans = leg.m_nNumDiginChans; - cur.m_nNumSerialChans = leg.m_nNumSerialChans; - cur.m_nNumDigoutChans = leg.m_nNumDigoutChans; - cur.m_nNumTotalChans = leg.m_nNumTotalChans; - cur.m_nNspStatus = fromLegacy(leg.m_nNspStatus[ctx.instrument_idx], ctx); - cur.m_nNumNTrodesPerInstrument = leg.m_nNumNTrodesPerInstrument[ctx.instrument_idx]; - cur.m_nGeminiSystem = leg.m_nGeminiSystem; - // ignore APP_WORKSPACE - return cur; -} - -NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg, const TranslationContext& ctx) { - NativeReceiveBuffer cur{}; - cur.received = leg.received; - cur.lasttime = leg.lasttime; - cur.headwrap = leg.headwrap; - cur.headindex = leg.headindex; - copyArr(cur.buffer, leg.buffer); - return cur; -} - -NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg, const TranslationContext& ctx) { - NativeTransmitBuffer cur{}; - cur.transmitted = leg.transmitted; - cur.headindex = leg.headindex; - cur.tailindex = leg.tailindex; - cur.last_valid_index = leg.last_valid_index; - cur.bufferlen = leg.bufferlen; - copyArr(cur.buffer, leg.buffer); - return cur; -} - -NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg, const TranslationContext& ctx) { - NativeTransmitBufferLocal cur{}; - cur.transmitted = leg.transmitted; - cur.headindex = leg.headindex; - cur.tailindex = leg.tailindex; - cur.last_valid_index = leg.last_valid_index; - cur.bufferlen = leg.bufferlen; - copyArr(cur.buffer, leg.buffer); - return cur; -} - -cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur, const TranslationContext& ctx) { - cbPKT_HEADER leg{}; - leg.time = cur.time; - leg.chid = cur.chid; - leg.type = static_cast(cur.type); - leg.dlen = cur.dlen; - leg.instrument = cur.instrument; - leg.reserved = cur.reserved; - return leg; -} - -cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur, const TranslationContext& ctx) { - cbPKT_SYSINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.sysfreq = cur.sysfreq; - leg.spikelen = cur.spikelen; - leg.spikepre = cur.spikepre; - leg.resetque = cur.resetque; - leg.runlevel = cur.runlevel; - leg.runflags = cur.runflags; - return leg; -} - -cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur, const TranslationContext& ctx) { - cbPKT_PROCINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.proc = cur.proc; - leg.idcode = cur.idcode; - leg.idcode = cur.idcode; - copyArr(leg.ident, cur.ident); - leg.chanbase = cur.chanbase; - leg.chancount = cur.chancount; - leg.bankcount = cur.bankcount; - leg.groupcount = cur.groupcount; - leg.filtcount = cur.filtcount; - leg.sortcount = cur.sortcount; - leg.unitcount = cur.unitcount; - leg.hoopcount = cur.hoopcount; - leg.reserved = cur.reserved; - leg.version = cur.version; - return leg; -} - -cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur, const TranslationContext& ctx) { - cbPKT_BANKINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.proc = cur.proc; - leg.bank = cur.bank; - leg.idcode = cur.idcode; - copyArr(leg.ident, cur.ident); - copyArr(leg.label, cur.label); - leg.chanbase = cur.chanbase; - leg.chancount = cur.chancount; - return leg; -} - -cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur, const TranslationContext& ctx) { - cbPKT_GROUPINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.proc = cur.proc; - leg.group = cur.group; - copyArr(leg.label, cur.label); - leg.period = cur.period; - leg.length = cur.length; - copyArr(leg.list, cur.list); - return leg; -} - -cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur, const TranslationContext& ctx) { - cbPKT_FILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.proc = cur.proc; - leg.filt = cur.filt; - copyArr(leg.label, cur.label); - leg.hpfreq = cur.hpfreq; - leg.hporder = cur.hporder; - leg.hptype = cur.hptype; - leg.lpfreq = cur.lpfreq; - leg.lporder = cur.lporder; - leg.lptype = cur.lptype; - leg.gain = cur.gain; - leg.sos1a1 = cur.sos1a1; - leg.sos1a2 = cur.sos1a2; - leg.sos1b1 = cur.sos1b1; - leg.sos1b2 = cur.sos1b2; - leg.sos2a1 = cur.sos2a1; - leg.sos2a2 = cur.sos2a2; - leg.sos2b1 = cur.sos2b1; - leg.sos2b2 = cur.sos2b2; - return leg; -} - -cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur, const TranslationContext& ctx) { - cbPKT_ADAPTFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.nMode = cur.nMode; - leg.dLearningRate = cur.dLearningRate; - leg.nRefChan1 = cur.nRefChan1; - leg.nRefChan2 = cur.nRefChan2; - return leg; -} - -cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur, const TranslationContext& ctx) { - cbPKT_REFELECFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.nMode = cur.nMode; - leg.nRefChan = cur.nRefChan; - return leg; -} - -cbSCALING toLegacy(const ::cbSCALING& cur, const TranslationContext& ctx) { - cbSCALING leg{}; - leg.digmin = cur.digmin; - leg.digmax = cur.digmax; - leg.anamin = cur.anamin; - leg.anamax = cur.anamax; - leg.anagain = cur.anagain; - copyArr(leg.anaunit, cur.anaunit); - return leg; -} - -cbFILTDESC toLegacy(const ::cbFILTDESC& cur, const TranslationContext& ctx) { - cbFILTDESC leg{}; - leg.hpfreq = cur.hpfreq; - leg.hporder = cur.hporder; - leg.hptype = cur.hptype; - leg.lpfreq = cur.lpfreq; - leg.lporder = cur.lporder; - leg.lptype = cur.lptype; - return leg; -} - -cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur, const TranslationContext& ctx) { - cbMANUALUNITMAPPING leg{}; - leg.nOverride = cur.nOverride; - copyArr(leg.afOrigin, cur.afOrigin); - copyArr2D(leg.afShape, cur.afShape); - leg.aPhi = cur.aPhi; - leg.bValid = cur.bValid; - return leg; -} - -cbHOOP toLegacy(const ::cbHOOP& cur, const TranslationContext& ctx) { - cbHOOP leg{}; - leg.valid = cur.valid; - leg.time = cur.time; - leg.min = cur.min; - leg.max = cur.max; - return leg; -} - -cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur, const TranslationContext& ctx) { - cbPKT_CHANINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.proc = cur.proc; - leg.bank = cur.bank; - leg.term = cur.term; - leg.chancaps = cur.chancaps; - leg.doutcaps = cur.doutcaps; - leg.dinpcaps = cur.dinpcaps; - leg.aoutcaps = cur.aoutcaps; - leg.ainpcaps = cur.ainpcaps; - leg.spkcaps = cur.spkcaps; - leg.physcalin = toLegacy(cur.physcalin, ctx); - leg.phyfiltin = toLegacy(cur.phyfiltin, ctx); - leg.physcalout = toLegacy(cur.physcalout, ctx); - leg.phyfiltout = toLegacy(cur.phyfiltout, ctx); - copyArr(leg.label, cur.label); - leg.userflags = cur.userflags; - copyArr(leg.position, cur.position); - leg.scalin = toLegacy(cur.scalin, ctx); - leg.scalout = toLegacy(cur.scalout, ctx); - leg.doutopts = cur.doutopts; - leg.dinpopts = cur.dinpopts; - leg.aoutopts = cur.aoutopts; - leg.eopchar = cur.eopchar; - leg.monsource = (static_cast(cur.moninst) << 16) | static_cast(cur.monchan); // aka highsamples and lowsamples - leg.outvalue = cur.outvalue; // aka offset - leg.trigtype = cur.trigtype; - leg.trigchan = cur.trigchan; - leg.trigval = cur.trigval; - leg.ainpopts = cur.ainpopts; - leg.lncrate = cur.lncrate; - leg.smpfilter = cur.smpfilter; - leg.smpgroup = cur.smpgroup; - leg.smpdispmin = cur.smpdispmin; - leg.smpdispmax = cur.smpdispmax; - leg.spkfilter = cur.spkfilter; - leg.spkdispmax = cur.spkdispmax; - leg.lncdispmax = cur.lncdispmax; - leg.spkopts = cur.spkopts; - leg.spkthrlevel = cur.spkthrlevel; - leg.spkthrlimit = cur.spkthrlimit; - leg.spkgroup = cur.spkgroup; - leg.amplrejpos = cur.amplrejpos; - leg.amplrejneg = cur.amplrejneg; - leg.refelecchan = cur.refelecchan; - copyArr(leg.unitmapping, cur.unitmapping, toLegacy, ctx); - copyArr2D(leg.spkhoops, cur.spkhoops, toLegacy, ctx); - return leg; -} - -cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur, const TranslationContext& ctx) { - cbPKT_FS_BASIS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.mode = cur.mode; - leg.fs = cur.fs; - copyArr2D(leg.basis, cur.basis); - return leg; -} - -cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur, const TranslationContext& ctx) { - cbPKT_SS_MODELSET leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.unit_number = cur.unit_number; - leg.valid = cur.valid; - leg.inverted = cur.inverted; - leg.num_samples = cur.num_samples; - copyArr(leg.mu_x, cur.mu_x); - copyArr2D(leg.Sigma_x, cur.Sigma_x); - leg.determinant_Sigma_x = cur.determinant_Sigma_x; - copyArr2D(leg.Sigma_x_inv, cur.Sigma_x_inv); - leg.log_determinant_Sigma_x = cur.log_determinant_Sigma_x; - leg.subcluster_spread_factor_numerator = cur.subcluster_spread_factor_numerator; - leg.subcluster_spread_factor_denominator = cur.subcluster_spread_factor_denominator; - leg.mu_e = cur.mu_e; - leg.sigma_e_squared = cur.sigma_e_squared; - return leg; -} - -cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur, const TranslationContext& ctx) { - cbPKT_SS_DETECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.fThreshold = cur.fThreshold; - leg.fMultiplier = cur.fMultiplier; - return leg; -} - -cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur, const TranslationContext& ctx) { - cbPKT_SS_ARTIF_REJECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.nMaxSimulChans = cur.nMaxSimulChans; - leg.nRefractoryCount = cur.nRefractoryCount; - return leg; -} - -cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur, const TranslationContext& ctx) { - cbPKT_SS_NOISE_BOUNDARY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - copyArr(leg.afc, cur.afc); - copyArr2D(leg.afS, cur.afS); - return leg; -} - -cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur, const TranslationContext& ctx) { - cbPKT_SS_STATISTICS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.nUpdateSpikes = cur.nUpdateSpikes; - leg.nAutoalg = cur.nAutoalg; - leg.nMode = cur.nMode; - leg.fMinClusterPairSpreadFactor = cur.fMinClusterPairSpreadFactor; - leg.fMaxSubclusterSpreadFactor = cur.fMaxSubclusterSpreadFactor; - leg.fMinClusterHistCorrMajMeasure = cur.fMinClusterHistCorrMajMeasure; - leg.fMaxClusterPairHistCorrMajMeasure = cur.fMaxClusterPairHistCorrMajMeasure; - leg.fClusterHistValleyPercentage = cur.fClusterHistValleyPercentage; - leg.fClusterHistClosePeakPercentage = cur.fClusterHistClosePeakPercentage; - leg.fClusterHistMinPeakPercentage = cur.fClusterHistMinPeakPercentage; - leg.nWaveBasisSize = cur.nWaveBasisSize; - leg.nWaveSampleSize = cur.nWaveSampleSize; - return leg; -} - -cbAdaptControl toLegacy(const ::cbAdaptControl& cur, const TranslationContext& ctx) { - cbAdaptControl leg{}; - leg.nMode = cur.nMode; - leg.fTimeOutMinutes = cur.fTimeOutMinutes; - leg.fElapsedMinutes = cur.fElapsedMinutes; - return leg; -} - -cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur, const TranslationContext& ctx) { - cbPKT_SS_STATUS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.cntlUnitStats = toLegacy(cur.cntlUnitStats, ctx); - leg.cntlNumUnits = toLegacy(cur.cntlNumUnits, ctx); - return leg; -} - -cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur, const TranslationContext& ctx) { - cbSPIKE_SORTING leg{}; - copyArr(leg.asBasis, cur.basis, toLegacy, ctx); - copyArr2D(leg.asSortModel, cur.models, toLegacy, ctx); - leg.pktDetect = toLegacy(cur.detect, ctx); - leg.pktArtifReject = toLegacy(cur.artifact_reject, ctx); - copyArr(leg.pktNoiseBoundary, cur.noise_boundary, toLegacy, ctx); - leg.pktStatistics = toLegacy(cur.statistics, ctx); - leg.pktStatus = toLegacy(cur.status, ctx); - return leg; -} - -cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur, const TranslationContext& ctx) { - cbPKT_NTRODEINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.ntrode = cur.ntrode; - copyArr(leg.label, cur.label); - copyArr2D(leg.ellipses, cur.ellipses, toLegacy, ctx); - leg.nSite = cur.nSite; - leg.fs = cur.fs; - copyArr(leg.nChan, cur.nChan); - return leg; -} - -cbWaveformData toLegacy(const ::cbWaveformData& cur, const TranslationContext& ctx) { - cbWaveformData leg{}; - leg.offset = cur.offset; // aka sineFrequency - leg.seq = cur.seq; // aka sineAmplitude - leg.seqTotal = cur.seqTotal; - leg.phases = cur.phases; - copyArr(leg.duration, cur.duration); - copyArr(leg.amplitude, cur.amplitude); - return leg; -} - -cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur, const TranslationContext& ctx) { - cbPKT_AOUT_WAVEFORM leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.mode = cur.mode; - leg.repeats = cur.repeats; - leg.trig = (static_cast(cur.trig) << 8) | static_cast(cur.trigInst); - leg.trigChan = cur.trigChan; - leg.trigValue = cur.trigValue; - leg.trigNum = cur.trigNum; - leg.active = cur.active; - leg.wave = toLegacy(cur.wave, ctx); - return leg; -} - -cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur, const TranslationContext& ctx) { - cbPKT_LNC leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.lncFreq = cur.lncFreq; - leg.lncRefChan = cur.lncRefChan; - leg.lncGlobalMode = cur.lncGlobalMode; - return leg; -} - -cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur, const TranslationContext& ctx) { - cbPKT_NPLAY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.ftime = cur.ftime; // aka opt - leg.stime = cur.stime; - leg.etime = cur.etime; - leg.val = cur.val; - leg.mode = cur.mode; - leg.flags = cur.flags; - leg.speed = cur.speed; - copyArr(leg.fname, cur.fname); - return leg; -} - -cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur, const TranslationContext& ctx) { - cbVIDEOSOURCE leg{}; - copyArr(leg.name, cur.name); - leg.fps = cur.fps; - return leg; -} - -cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur, const TranslationContext& ctx) { - cbTRACKOBJ leg{}; - copyArr(leg.name, cur.name); - leg.type = cur.type; - leg.pointCount = cur.pointCount; - return leg; -} - -cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur, const TranslationContext& ctx) { - cbPKT_FILECFG leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.options = cur.options; - leg.duration = cur.duration; - leg.recording = cur.recording; - leg.extctrl = cur.extctrl; - copyArr(leg.username, cur.username); - copyArr(leg.filename, cur.filename); // aka datetime - copyArr(leg.comment, cur.comment); - return leg; -} - -NSPStatus toLegacy(const NativeNSPStatus& cur, const TranslationContext& ctx) { - switch(cur) { - case NativeNSPStatus::NSP_INIT: - return NSPStatus::NSP_INIT; - case NativeNSPStatus::NSP_NOIPADDR: - return NSPStatus::NSP_NOIPADDR; - case NativeNSPStatus::NSP_NOREPLY: - return NSPStatus::NSP_NOREPLY; - case NativeNSPStatus::NSP_FOUND: - return NSPStatus::NSP_FOUND; - case NativeNSPStatus::NSP_INVALID: - default: - return NSPStatus::NSP_INVALID; - } -} - -cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur, const TranslationContext& ctx) { - cbPKT_UNIT_SELECTION leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.lastchan = cur.lastchan; - copyArr(leg.abyUnitSelections, cur.abyUnitSelections); - return leg; -} - -cbPcStatus toLegacy(const NativePCStatus& cur, const TranslationContext& ctx) { - cbPcStatus leg{}; - leg.isSelection[ctx.instrument_idx] = toLegacy(cur.isSelection, ctx); - leg.m_iBlockRecording = cur.m_iBlockRecording; - leg.m_nPCStatusFlags = cur.m_nPCStatusFlags; - leg.m_nNumFEChans = cur.m_nNumFEChans; - leg.m_nNumAnainChans = cur.m_nNumAnainChans; - leg.m_nNumAnalogChans = cur.m_nNumAnalogChans; - leg.m_nNumAoutChans = cur.m_nNumAoutChans; - leg.m_nNumAudioChans = cur.m_nNumAudioChans; - leg.m_nNumAnalogoutChans = cur.m_nNumAnalogoutChans; - leg.m_nNumDiginChans = cur.m_nNumDiginChans; - leg.m_nNumSerialChans = cur.m_nNumSerialChans; - leg.m_nNumDigoutChans = cur.m_nNumDigoutChans; - leg.m_nNumTotalChans = cur.m_nNumTotalChans; - leg.m_nNspStatus[ctx.instrument_idx] = toLegacy(cur.m_nNspStatus, ctx); - leg.m_nNumNTrodesPerInstrument[ctx.instrument_idx] = cur.m_nNumNTrodesPerInstrument; - leg.m_nGeminiSystem = cur.m_nGeminiSystem; - // ignore APP_WORKSPACE - return leg; -} - -cbRECBUFF toLegacy(const NativeReceiveBuffer& cur, const TranslationContext& ctx) { - cbRECBUFF leg{}; - leg.received = cur.received; - leg.lasttime = cur.lasttime; - leg.headwrap = cur.headwrap; - leg.headindex = cur.headindex; - copyArr(leg.buffer, cur.buffer); - return leg; -} - -cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur, const TranslationContext& ctx) { - cbXMTBUFF leg{}; - leg.transmitted = cur.transmitted; - leg.headindex = cur.headindex; - leg.tailindex = cur.tailindex; - leg.last_valid_index = cur.last_valid_index; - leg.bufferlen = cur.bufferlen; - copyArr(leg.buffer, cur.buffer); - return leg; -} - -cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur, const TranslationContext& ctx) { - cbXMTBUFFLOCAL leg{}; - leg.transmitted = cur.transmitted; - leg.headindex = cur.headindex; - leg.tailindex = cur.tailindex; - leg.last_valid_index = cur.last_valid_index; - leg.bufferlen = cur.bufferlen; - copyArr(leg.buffer, cur.buffer); - return leg; -} - -} // namespace central_v4_0 - -} // namespace cbshm diff --git a/src/cbshm/src/central_translators/v4_1.cpp b/src/cbshm/src/central_translators/v4_1.cpp deleted file mode 100644 index fbd31ccf..00000000 --- a/src/cbshm/src/central_translators/v4_1.cpp +++ /dev/null @@ -1,1007 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file v4_1.cpp -/// @author Caden Shmookler -/// @date 2026-05-22 -/// -/// @brief Central translator implementations -/// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#include "utils.h" -#include -#include - -namespace cbshm { - -namespace central_v4_1 { - -::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg, const TranslationContext& ctx) { - ::cbPKT_HEADER cur{}; - cur.time = leg.time; - cur.chid = leg.chid; - cur.type = leg.type; - cur.dlen = leg.dlen; - cur.instrument = leg.instrument; - cur.reserved = leg.reserved; - return cur; -} - -::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg, const TranslationContext& ctx) { - ::cbPKT_SYSINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.sysfreq = leg.sysfreq; - cur.spikelen = leg.spikelen; - cur.spikepre = leg.spikepre; - cur.resetque = leg.resetque; - cur.runlevel = leg.runlevel; - cur.runflags = leg.runflags; - return cur; -} - -::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg, const TranslationContext& ctx) { - ::cbPKT_PROCINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.proc = leg.proc; - cur.idcode = leg.idcode; - cur.idcode = leg.idcode; - copyArr(cur.ident, leg.ident); - cur.chanbase = leg.chanbase; - cur.chancount = leg.chancount; - cur.bankcount = leg.bankcount; - cur.groupcount = leg.groupcount; - cur.filtcount = leg.filtcount; - cur.sortcount = leg.sortcount; - cur.unitcount = leg.unitcount; - cur.hoopcount = leg.hoopcount; - cur.reserved = leg.reserved; - cur.version = leg.version; - return cur; -} - -::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg, const TranslationContext& ctx) { - ::cbPKT_BANKINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.proc = leg.proc; - cur.bank = leg.bank; - cur.idcode = leg.idcode; - copyArr(cur.ident, leg.ident); - copyArr(cur.label, leg.label); - cur.chanbase = leg.chanbase; - cur.chancount = leg.chancount; - return cur; -} - -::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg, const TranslationContext& ctx) { - ::cbPKT_GROUPINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.proc = leg.proc; - cur.group = leg.group; - copyArr(cur.label, leg.label); - cur.period = leg.period; - cur.length = leg.length; - copyArr(cur.list, leg.list); - return cur; -} - -::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg, const TranslationContext& ctx) { - ::cbPKT_FILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.proc = leg.proc; - cur.filt = leg.filt; - copyArr(cur.label, leg.label); - cur.hpfreq = leg.hpfreq; - cur.hporder = leg.hporder; - cur.hptype = leg.hptype; - cur.lpfreq = leg.lpfreq; - cur.lporder = leg.lporder; - cur.lptype = leg.lptype; - cur.gain = leg.gain; - cur.sos1a1 = leg.sos1a1; - cur.sos1a2 = leg.sos1a2; - cur.sos1b1 = leg.sos1b1; - cur.sos1b2 = leg.sos1b2; - cur.sos2a1 = leg.sos2a1; - cur.sos2a2 = leg.sos2a2; - cur.sos2b1 = leg.sos2b1; - cur.sos2b2 = leg.sos2b2; - return cur; -} - -::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg, const TranslationContext& ctx) { - ::cbPKT_ADAPTFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.nMode = leg.nMode; - cur.dLearningRate = leg.dLearningRate; - cur.nRefChan1 = leg.nRefChan1; - cur.nRefChan2 = leg.nRefChan2; - return cur; -} - -::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg, const TranslationContext& ctx) { - ::cbPKT_REFELECFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.nMode = leg.nMode; - cur.nRefChan = leg.nRefChan; - return cur; -} - -::cbSCALING fromLegacy(const cbSCALING& leg, const TranslationContext& ctx) { - ::cbSCALING cur{}; - cur.digmin = leg.digmin; - cur.digmax = leg.digmax; - cur.anamin = leg.anamin; - cur.anamax = leg.anamax; - cur.anagain = leg.anagain; - copyArr(cur.anaunit, leg.anaunit); - return cur; -} - -::cbFILTDESC fromLegacy(const cbFILTDESC& leg, const TranslationContext& ctx) { - ::cbFILTDESC cur{}; - cur.hpfreq = leg.hpfreq; - cur.hporder = leg.hporder; - cur.hptype = leg.hptype; - cur.lpfreq = leg.lpfreq; - cur.lporder = leg.lporder; - cur.lptype = leg.lptype; - return cur; -} - -::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg, const TranslationContext& ctx) { - ::cbMANUALUNITMAPPING cur{}; - cur.nOverride = leg.nOverride; - copyArr(cur.afOrigin, leg.afOrigin); - copyArr2D(cur.afShape, leg.afShape); - cur.aPhi = leg.aPhi; - cur.bValid = leg.bValid; - return cur; -} - -::cbHOOP fromLegacy(const cbHOOP& leg, const TranslationContext& ctx) { - ::cbHOOP cur{}; - cur.valid = leg.valid; - cur.time = leg.time; - cur.min = leg.min; - cur.max = leg.max; - return cur; -} - -::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg, const TranslationContext& ctx) { - ::cbPKT_CHANINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.proc = leg.proc; - cur.bank = leg.bank; - cur.term = leg.term; - cur.chancaps = leg.chancaps; - cur.doutcaps = leg.doutcaps; - cur.dinpcaps = leg.dinpcaps; - cur.aoutcaps = leg.aoutcaps; - cur.ainpcaps = leg.ainpcaps; - cur.spkcaps = leg.spkcaps; - cur.physcalin = fromLegacy(leg.physcalin, ctx); - cur.phyfiltin = fromLegacy(leg.phyfiltin, ctx); - cur.physcalout = fromLegacy(leg.physcalout, ctx); - cur.phyfiltout = fromLegacy(leg.phyfiltout, ctx); - copyArr(cur.label, leg.label); - cur.userflags = leg.userflags; - copyArr(cur.position, leg.position); - cur.scalin = fromLegacy(leg.scalin, ctx); - cur.scalout = fromLegacy(leg.scalout, ctx); - cur.doutopts = leg.doutopts; - cur.dinpopts = leg.dinpopts; - cur.aoutopts = leg.aoutopts; - cur.eopchar = leg.eopchar; - cur.moninst = leg.moninst; // aka lowsamples - cur.monchan = leg.monchan; // aka highsamples - cur.outvalue = leg.outvalue; // aka offset - cur.trigtype = leg.trigtype; - copyArr(cur.reserved, leg.reserved); - cur.triginst = leg.triginst; - cur.trigchan = leg.trigchan; - cur.trigval = leg.trigval; - cur.ainpopts = leg.ainpopts; - cur.lncrate = leg.lncrate; - cur.smpfilter = leg.smpfilter; - cur.smpgroup = leg.smpgroup; - cur.smpdispmin = leg.smpdispmin; - cur.smpdispmax = leg.smpdispmax; - cur.spkfilter = leg.spkfilter; - cur.spkdispmax = leg.spkdispmax; - cur.lncdispmax = leg.lncdispmax; - cur.spkopts = leg.spkopts; - cur.spkthrlevel = leg.spkthrlevel; - cur.spkthrlimit = leg.spkthrlimit; - cur.spkgroup = leg.spkgroup; - cur.amplrejpos = leg.amplrejpos; - cur.amplrejneg = leg.amplrejneg; - cur.refelecchan = leg.refelecchan; - copyArr(cur.unitmapping, leg.unitmapping, fromLegacy, ctx); - copyArr2D(cur.spkhoops, leg.spkhoops, fromLegacy, ctx); - return cur; -} - -::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg, const TranslationContext& ctx) { - ::cbPKT_FS_BASIS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.mode = leg.mode; - cur.fs = leg.fs; - copyArr2D(cur.basis, leg.basis); - return cur; -} - -::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg, const TranslationContext& ctx) { - ::cbPKT_SS_MODELSET cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.unit_number = leg.unit_number; - cur.valid = leg.valid; - cur.inverted = leg.inverted; - cur.num_samples = leg.num_samples; - copyArr(cur.mu_x, leg.mu_x); - copyArr2D(cur.Sigma_x, leg.Sigma_x); - cur.determinant_Sigma_x = leg.determinant_Sigma_x; - copyArr2D(cur.Sigma_x_inv, leg.Sigma_x_inv); - cur.log_determinant_Sigma_x = leg.log_determinant_Sigma_x; - cur.subcluster_spread_factor_numerator = leg.subcluster_spread_factor_numerator; - cur.subcluster_spread_factor_denominator = leg.subcluster_spread_factor_denominator; - cur.mu_e = leg.mu_e; - cur.sigma_e_squared = leg.sigma_e_squared; - return cur; -} - -::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg, const TranslationContext& ctx) { - ::cbPKT_SS_DETECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.fThreshold = leg.fThreshold; - cur.fMultiplier = leg.fMultiplier; - return cur; -} - -::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg, const TranslationContext& ctx) { - ::cbPKT_SS_ARTIF_REJECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.nMaxSimulChans = leg.nMaxSimulChans; - cur.nRefractoryCount = leg.nRefractoryCount; - return cur; -} - -::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg, const TranslationContext& ctx) { - ::cbPKT_SS_NOISE_BOUNDARY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - copyArr(cur.afc, leg.afc); - copyArr2D(cur.afS, leg.afS); - return cur; -} - -::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg, const TranslationContext& ctx) { - ::cbPKT_SS_STATISTICS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.nUpdateSpikes = leg.nUpdateSpikes; - cur.nAutoalg = leg.nAutoalg; - cur.nMode = leg.nMode; - cur.fMinClusterPairSpreadFactor = leg.fMinClusterPairSpreadFactor; - cur.fMaxSubclusterSpreadFactor = leg.fMaxSubclusterSpreadFactor; - cur.fMinClusterHistCorrMajMeasure = leg.fMinClusterHistCorrMajMeasure; - cur.fMaxClusterPairHistCorrMajMeasure = leg.fMaxClusterPairHistCorrMajMeasure; - cur.fClusterHistValleyPercentage = leg.fClusterHistValleyPercentage; - cur.fClusterHistClosePeakPercentage = leg.fClusterHistClosePeakPercentage; - cur.fClusterHistMinPeakPercentage = leg.fClusterHistMinPeakPercentage; - cur.nWaveBasisSize = leg.nWaveBasisSize; - cur.nWaveSampleSize = leg.nWaveSampleSize; - return cur; -} - -::cbAdaptControl fromLegacy(const cbAdaptControl& leg, const TranslationContext& ctx) { - ::cbAdaptControl cur{}; - cur.nMode = leg.nMode; - cur.fTimeOutMinutes = leg.fTimeOutMinutes; - cur.fElapsedMinutes = leg.fElapsedMinutes; - return cur; -} - -::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg, const TranslationContext& ctx) { - ::cbPKT_SS_STATUS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats, ctx); - cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits, ctx); - return cur; -} - -::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg, const TranslationContext& ctx) { - ::cbproto::SpikeSorting cur{}; - copyArr(cur.basis, leg.asBasis, fromLegacy, ctx); - copyArr2D(cur.models, leg.asSortModel, fromLegacy, ctx); - cur.detect = fromLegacy(leg.pktDetect, ctx); - cur.artifact_reject = fromLegacy(leg.pktArtifReject, ctx); - copyArr(cur.noise_boundary, leg.pktNoiseBoundary, fromLegacy, ctx); - cur.statistics = fromLegacy(leg.pktStatistics, ctx); - cur.status = fromLegacy(leg.pktStatus, ctx); - return cur; -} - -::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg, const TranslationContext& ctx) { - ::cbPKT_NTRODEINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.ntrode = leg.ntrode; - copyArr(cur.label, leg.label); - copyArr2D(cur.ellipses, leg.ellipses, fromLegacy, ctx); - cur.nSite = leg.nSite; - cur.fs = leg.fs; - copyArr(cur.nChan, leg.nChan); - return cur; -} - -::cbWaveformData fromLegacy(const cbWaveformData& leg, const TranslationContext& ctx) { - ::cbWaveformData cur{}; - cur.offset = leg.offset; // aka sineFrequency - cur.seq = leg.seq; // aka sineAmplitude - cur.seqTotal = leg.seqTotal; - cur.phases = leg.phases; - copyArr(cur.duration, leg.duration); - copyArr(cur.amplitude, leg.amplitude); - return cur; -} - -::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg, const TranslationContext& ctx) { - ::cbPKT_AOUT_WAVEFORM cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.mode = leg.mode; - cur.repeats = leg.repeats; - cur.trig = leg.trig; - cur.trigInst = leg.trigInst; - cur.trigChan = leg.trigChan; - cur.trigValue = leg.trigValue; - cur.trigNum = leg.trigNum; - cur.active = leg.active; - cur.wave = fromLegacy(leg.wave, ctx); - return cur; -} - -::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg, const TranslationContext& ctx) { - ::cbPKT_LNC cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.lncFreq = leg.lncFreq; - cur.lncRefChan = leg.lncRefChan; - cur.lncGlobalMode = leg.lncGlobalMode; - return cur; -} - -::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg, const TranslationContext& ctx) { - ::cbPKT_NPLAY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.ftime = leg.ftime; // aka opt - cur.stime = leg.stime; - cur.etime = leg.etime; - cur.val = leg.val; - cur.mode = leg.mode; - cur.flags = leg.flags; - cur.speed = leg.speed; - copyArr(cur.fname, leg.fname); - return cur; -} - -::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg, const TranslationContext& ctx) { - ::cbVIDEOSOURCE cur{}; - copyArr(cur.name, leg.name); - cur.fps = leg.fps; - return cur; -} - -::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg, const TranslationContext& ctx) { - ::cbTRACKOBJ cur{}; - copyArr(cur.name, leg.name); - cur.type = leg.type; - cur.pointCount = leg.pointCount; - return cur; -} - -::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg, const TranslationContext& ctx) { - ::cbPKT_FILECFG cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.options = leg.options; - cur.duration = leg.duration; - cur.recording = leg.recording; - cur.extctrl = leg.extctrl; - copyArr(cur.username, leg.username); - copyArr(cur.filename, leg.filename); // aka datetime - copyArr(cur.comment, leg.comment); - return cur; -} - -NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg, const TranslationContext& ctx) { - // TODO: VERIFY that each list that's assumed to be instrument-independent is in fact independent from any particular instrument. - NativeConfigBuffer cur{}; - cur.version = leg.version; - cur.sysflags = leg.sysflags; - cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); - cur.sysinfo = fromLegacy(leg.sysinfo, ctx); - cur.procinfo = fromLegacy(leg.procinfo[ctx.instrument_idx], ctx); - copyArr(cur.bankinfo, leg.bankinfo[ctx.instrument_idx], fromLegacy, ctx); - copyArr(cur.groupinfo, leg.groupinfo[ctx.instrument_idx], fromLegacy, ctx); - copyArr(cur.filtinfo, leg.filtinfo[ctx.instrument_idx], fromLegacy, ctx); - cur.adaptinfo = fromLegacy(leg.adaptinfo[ctx.instrument_idx], ctx); - cur.refelecinfo = fromLegacy(leg.refelecinfo[ctx.instrument_idx], ctx); - copyArr(cur.chaninfo, leg.chaninfo, fromLegacy, ctx); - copyArr(cur.asBasis, leg.isSortingOptions.asBasis, fromLegacy, ctx); - copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, fromLegacy, ctx); - // TODO: Move native isSortingOptions fields into a struct - cur.pktDetect = fromLegacy(leg.isSortingOptions.pktDetect, ctx); - cur.pktArtifReject = fromLegacy(leg.isSortingOptions.pktArtifReject, ctx); - copyArr(cur.pktNoiseBoundary, leg.isSortingOptions.pktNoiseBoundary, fromLegacy, ctx); - cur.pktStatistics = fromLegacy(leg.isSortingOptions.pktStatistics, ctx); - cur.pktStatus = fromLegacy(leg.isSortingOptions.pktStatus, ctx); - copyArr(cur.isNTrodeInfo, leg.isNTrodeInfo, fromLegacy, ctx); - copyArr2D(cur.isWaveform, leg.isWaveform, fromLegacy, ctx); - cur.isLnc = fromLegacy(leg.isLnc[ctx.instrument_idx], ctx); - cur.isNPlay = fromLegacy(leg.isNPlay, ctx); - copyArr(cur.isVideoSource, leg.isVideoSource, fromLegacy, ctx); - copyArr(cur.isTrackObj, leg.isTrackObj, fromLegacy, ctx); - cur.fileinfo = fromLegacy(leg.fileinfo, ctx); - - return cur; -} - -NativeNSPStatus fromLegacy(const NSPStatus& leg, const TranslationContext& ctx) { - switch(leg) { - case NSPStatus::NSP_INIT: - return NativeNSPStatus::NSP_INIT; - case NSPStatus::NSP_NOIPADDR: - return NativeNSPStatus::NSP_NOIPADDR; - case NSPStatus::NSP_NOREPLY: - return NativeNSPStatus::NSP_NOREPLY; - case NSPStatus::NSP_FOUND: - return NativeNSPStatus::NSP_FOUND; - case NSPStatus::NSP_INVALID: - default: - return NativeNSPStatus::NSP_INVALID; - } -} - -::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg, const TranslationContext& ctx) { - ::cbPKT_UNIT_SELECTION cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.lastchan = leg.lastchan; - copyArr(cur.abyUnitSelections, leg.abyUnitSelections); - return cur; -} - -NativePCStatus fromLegacy(const cbPcStatus& leg, const TranslationContext& ctx) { - NativePCStatus cur{}; - cur.isSelection = fromLegacy(leg.isSelection[ctx.instrument_idx], ctx); - cur.m_iBlockRecording = leg.m_iBlockRecording; - cur.m_nPCStatusFlags = leg.m_nPCStatusFlags; - cur.m_nNumFEChans = leg.m_nNumFEChans; - cur.m_nNumAnainChans = leg.m_nNumAnainChans; - cur.m_nNumAnalogChans = leg.m_nNumAnalogChans; - cur.m_nNumAoutChans = leg.m_nNumAoutChans; - cur.m_nNumAudioChans = leg.m_nNumAudioChans; - cur.m_nNumAnalogoutChans = leg.m_nNumAnalogoutChans; - cur.m_nNumDiginChans = leg.m_nNumDiginChans; - cur.m_nNumSerialChans = leg.m_nNumSerialChans; - cur.m_nNumDigoutChans = leg.m_nNumDigoutChans; - cur.m_nNumTotalChans = leg.m_nNumTotalChans; - cur.m_nNspStatus = fromLegacy(leg.m_nNspStatus[ctx.instrument_idx], ctx); - cur.m_nNumNTrodesPerInstrument = leg.m_nNumNTrodesPerInstrument[ctx.instrument_idx]; - cur.m_nGeminiSystem = leg.m_nGeminiSystem; - // ignore APP_WORKSPACE - return cur; -} - -NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg, const TranslationContext& ctx) { - NativeReceiveBuffer cur{}; - cur.received = leg.received; - cur.lasttime = leg.lasttime; - cur.headwrap = leg.headwrap; - cur.headindex = leg.headindex; - copyArr(cur.buffer, leg.buffer); - return cur; -} - -NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg, const TranslationContext& ctx) { - NativeTransmitBuffer cur{}; - cur.transmitted = leg.transmitted; - cur.headindex = leg.headindex; - cur.tailindex = leg.tailindex; - cur.last_valid_index = leg.last_valid_index; - cur.bufferlen = leg.bufferlen; - copyArr(cur.buffer, leg.buffer); - return cur; -} - -NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg, const TranslationContext& ctx) { - NativeTransmitBufferLocal cur{}; - cur.transmitted = leg.transmitted; - cur.headindex = leg.headindex; - cur.tailindex = leg.tailindex; - cur.last_valid_index = leg.last_valid_index; - cur.bufferlen = leg.bufferlen; - copyArr(cur.buffer, leg.buffer); - return cur; -} - -cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur, const TranslationContext& ctx) { - cbPKT_HEADER leg{}; - leg.time = cur.time; - leg.chid = cur.chid; - leg.type = cur.type; - leg.dlen = cur.dlen; - leg.instrument = cur.instrument; - leg.reserved = cur.reserved; - return leg; -} - -cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur, const TranslationContext& ctx) { - cbPKT_SYSINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.sysfreq = cur.sysfreq; - leg.spikelen = cur.spikelen; - leg.spikepre = cur.spikepre; - leg.resetque = cur.resetque; - leg.runlevel = cur.runlevel; - leg.runflags = cur.runflags; - return leg; -} - -cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur, const TranslationContext& ctx) { - cbPKT_PROCINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.proc = cur.proc; - leg.idcode = cur.idcode; - leg.idcode = cur.idcode; - copyArr(leg.ident, cur.ident); - leg.chanbase = cur.chanbase; - leg.chancount = cur.chancount; - leg.bankcount = cur.bankcount; - leg.groupcount = cur.groupcount; - leg.filtcount = cur.filtcount; - leg.sortcount = cur.sortcount; - leg.unitcount = cur.unitcount; - leg.hoopcount = cur.hoopcount; - leg.reserved = cur.reserved; - leg.version = cur.version; - return leg; -} - -cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur, const TranslationContext& ctx) { - cbPKT_BANKINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.proc = cur.proc; - leg.bank = cur.bank; - leg.idcode = cur.idcode; - copyArr(leg.ident, cur.ident); - copyArr(leg.label, cur.label); - leg.chanbase = cur.chanbase; - leg.chancount = cur.chancount; - return leg; -} - -cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur, const TranslationContext& ctx) { - cbPKT_GROUPINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.proc = cur.proc; - leg.group = cur.group; - copyArr(leg.label, cur.label); - leg.period = cur.period; - leg.length = cur.length; - copyArr(leg.list, cur.list); - return leg; -} - -cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur, const TranslationContext& ctx) { - cbPKT_FILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.proc = cur.proc; - leg.filt = cur.filt; - copyArr(leg.label, cur.label); - leg.hpfreq = cur.hpfreq; - leg.hporder = cur.hporder; - leg.hptype = cur.hptype; - leg.lpfreq = cur.lpfreq; - leg.lporder = cur.lporder; - leg.lptype = cur.lptype; - leg.gain = cur.gain; - leg.sos1a1 = cur.sos1a1; - leg.sos1a2 = cur.sos1a2; - leg.sos1b1 = cur.sos1b1; - leg.sos1b2 = cur.sos1b2; - leg.sos2a1 = cur.sos2a1; - leg.sos2a2 = cur.sos2a2; - leg.sos2b1 = cur.sos2b1; - leg.sos2b2 = cur.sos2b2; - return leg; -} - -cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur, const TranslationContext& ctx) { - cbPKT_ADAPTFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.nMode = cur.nMode; - leg.dLearningRate = cur.dLearningRate; - leg.nRefChan1 = cur.nRefChan1; - leg.nRefChan2 = cur.nRefChan2; - return leg; -} - -cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur, const TranslationContext& ctx) { - cbPKT_REFELECFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.nMode = cur.nMode; - leg.nRefChan = cur.nRefChan; - return leg; -} - -cbSCALING toLegacy(const ::cbSCALING& cur, const TranslationContext& ctx) { - cbSCALING leg{}; - leg.digmin = cur.digmin; - leg.digmax = cur.digmax; - leg.anamin = cur.anamin; - leg.anamax = cur.anamax; - leg.anagain = cur.anagain; - copyArr(leg.anaunit, cur.anaunit); - return leg; -} - -cbFILTDESC toLegacy(const ::cbFILTDESC& cur, const TranslationContext& ctx) { - cbFILTDESC leg{}; - leg.hpfreq = cur.hpfreq; - leg.hporder = cur.hporder; - leg.hptype = cur.hptype; - leg.lpfreq = cur.lpfreq; - leg.lporder = cur.lporder; - leg.lptype = cur.lptype; - return leg; -} - -cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur, const TranslationContext& ctx) { - cbMANUALUNITMAPPING leg{}; - leg.nOverride = cur.nOverride; - copyArr(leg.afOrigin, cur.afOrigin); - copyArr2D(leg.afShape, cur.afShape); - leg.aPhi = cur.aPhi; - leg.bValid = cur.bValid; - return leg; -} - -cbHOOP toLegacy(const ::cbHOOP& cur, const TranslationContext& ctx) { - cbHOOP leg{}; - leg.valid = cur.valid; - leg.time = cur.time; - leg.min = cur.min; - leg.max = cur.max; - return leg; -} - -cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur, const TranslationContext& ctx) { - cbPKT_CHANINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.proc = cur.proc; - leg.bank = cur.bank; - leg.term = cur.term; - leg.chancaps = cur.chancaps; - leg.doutcaps = cur.doutcaps; - leg.dinpcaps = cur.dinpcaps; - leg.aoutcaps = cur.aoutcaps; - leg.ainpcaps = cur.ainpcaps; - leg.spkcaps = cur.spkcaps; - leg.physcalin = toLegacy(cur.physcalin, ctx); - leg.phyfiltin = toLegacy(cur.phyfiltin, ctx); - leg.physcalout = toLegacy(cur.physcalout, ctx); - leg.phyfiltout = toLegacy(cur.phyfiltout, ctx); - copyArr(leg.label, cur.label); - leg.userflags = cur.userflags; - copyArr(leg.position, cur.position); - leg.scalin = toLegacy(cur.scalin, ctx); - leg.scalout = toLegacy(cur.scalout, ctx); - leg.doutopts = cur.doutopts; - leg.dinpopts = cur.dinpopts; - leg.aoutopts = cur.aoutopts; - leg.eopchar = cur.eopchar; - leg.moninst = cur.moninst; // aka lowsamples - leg.monchan = cur.monchan; // aka highsamples - leg.outvalue = cur.outvalue; // aka offset - leg.trigtype = cur.trigtype; - copyArr(leg.reserved, cur.reserved); - leg.triginst = cur.triginst; - leg.trigchan = cur.trigchan; - leg.trigval = cur.trigval; - leg.ainpopts = cur.ainpopts; - leg.lncrate = cur.lncrate; - leg.smpfilter = cur.smpfilter; - leg.smpgroup = cur.smpgroup; - leg.smpdispmin = cur.smpdispmin; - leg.smpdispmax = cur.smpdispmax; - leg.spkfilter = cur.spkfilter; - leg.spkdispmax = cur.spkdispmax; - leg.lncdispmax = cur.lncdispmax; - leg.spkopts = cur.spkopts; - leg.spkthrlevel = cur.spkthrlevel; - leg.spkthrlimit = cur.spkthrlimit; - leg.spkgroup = cur.spkgroup; - leg.amplrejpos = cur.amplrejpos; - leg.amplrejneg = cur.amplrejneg; - leg.refelecchan = cur.refelecchan; - copyArr(leg.unitmapping, cur.unitmapping, toLegacy, ctx); - copyArr2D(leg.spkhoops, cur.spkhoops, toLegacy, ctx); - return leg; -} - -cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur, const TranslationContext& ctx) { - cbPKT_FS_BASIS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.mode = cur.mode; - leg.fs = cur.fs; - copyArr2D(leg.basis, cur.basis); - return leg; -} - -cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur, const TranslationContext& ctx) { - cbPKT_SS_MODELSET leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.unit_number = cur.unit_number; - leg.valid = cur.valid; - leg.inverted = cur.inverted; - leg.num_samples = cur.num_samples; - copyArr(leg.mu_x, cur.mu_x); - copyArr2D(leg.Sigma_x, cur.Sigma_x); - leg.determinant_Sigma_x = cur.determinant_Sigma_x; - copyArr2D(leg.Sigma_x_inv, cur.Sigma_x_inv); - leg.log_determinant_Sigma_x = cur.log_determinant_Sigma_x; - leg.subcluster_spread_factor_numerator = cur.subcluster_spread_factor_numerator; - leg.subcluster_spread_factor_denominator = cur.subcluster_spread_factor_denominator; - leg.mu_e = cur.mu_e; - leg.sigma_e_squared = cur.sigma_e_squared; - return leg; -} - -cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur, const TranslationContext& ctx) { - cbPKT_SS_DETECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.fThreshold = cur.fThreshold; - leg.fMultiplier = cur.fMultiplier; - return leg; -} - -cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur, const TranslationContext& ctx) { - cbPKT_SS_ARTIF_REJECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.nMaxSimulChans = cur.nMaxSimulChans; - leg.nRefractoryCount = cur.nRefractoryCount; - return leg; -} - -cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur, const TranslationContext& ctx) { - cbPKT_SS_NOISE_BOUNDARY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - copyArr(leg.afc, cur.afc); - copyArr2D(leg.afS, cur.afS); - return leg; -} - -cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur, const TranslationContext& ctx) { - cbPKT_SS_STATISTICS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.nUpdateSpikes = cur.nUpdateSpikes; - leg.nAutoalg = cur.nAutoalg; - leg.nMode = cur.nMode; - leg.fMinClusterPairSpreadFactor = cur.fMinClusterPairSpreadFactor; - leg.fMaxSubclusterSpreadFactor = cur.fMaxSubclusterSpreadFactor; - leg.fMinClusterHistCorrMajMeasure = cur.fMinClusterHistCorrMajMeasure; - leg.fMaxClusterPairHistCorrMajMeasure = cur.fMaxClusterPairHistCorrMajMeasure; - leg.fClusterHistValleyPercentage = cur.fClusterHistValleyPercentage; - leg.fClusterHistClosePeakPercentage = cur.fClusterHistClosePeakPercentage; - leg.fClusterHistMinPeakPercentage = cur.fClusterHistMinPeakPercentage; - leg.nWaveBasisSize = cur.nWaveBasisSize; - leg.nWaveSampleSize = cur.nWaveSampleSize; - return leg; -} - -cbAdaptControl toLegacy(const ::cbAdaptControl& cur, const TranslationContext& ctx) { - cbAdaptControl leg{}; - leg.nMode = cur.nMode; - leg.fTimeOutMinutes = cur.fTimeOutMinutes; - leg.fElapsedMinutes = cur.fElapsedMinutes; - return leg; -} - -cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur, const TranslationContext& ctx) { - cbPKT_SS_STATUS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.cntlUnitStats = toLegacy(cur.cntlUnitStats, ctx); - leg.cntlNumUnits = toLegacy(cur.cntlNumUnits, ctx); - return leg; -} - -cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur, const TranslationContext& ctx) { - cbSPIKE_SORTING leg{}; - copyArr(leg.asBasis, cur.basis, toLegacy, ctx); - copyArr2D(leg.asSortModel, cur.models, toLegacy, ctx); - leg.pktDetect = toLegacy(cur.detect, ctx); - leg.pktArtifReject = toLegacy(cur.artifact_reject, ctx); - copyArr(leg.pktNoiseBoundary, cur.noise_boundary, toLegacy, ctx); - leg.pktStatistics = toLegacy(cur.statistics, ctx); - leg.pktStatus = toLegacy(cur.status, ctx); - return leg; -} - -cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur, const TranslationContext& ctx) { - cbPKT_NTRODEINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.ntrode = cur.ntrode; - copyArr(leg.label, cur.label); - copyArr2D(leg.ellipses, cur.ellipses, toLegacy, ctx); - leg.nSite = cur.nSite; - leg.fs = cur.fs; - copyArr(leg.nChan, cur.nChan); - return leg; -} - -cbWaveformData toLegacy(const ::cbWaveformData& cur, const TranslationContext& ctx) { - cbWaveformData leg{}; - leg.offset = cur.offset; // aka sineFrequency - leg.seq = cur.seq; // aka sineAmplitude - leg.seqTotal = cur.seqTotal; - leg.phases = cur.phases; - copyArr(leg.duration, cur.duration); - copyArr(leg.amplitude, cur.amplitude); - return leg; -} - -cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur, const TranslationContext& ctx) { - cbPKT_AOUT_WAVEFORM leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.mode = cur.mode; - leg.repeats = cur.repeats; - leg.trig = cur.trig; - leg.trigInst = cur.trigInst; - leg.trigChan = cur.trigChan; - leg.trigValue = cur.trigValue; - leg.trigNum = cur.trigNum; - leg.active = cur.active; - leg.wave = toLegacy(cur.wave, ctx); - return leg; -} - -cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur, const TranslationContext& ctx) { - cbPKT_LNC leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.lncFreq = cur.lncFreq; - leg.lncRefChan = cur.lncRefChan; - leg.lncGlobalMode = cur.lncGlobalMode; - return leg; -} - -cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur, const TranslationContext& ctx) { - cbPKT_NPLAY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.ftime = cur.ftime; // aka opt - leg.stime = cur.stime; - leg.etime = cur.etime; - leg.val = cur.val; - leg.mode = cur.mode; - leg.flags = cur.flags; - leg.speed = cur.speed; - copyArr(leg.fname, cur.fname); - return leg; -} - -cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur, const TranslationContext& ctx) { - cbVIDEOSOURCE leg{}; - copyArr(leg.name, cur.name); - leg.fps = cur.fps; - return leg; -} - -cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur, const TranslationContext& ctx) { - cbTRACKOBJ leg{}; - copyArr(leg.name, cur.name); - leg.type = cur.type; - leg.pointCount = cur.pointCount; - return leg; -} - -cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur, const TranslationContext& ctx) { - cbPKT_FILECFG leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.options = cur.options; - leg.duration = cur.duration; - leg.recording = cur.recording; - leg.extctrl = cur.extctrl; - copyArr(leg.username, cur.username); - copyArr(leg.filename, cur.filename); // aka datetime - copyArr(leg.comment, cur.comment); - return leg; -} - -NSPStatus toLegacy(const NativeNSPStatus& cur, const TranslationContext& ctx) { - switch(cur) { - case NativeNSPStatus::NSP_INIT: - return NSPStatus::NSP_INIT; - case NativeNSPStatus::NSP_NOIPADDR: - return NSPStatus::NSP_NOIPADDR; - case NativeNSPStatus::NSP_NOREPLY: - return NSPStatus::NSP_NOREPLY; - case NativeNSPStatus::NSP_FOUND: - return NSPStatus::NSP_FOUND; - case NativeNSPStatus::NSP_INVALID: - default: - return NSPStatus::NSP_INVALID; - } -} - -cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur, const TranslationContext& ctx) { - cbPKT_UNIT_SELECTION leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.lastchan = cur.lastchan; - copyArr(leg.abyUnitSelections, cur.abyUnitSelections); - return leg; -} - -cbPcStatus toLegacy(const NativePCStatus& cur, const TranslationContext& ctx) { - cbPcStatus leg{}; - leg.isSelection[ctx.instrument_idx] = toLegacy(cur.isSelection, ctx); - leg.m_iBlockRecording = cur.m_iBlockRecording; - leg.m_nPCStatusFlags = cur.m_nPCStatusFlags; - leg.m_nNumFEChans = cur.m_nNumFEChans; - leg.m_nNumAnainChans = cur.m_nNumAnainChans; - leg.m_nNumAnalogChans = cur.m_nNumAnalogChans; - leg.m_nNumAoutChans = cur.m_nNumAoutChans; - leg.m_nNumAudioChans = cur.m_nNumAudioChans; - leg.m_nNumAnalogoutChans = cur.m_nNumAnalogoutChans; - leg.m_nNumDiginChans = cur.m_nNumDiginChans; - leg.m_nNumSerialChans = cur.m_nNumSerialChans; - leg.m_nNumDigoutChans = cur.m_nNumDigoutChans; - leg.m_nNumTotalChans = cur.m_nNumTotalChans; - leg.m_nNspStatus[ctx.instrument_idx] = toLegacy(cur.m_nNspStatus, ctx); - leg.m_nNumNTrodesPerInstrument[ctx.instrument_idx] = cur.m_nNumNTrodesPerInstrument; - leg.m_nGeminiSystem = cur.m_nGeminiSystem; - // ignore APP_WORKSPACE - return leg; -} - -cbRECBUFF toLegacy(const NativeReceiveBuffer& cur, const TranslationContext& ctx) { - cbRECBUFF leg{}; - leg.received = cur.received; - leg.lasttime = cur.lasttime; - leg.headwrap = cur.headwrap; - leg.headindex = cur.headindex; - copyArr(leg.buffer, cur.buffer); - return leg; -} - -cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur, const TranslationContext& ctx) { - cbXMTBUFF leg{}; - leg.transmitted = cur.transmitted; - leg.headindex = cur.headindex; - leg.tailindex = cur.tailindex; - leg.last_valid_index = cur.last_valid_index; - leg.bufferlen = cur.bufferlen; - copyArr(leg.buffer, cur.buffer); - return leg; -} - -cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur, const TranslationContext& ctx) { - cbXMTBUFFLOCAL leg{}; - leg.transmitted = cur.transmitted; - leg.headindex = cur.headindex; - leg.tailindex = cur.tailindex; - leg.last_valid_index = cur.last_valid_index; - leg.bufferlen = cur.bufferlen; - copyArr(leg.buffer, cur.buffer); - return leg; -} - -} // namespace central_v4_1 - -} // namespace cbshm diff --git a/src/cbshm/src/central_translators/v4_2.cpp b/src/cbshm/src/central_translators/v4_2.cpp deleted file mode 100644 index c6d2b911..00000000 --- a/src/cbshm/src/central_translators/v4_2.cpp +++ /dev/null @@ -1,1007 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file v4_2.cpp -/// @author Caden Shmookler -/// @date 2026-05-22 -/// -/// @brief Central translator implementations -/// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#include "utils.h" -#include -#include - -namespace cbshm { - -namespace central_v4_2 { - -::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg, const TranslationContext& ctx) { - ::cbPKT_HEADER cur{}; - cur.time = leg.time; - cur.chid = leg.chid; - cur.type = leg.type; - cur.dlen = leg.dlen; - cur.instrument = leg.instrument; - cur.reserved = leg.reserved; - return cur; -} - -::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg, const TranslationContext& ctx) { - ::cbPKT_SYSINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.sysfreq = leg.sysfreq; - cur.spikelen = leg.spikelen; - cur.spikepre = leg.spikepre; - cur.resetque = leg.resetque; - cur.runlevel = leg.runlevel; - cur.runflags = leg.runflags; - return cur; -} - -::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg, const TranslationContext& ctx) { - ::cbPKT_PROCINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.proc = leg.proc; - cur.idcode = leg.idcode; - cur.idcode = leg.idcode; - copyArr(cur.ident, leg.ident); - cur.chanbase = leg.chanbase; - cur.chancount = leg.chancount; - cur.bankcount = leg.bankcount; - cur.groupcount = leg.groupcount; - cur.filtcount = leg.filtcount; - cur.sortcount = leg.sortcount; - cur.unitcount = leg.unitcount; - cur.hoopcount = leg.hoopcount; - cur.reserved = leg.reserved; - cur.version = leg.version; - return cur; -} - -::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg, const TranslationContext& ctx) { - ::cbPKT_BANKINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.proc = leg.proc; - cur.bank = leg.bank; - cur.idcode = leg.idcode; - copyArr(cur.ident, leg.ident); - copyArr(cur.label, leg.label); - cur.chanbase = leg.chanbase; - cur.chancount = leg.chancount; - return cur; -} - -::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg, const TranslationContext& ctx) { - ::cbPKT_GROUPINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.proc = leg.proc; - cur.group = leg.group; - copyArr(cur.label, leg.label); - cur.period = leg.period; - cur.length = leg.length; - copyArr(cur.list, leg.list); - return cur; -} - -::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg, const TranslationContext& ctx) { - ::cbPKT_FILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.proc = leg.proc; - cur.filt = leg.filt; - copyArr(cur.label, leg.label); - cur.hpfreq = leg.hpfreq; - cur.hporder = leg.hporder; - cur.hptype = leg.hptype; - cur.lpfreq = leg.lpfreq; - cur.lporder = leg.lporder; - cur.lptype = leg.lptype; - cur.gain = leg.gain; - cur.sos1a1 = leg.sos1a1; - cur.sos1a2 = leg.sos1a2; - cur.sos1b1 = leg.sos1b1; - cur.sos1b2 = leg.sos1b2; - cur.sos2a1 = leg.sos2a1; - cur.sos2a2 = leg.sos2a2; - cur.sos2b1 = leg.sos2b1; - cur.sos2b2 = leg.sos2b2; - return cur; -} - -::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg, const TranslationContext& ctx) { - ::cbPKT_ADAPTFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.nMode = leg.nMode; - cur.dLearningRate = leg.dLearningRate; - cur.nRefChan1 = leg.nRefChan1; - cur.nRefChan2 = leg.nRefChan2; - return cur; -} - -::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg, const TranslationContext& ctx) { - ::cbPKT_REFELECFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.nMode = leg.nMode; - cur.nRefChan = leg.nRefChan; - return cur; -} - -::cbSCALING fromLegacy(const cbSCALING& leg, const TranslationContext& ctx) { - ::cbSCALING cur{}; - cur.digmin = leg.digmin; - cur.digmax = leg.digmax; - cur.anamin = leg.anamin; - cur.anamax = leg.anamax; - cur.anagain = leg.anagain; - copyArr(cur.anaunit, leg.anaunit); - return cur; -} - -::cbFILTDESC fromLegacy(const cbFILTDESC& leg, const TranslationContext& ctx) { - ::cbFILTDESC cur{}; - cur.hpfreq = leg.hpfreq; - cur.hporder = leg.hporder; - cur.hptype = leg.hptype; - cur.lpfreq = leg.lpfreq; - cur.lporder = leg.lporder; - cur.lptype = leg.lptype; - return cur; -} - -::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg, const TranslationContext& ctx) { - ::cbMANUALUNITMAPPING cur{}; - cur.nOverride = leg.nOverride; - copyArr(cur.afOrigin, leg.afOrigin); - copyArr2D(cur.afShape, leg.afShape); - cur.aPhi = leg.aPhi; - cur.bValid = leg.bValid; - return cur; -} - -::cbHOOP fromLegacy(const cbHOOP& leg, const TranslationContext& ctx) { - ::cbHOOP cur{}; - cur.valid = leg.valid; - cur.time = leg.time; - cur.min = leg.min; - cur.max = leg.max; - return cur; -} - -::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg, const TranslationContext& ctx) { - ::cbPKT_CHANINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.proc = leg.proc; - cur.bank = leg.bank; - cur.term = leg.term; - cur.chancaps = leg.chancaps; - cur.doutcaps = leg.doutcaps; - cur.dinpcaps = leg.dinpcaps; - cur.aoutcaps = leg.aoutcaps; - cur.ainpcaps = leg.ainpcaps; - cur.spkcaps = leg.spkcaps; - cur.physcalin = fromLegacy(leg.physcalin, ctx); - cur.phyfiltin = fromLegacy(leg.phyfiltin, ctx); - cur.physcalout = fromLegacy(leg.physcalout, ctx); - cur.phyfiltout = fromLegacy(leg.phyfiltout, ctx); - copyArr(cur.label, leg.label); - cur.userflags = leg.userflags; - copyArr(cur.position, leg.position); - cur.scalin = fromLegacy(leg.scalin, ctx); - cur.scalout = fromLegacy(leg.scalout, ctx); - cur.doutopts = leg.doutopts; - cur.dinpopts = leg.dinpopts; - cur.aoutopts = leg.aoutopts; - cur.eopchar = leg.eopchar; - cur.moninst = leg.moninst; // aka lowsamples - cur.monchan = leg.monchan; // aka highsamples - cur.outvalue = leg.outvalue; // aka offset - cur.trigtype = leg.trigtype; - copyArr(cur.reserved, leg.reserved); - cur.triginst = leg.triginst; - cur.trigchan = leg.trigchan; - cur.trigval = leg.trigval; - cur.ainpopts = leg.ainpopts; - cur.lncrate = leg.lncrate; - cur.smpfilter = leg.smpfilter; - cur.smpgroup = leg.smpgroup; - cur.smpdispmin = leg.smpdispmin; - cur.smpdispmax = leg.smpdispmax; - cur.spkfilter = leg.spkfilter; - cur.spkdispmax = leg.spkdispmax; - cur.lncdispmax = leg.lncdispmax; - cur.spkopts = leg.spkopts; - cur.spkthrlevel = leg.spkthrlevel; - cur.spkthrlimit = leg.spkthrlimit; - cur.spkgroup = leg.spkgroup; - cur.amplrejpos = leg.amplrejpos; - cur.amplrejneg = leg.amplrejneg; - cur.refelecchan = leg.refelecchan; - copyArr(cur.unitmapping, leg.unitmapping, fromLegacy, ctx); - copyArr2D(cur.spkhoops, leg.spkhoops, fromLegacy, ctx); - return cur; -} - -::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg, const TranslationContext& ctx) { - ::cbPKT_FS_BASIS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.mode = leg.mode; - cur.fs = leg.fs; - copyArr2D(cur.basis, leg.basis); - return cur; -} - -::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg, const TranslationContext& ctx) { - ::cbPKT_SS_MODELSET cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.unit_number = leg.unit_number; - cur.valid = leg.valid; - cur.inverted = leg.inverted; - cur.num_samples = leg.num_samples; - copyArr(cur.mu_x, leg.mu_x); - copyArr2D(cur.Sigma_x, leg.Sigma_x); - cur.determinant_Sigma_x = leg.determinant_Sigma_x; - copyArr2D(cur.Sigma_x_inv, leg.Sigma_x_inv); - cur.log_determinant_Sigma_x = leg.log_determinant_Sigma_x; - cur.subcluster_spread_factor_numerator = leg.subcluster_spread_factor_numerator; - cur.subcluster_spread_factor_denominator = leg.subcluster_spread_factor_denominator; - cur.mu_e = leg.mu_e; - cur.sigma_e_squared = leg.sigma_e_squared; - return cur; -} - -::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg, const TranslationContext& ctx) { - ::cbPKT_SS_DETECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.fThreshold = leg.fThreshold; - cur.fMultiplier = leg.fMultiplier; - return cur; -} - -::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg, const TranslationContext& ctx) { - ::cbPKT_SS_ARTIF_REJECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.nMaxSimulChans = leg.nMaxSimulChans; - cur.nRefractoryCount = leg.nRefractoryCount; - return cur; -} - -::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg, const TranslationContext& ctx) { - ::cbPKT_SS_NOISE_BOUNDARY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - copyArr(cur.afc, leg.afc); - copyArr2D(cur.afS, leg.afS); - return cur; -} - -::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg, const TranslationContext& ctx) { - ::cbPKT_SS_STATISTICS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.nUpdateSpikes = leg.nUpdateSpikes; - cur.nAutoalg = leg.nAutoalg; - cur.nMode = leg.nMode; - cur.fMinClusterPairSpreadFactor = leg.fMinClusterPairSpreadFactor; - cur.fMaxSubclusterSpreadFactor = leg.fMaxSubclusterSpreadFactor; - cur.fMinClusterHistCorrMajMeasure = leg.fMinClusterHistCorrMajMeasure; - cur.fMaxClusterPairHistCorrMajMeasure = leg.fMaxClusterPairHistCorrMajMeasure; - cur.fClusterHistValleyPercentage = leg.fClusterHistValleyPercentage; - cur.fClusterHistClosePeakPercentage = leg.fClusterHistClosePeakPercentage; - cur.fClusterHistMinPeakPercentage = leg.fClusterHistMinPeakPercentage; - cur.nWaveBasisSize = leg.nWaveBasisSize; - cur.nWaveSampleSize = leg.nWaveSampleSize; - return cur; -} - -::cbAdaptControl fromLegacy(const cbAdaptControl& leg, const TranslationContext& ctx) { - ::cbAdaptControl cur{}; - cur.nMode = leg.nMode; - cur.fTimeOutMinutes = leg.fTimeOutMinutes; - cur.fElapsedMinutes = leg.fElapsedMinutes; - return cur; -} - -::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg, const TranslationContext& ctx) { - ::cbPKT_SS_STATUS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats, ctx); - cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits, ctx); - return cur; -} - -::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg, const TranslationContext& ctx) { - ::cbproto::SpikeSorting cur{}; - copyArr(cur.basis, leg.asBasis, fromLegacy, ctx); - copyArr2D(cur.models, leg.asSortModel, fromLegacy, ctx); - cur.detect = fromLegacy(leg.pktDetect, ctx); - cur.artifact_reject = fromLegacy(leg.pktArtifReject, ctx); - copyArr(cur.noise_boundary, leg.pktNoiseBoundary, fromLegacy, ctx); - cur.statistics = fromLegacy(leg.pktStatistics, ctx); - cur.status = fromLegacy(leg.pktStatus, ctx); - return cur; -} - -::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg, const TranslationContext& ctx) { - ::cbPKT_NTRODEINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.ntrode = leg.ntrode; - copyArr(cur.label, leg.label); - copyArr2D(cur.ellipses, leg.ellipses, fromLegacy, ctx); - cur.nSite = leg.nSite; - cur.fs = leg.fs; - copyArr(cur.nChan, leg.nChan); - return cur; -} - -::cbWaveformData fromLegacy(const cbWaveformData& leg, const TranslationContext& ctx) { - ::cbWaveformData cur{}; - cur.offset = leg.offset; // aka sineFrequency - cur.seq = leg.seq; // aka sineAmplitude - cur.seqTotal = leg.seqTotal; - cur.phases = leg.phases; - copyArr(cur.duration, leg.duration); - copyArr(cur.amplitude, leg.amplitude); - return cur; -} - -::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg, const TranslationContext& ctx) { - ::cbPKT_AOUT_WAVEFORM cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.chan = leg.chan; - cur.mode = leg.mode; - cur.repeats = leg.repeats; - cur.trig = leg.trig; - cur.trigInst = leg.trigInst; - cur.trigChan = leg.trigChan; - cur.trigValue = leg.trigValue; - cur.trigNum = leg.trigNum; - cur.active = leg.active; - cur.wave = fromLegacy(leg.wave, ctx); - return cur; -} - -::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg, const TranslationContext& ctx) { - ::cbPKT_LNC cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.lncFreq = leg.lncFreq; - cur.lncRefChan = leg.lncRefChan; - cur.lncGlobalMode = leg.lncGlobalMode; - return cur; -} - -::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg, const TranslationContext& ctx) { - ::cbPKT_NPLAY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.ftime = leg.ftime; // aka opt - cur.stime = leg.stime; - cur.etime = leg.etime; - cur.val = leg.val; - cur.mode = leg.mode; - cur.flags = leg.flags; - cur.speed = leg.speed; - copyArr(cur.fname, leg.fname); - return cur; -} - -::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg, const TranslationContext& ctx) { - ::cbVIDEOSOURCE cur{}; - copyArr(cur.name, leg.name); - cur.fps = leg.fps; - return cur; -} - -::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg, const TranslationContext& ctx) { - ::cbTRACKOBJ cur{}; - copyArr(cur.name, leg.name); - cur.type = leg.type; - cur.pointCount = leg.pointCount; - return cur; -} - -::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg, const TranslationContext& ctx) { - ::cbPKT_FILECFG cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.options = leg.options; - cur.duration = leg.duration; - cur.recording = leg.recording; - cur.extctrl = leg.extctrl; - copyArr(cur.username, leg.username); - copyArr(cur.filename, leg.filename); // aka datetime - copyArr(cur.comment, leg.comment); - return cur; -} - -NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg, const TranslationContext& ctx) { - // TODO: VERIFY that each list that's assumed to be instrument-independent is in fact independent from any particular instrument. - NativeConfigBuffer cur{}; - cur.version = leg.version; - cur.sysflags = leg.sysflags; - cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); - cur.sysinfo = fromLegacy(leg.sysinfo, ctx); - cur.procinfo = fromLegacy(leg.procinfo[ctx.instrument_idx], ctx); - copyArr(cur.bankinfo, leg.bankinfo[ctx.instrument_idx], fromLegacy, ctx); - copyArr(cur.groupinfo, leg.groupinfo[ctx.instrument_idx], fromLegacy, ctx); - copyArr(cur.filtinfo, leg.filtinfo[ctx.instrument_idx], fromLegacy, ctx); - cur.adaptinfo = fromLegacy(leg.adaptinfo[ctx.instrument_idx], ctx); - cur.refelecinfo = fromLegacy(leg.refelecinfo[ctx.instrument_idx], ctx); - copyArr(cur.chaninfo, leg.chaninfo, fromLegacy, ctx); - copyArr(cur.asBasis, leg.isSortingOptions.asBasis, fromLegacy, ctx); - copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, fromLegacy, ctx); - // TODO: Move native isSortingOptions fields into a struct - cur.pktDetect = fromLegacy(leg.isSortingOptions.pktDetect, ctx); - cur.pktArtifReject = fromLegacy(leg.isSortingOptions.pktArtifReject, ctx); - copyArr(cur.pktNoiseBoundary, leg.isSortingOptions.pktNoiseBoundary, fromLegacy, ctx); - cur.pktStatistics = fromLegacy(leg.isSortingOptions.pktStatistics, ctx); - cur.pktStatus = fromLegacy(leg.isSortingOptions.pktStatus, ctx); - copyArr(cur.isNTrodeInfo, leg.isNTrodeInfo, fromLegacy, ctx); - copyArr2D(cur.isWaveform, leg.isWaveform, fromLegacy, ctx); - cur.isLnc = fromLegacy(leg.isLnc[ctx.instrument_idx], ctx); - cur.isNPlay = fromLegacy(leg.isNPlay, ctx); - copyArr(cur.isVideoSource, leg.isVideoSource, fromLegacy, ctx); - copyArr(cur.isTrackObj, leg.isTrackObj, fromLegacy, ctx); - cur.fileinfo = fromLegacy(leg.fileinfo, ctx); - - return cur; -} - -NativeNSPStatus fromLegacy(const NSPStatus& leg, const TranslationContext& ctx) { - switch(leg) { - case NSPStatus::NSP_INIT: - return NativeNSPStatus::NSP_INIT; - case NSPStatus::NSP_NOIPADDR: - return NativeNSPStatus::NSP_NOIPADDR; - case NSPStatus::NSP_NOREPLY: - return NativeNSPStatus::NSP_NOREPLY; - case NSPStatus::NSP_FOUND: - return NativeNSPStatus::NSP_FOUND; - case NSPStatus::NSP_INVALID: - default: - return NativeNSPStatus::NSP_INVALID; - } -} - -::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg, const TranslationContext& ctx) { - ::cbPKT_UNIT_SELECTION cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header, ctx); - cur.lastchan = leg.lastchan; - copyArr(cur.abyUnitSelections, leg.abyUnitSelections); - return cur; -} - -NativePCStatus fromLegacy(const cbPcStatus& leg, const TranslationContext& ctx) { - NativePCStatus cur{}; - cur.isSelection = fromLegacy(leg.isSelection[ctx.instrument_idx], ctx); - cur.m_iBlockRecording = leg.m_iBlockRecording; - cur.m_nPCStatusFlags = leg.m_nPCStatusFlags; - cur.m_nNumFEChans = leg.m_nNumFEChans; - cur.m_nNumAnainChans = leg.m_nNumAnainChans; - cur.m_nNumAnalogChans = leg.m_nNumAnalogChans; - cur.m_nNumAoutChans = leg.m_nNumAoutChans; - cur.m_nNumAudioChans = leg.m_nNumAudioChans; - cur.m_nNumAnalogoutChans = leg.m_nNumAnalogoutChans; - cur.m_nNumDiginChans = leg.m_nNumDiginChans; - cur.m_nNumSerialChans = leg.m_nNumSerialChans; - cur.m_nNumDigoutChans = leg.m_nNumDigoutChans; - cur.m_nNumTotalChans = leg.m_nNumTotalChans; - cur.m_nNspStatus = fromLegacy(leg.m_nNspStatus[ctx.instrument_idx], ctx); - cur.m_nNumNTrodesPerInstrument = leg.m_nNumNTrodesPerInstrument[ctx.instrument_idx]; - cur.m_nGeminiSystem = leg.m_nGeminiSystem; - // ignore APP_WORKSPACE - return cur; -} - -NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg, const TranslationContext& ctx) { - NativeReceiveBuffer cur{}; - cur.received = leg.received; - cur.lasttime = leg.lasttime; - cur.headwrap = leg.headwrap; - cur.headindex = leg.headindex; - copyArr(cur.buffer, leg.buffer); - return cur; -} - -NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg, const TranslationContext& ctx) { - NativeTransmitBuffer cur{}; - cur.transmitted = leg.transmitted; - cur.headindex = leg.headindex; - cur.tailindex = leg.tailindex; - cur.last_valid_index = leg.last_valid_index; - cur.bufferlen = leg.bufferlen; - copyArr(cur.buffer, leg.buffer); - return cur; -} - -NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg, const TranslationContext& ctx) { - NativeTransmitBufferLocal cur{}; - cur.transmitted = leg.transmitted; - cur.headindex = leg.headindex; - cur.tailindex = leg.tailindex; - cur.last_valid_index = leg.last_valid_index; - cur.bufferlen = leg.bufferlen; - copyArr(cur.buffer, leg.buffer); - return cur; -} - -cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur, const TranslationContext& ctx) { - cbPKT_HEADER leg{}; - leg.time = cur.time; - leg.chid = cur.chid; - leg.type = cur.type; - leg.dlen = cur.dlen; - leg.instrument = cur.instrument; - leg.reserved = cur.reserved; - return leg; -} - -cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur, const TranslationContext& ctx) { - cbPKT_SYSINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.sysfreq = cur.sysfreq; - leg.spikelen = cur.spikelen; - leg.spikepre = cur.spikepre; - leg.resetque = cur.resetque; - leg.runlevel = cur.runlevel; - leg.runflags = cur.runflags; - return leg; -} - -cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur, const TranslationContext& ctx) { - cbPKT_PROCINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.proc = cur.proc; - leg.idcode = cur.idcode; - leg.idcode = cur.idcode; - copyArr(leg.ident, cur.ident); - leg.chanbase = cur.chanbase; - leg.chancount = cur.chancount; - leg.bankcount = cur.bankcount; - leg.groupcount = cur.groupcount; - leg.filtcount = cur.filtcount; - leg.sortcount = cur.sortcount; - leg.unitcount = cur.unitcount; - leg.hoopcount = cur.hoopcount; - leg.reserved = cur.reserved; - leg.version = cur.version; - return leg; -} - -cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur, const TranslationContext& ctx) { - cbPKT_BANKINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.proc = cur.proc; - leg.bank = cur.bank; - leg.idcode = cur.idcode; - copyArr(leg.ident, cur.ident); - copyArr(leg.label, cur.label); - leg.chanbase = cur.chanbase; - leg.chancount = cur.chancount; - return leg; -} - -cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur, const TranslationContext& ctx) { - cbPKT_GROUPINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.proc = cur.proc; - leg.group = cur.group; - copyArr(leg.label, cur.label); - leg.period = cur.period; - leg.length = cur.length; - copyArr(leg.list, cur.list); - return leg; -} - -cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur, const TranslationContext& ctx) { - cbPKT_FILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.proc = cur.proc; - leg.filt = cur.filt; - copyArr(leg.label, cur.label); - leg.hpfreq = cur.hpfreq; - leg.hporder = cur.hporder; - leg.hptype = cur.hptype; - leg.lpfreq = cur.lpfreq; - leg.lporder = cur.lporder; - leg.lptype = cur.lptype; - leg.gain = cur.gain; - leg.sos1a1 = cur.sos1a1; - leg.sos1a2 = cur.sos1a2; - leg.sos1b1 = cur.sos1b1; - leg.sos1b2 = cur.sos1b2; - leg.sos2a1 = cur.sos2a1; - leg.sos2a2 = cur.sos2a2; - leg.sos2b1 = cur.sos2b1; - leg.sos2b2 = cur.sos2b2; - return leg; -} - -cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur, const TranslationContext& ctx) { - cbPKT_ADAPTFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.nMode = cur.nMode; - leg.dLearningRate = cur.dLearningRate; - leg.nRefChan1 = cur.nRefChan1; - leg.nRefChan2 = cur.nRefChan2; - return leg; -} - -cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur, const TranslationContext& ctx) { - cbPKT_REFELECFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.nMode = cur.nMode; - leg.nRefChan = cur.nRefChan; - return leg; -} - -cbSCALING toLegacy(const ::cbSCALING& cur, const TranslationContext& ctx) { - cbSCALING leg{}; - leg.digmin = cur.digmin; - leg.digmax = cur.digmax; - leg.anamin = cur.anamin; - leg.anamax = cur.anamax; - leg.anagain = cur.anagain; - copyArr(leg.anaunit, cur.anaunit); - return leg; -} - -cbFILTDESC toLegacy(const ::cbFILTDESC& cur, const TranslationContext& ctx) { - cbFILTDESC leg{}; - leg.hpfreq = cur.hpfreq; - leg.hporder = cur.hporder; - leg.hptype = cur.hptype; - leg.lpfreq = cur.lpfreq; - leg.lporder = cur.lporder; - leg.lptype = cur.lptype; - return leg; -} - -cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur, const TranslationContext& ctx) { - cbMANUALUNITMAPPING leg{}; - leg.nOverride = cur.nOverride; - copyArr(leg.afOrigin, cur.afOrigin); - copyArr2D(leg.afShape, cur.afShape); - leg.aPhi = cur.aPhi; - leg.bValid = cur.bValid; - return leg; -} - -cbHOOP toLegacy(const ::cbHOOP& cur, const TranslationContext& ctx) { - cbHOOP leg{}; - leg.valid = cur.valid; - leg.time = cur.time; - leg.min = cur.min; - leg.max = cur.max; - return leg; -} - -cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur, const TranslationContext& ctx) { - cbPKT_CHANINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.proc = cur.proc; - leg.bank = cur.bank; - leg.term = cur.term; - leg.chancaps = cur.chancaps; - leg.doutcaps = cur.doutcaps; - leg.dinpcaps = cur.dinpcaps; - leg.aoutcaps = cur.aoutcaps; - leg.ainpcaps = cur.ainpcaps; - leg.spkcaps = cur.spkcaps; - leg.physcalin = toLegacy(cur.physcalin, ctx); - leg.phyfiltin = toLegacy(cur.phyfiltin, ctx); - leg.physcalout = toLegacy(cur.physcalout, ctx); - leg.phyfiltout = toLegacy(cur.phyfiltout, ctx); - copyArr(leg.label, cur.label); - leg.userflags = cur.userflags; - copyArr(leg.position, cur.position); - leg.scalin = toLegacy(cur.scalin, ctx); - leg.scalout = toLegacy(cur.scalout, ctx); - leg.doutopts = cur.doutopts; - leg.dinpopts = cur.dinpopts; - leg.aoutopts = cur.aoutopts; - leg.eopchar = cur.eopchar; - leg.moninst = cur.moninst; // aka lowsamples - leg.monchan = cur.monchan; // aka highsamples - leg.outvalue = cur.outvalue; // aka offset - leg.trigtype = cur.trigtype; - copyArr(leg.reserved, cur.reserved); - leg.triginst = cur.triginst; - leg.trigchan = cur.trigchan; - leg.trigval = cur.trigval; - leg.ainpopts = cur.ainpopts; - leg.lncrate = cur.lncrate; - leg.smpfilter = cur.smpfilter; - leg.smpgroup = cur.smpgroup; - leg.smpdispmin = cur.smpdispmin; - leg.smpdispmax = cur.smpdispmax; - leg.spkfilter = cur.spkfilter; - leg.spkdispmax = cur.spkdispmax; - leg.lncdispmax = cur.lncdispmax; - leg.spkopts = cur.spkopts; - leg.spkthrlevel = cur.spkthrlevel; - leg.spkthrlimit = cur.spkthrlimit; - leg.spkgroup = cur.spkgroup; - leg.amplrejpos = cur.amplrejpos; - leg.amplrejneg = cur.amplrejneg; - leg.refelecchan = cur.refelecchan; - copyArr(leg.unitmapping, cur.unitmapping, toLegacy, ctx); - copyArr2D(leg.spkhoops, cur.spkhoops, toLegacy, ctx); - return leg; -} - -cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur, const TranslationContext& ctx) { - cbPKT_FS_BASIS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.mode = cur.mode; - leg.fs = cur.fs; - copyArr2D(leg.basis, cur.basis); - return leg; -} - -cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur, const TranslationContext& ctx) { - cbPKT_SS_MODELSET leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.unit_number = cur.unit_number; - leg.valid = cur.valid; - leg.inverted = cur.inverted; - leg.num_samples = cur.num_samples; - copyArr(leg.mu_x, cur.mu_x); - copyArr2D(leg.Sigma_x, cur.Sigma_x); - leg.determinant_Sigma_x = cur.determinant_Sigma_x; - copyArr2D(leg.Sigma_x_inv, cur.Sigma_x_inv); - leg.log_determinant_Sigma_x = cur.log_determinant_Sigma_x; - leg.subcluster_spread_factor_numerator = cur.subcluster_spread_factor_numerator; - leg.subcluster_spread_factor_denominator = cur.subcluster_spread_factor_denominator; - leg.mu_e = cur.mu_e; - leg.sigma_e_squared = cur.sigma_e_squared; - return leg; -} - -cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur, const TranslationContext& ctx) { - cbPKT_SS_DETECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.fThreshold = cur.fThreshold; - leg.fMultiplier = cur.fMultiplier; - return leg; -} - -cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur, const TranslationContext& ctx) { - cbPKT_SS_ARTIF_REJECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.nMaxSimulChans = cur.nMaxSimulChans; - leg.nRefractoryCount = cur.nRefractoryCount; - return leg; -} - -cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur, const TranslationContext& ctx) { - cbPKT_SS_NOISE_BOUNDARY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - copyArr(leg.afc, cur.afc); - copyArr2D(leg.afS, cur.afS); - return leg; -} - -cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur, const TranslationContext& ctx) { - cbPKT_SS_STATISTICS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.nUpdateSpikes = cur.nUpdateSpikes; - leg.nAutoalg = cur.nAutoalg; - leg.nMode = cur.nMode; - leg.fMinClusterPairSpreadFactor = cur.fMinClusterPairSpreadFactor; - leg.fMaxSubclusterSpreadFactor = cur.fMaxSubclusterSpreadFactor; - leg.fMinClusterHistCorrMajMeasure = cur.fMinClusterHistCorrMajMeasure; - leg.fMaxClusterPairHistCorrMajMeasure = cur.fMaxClusterPairHistCorrMajMeasure; - leg.fClusterHistValleyPercentage = cur.fClusterHistValleyPercentage; - leg.fClusterHistClosePeakPercentage = cur.fClusterHistClosePeakPercentage; - leg.fClusterHistMinPeakPercentage = cur.fClusterHistMinPeakPercentage; - leg.nWaveBasisSize = cur.nWaveBasisSize; - leg.nWaveSampleSize = cur.nWaveSampleSize; - return leg; -} - -cbAdaptControl toLegacy(const ::cbAdaptControl& cur, const TranslationContext& ctx) { - cbAdaptControl leg{}; - leg.nMode = cur.nMode; - leg.fTimeOutMinutes = cur.fTimeOutMinutes; - leg.fElapsedMinutes = cur.fElapsedMinutes; - return leg; -} - -cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur, const TranslationContext& ctx) { - cbPKT_SS_STATUS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.cntlUnitStats = toLegacy(cur.cntlUnitStats, ctx); - leg.cntlNumUnits = toLegacy(cur.cntlNumUnits, ctx); - return leg; -} - -cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur, const TranslationContext& ctx) { - cbSPIKE_SORTING leg{}; - copyArr(leg.asBasis, cur.basis, toLegacy, ctx); - copyArr2D(leg.asSortModel, cur.models, toLegacy, ctx); - leg.pktDetect = toLegacy(cur.detect, ctx); - leg.pktArtifReject = toLegacy(cur.artifact_reject, ctx); - copyArr(leg.pktNoiseBoundary, cur.noise_boundary, toLegacy, ctx); - leg.pktStatistics = toLegacy(cur.statistics, ctx); - leg.pktStatus = toLegacy(cur.status, ctx); - return leg; -} - -cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur, const TranslationContext& ctx) { - cbPKT_NTRODEINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.ntrode = cur.ntrode; - copyArr(leg.label, cur.label); - copyArr2D(leg.ellipses, cur.ellipses, toLegacy, ctx); - leg.nSite = cur.nSite; - leg.fs = cur.fs; - copyArr(leg.nChan, cur.nChan); - return leg; -} - -cbWaveformData toLegacy(const ::cbWaveformData& cur, const TranslationContext& ctx) { - cbWaveformData leg{}; - leg.offset = cur.offset; // aka sineFrequency - leg.seq = cur.seq; // aka sineAmplitude - leg.seqTotal = cur.seqTotal; - leg.phases = cur.phases; - copyArr(leg.duration, cur.duration); - copyArr(leg.amplitude, cur.amplitude); - return leg; -} - -cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur, const TranslationContext& ctx) { - cbPKT_AOUT_WAVEFORM leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.chan = cur.chan; - leg.mode = cur.mode; - leg.repeats = cur.repeats; - leg.trig = cur.trig; - leg.trigInst = cur.trigInst; - leg.trigChan = cur.trigChan; - leg.trigValue = cur.trigValue; - leg.trigNum = cur.trigNum; - leg.active = cur.active; - leg.wave = toLegacy(cur.wave, ctx); - return leg; -} - -cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur, const TranslationContext& ctx) { - cbPKT_LNC leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.lncFreq = cur.lncFreq; - leg.lncRefChan = cur.lncRefChan; - leg.lncGlobalMode = cur.lncGlobalMode; - return leg; -} - -cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur, const TranslationContext& ctx) { - cbPKT_NPLAY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.ftime = cur.ftime; // aka opt - leg.stime = cur.stime; - leg.etime = cur.etime; - leg.val = cur.val; - leg.mode = cur.mode; - leg.flags = cur.flags; - leg.speed = cur.speed; - copyArr(leg.fname, cur.fname); - return leg; -} - -cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur, const TranslationContext& ctx) { - cbVIDEOSOURCE leg{}; - copyArr(leg.name, cur.name); - leg.fps = cur.fps; - return leg; -} - -cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur, const TranslationContext& ctx) { - cbTRACKOBJ leg{}; - copyArr(leg.name, cur.name); - leg.type = cur.type; - leg.pointCount = cur.pointCount; - return leg; -} - -cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur, const TranslationContext& ctx) { - cbPKT_FILECFG leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.options = cur.options; - leg.duration = cur.duration; - leg.recording = cur.recording; - leg.extctrl = cur.extctrl; - copyArr(leg.username, cur.username); - copyArr(leg.filename, cur.filename); // aka datetime - copyArr(leg.comment, cur.comment); - return leg; -} - -NSPStatus toLegacy(const NativeNSPStatus& cur, const TranslationContext& ctx) { - switch(cur) { - case NativeNSPStatus::NSP_INIT: - return NSPStatus::NSP_INIT; - case NativeNSPStatus::NSP_NOIPADDR: - return NSPStatus::NSP_NOIPADDR; - case NativeNSPStatus::NSP_NOREPLY: - return NSPStatus::NSP_NOREPLY; - case NativeNSPStatus::NSP_FOUND: - return NSPStatus::NSP_FOUND; - case NativeNSPStatus::NSP_INVALID: - default: - return NSPStatus::NSP_INVALID; - } -} - -cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur, const TranslationContext& ctx) { - cbPKT_UNIT_SELECTION leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header, ctx); - leg.lastchan = cur.lastchan; - copyArr(leg.abyUnitSelections, cur.abyUnitSelections); - return leg; -} - -cbPcStatus toLegacy(const NativePCStatus& cur, const TranslationContext& ctx) { - cbPcStatus leg{}; - leg.isSelection[ctx.instrument_idx] = toLegacy(cur.isSelection, ctx); - leg.m_iBlockRecording = cur.m_iBlockRecording; - leg.m_nPCStatusFlags = cur.m_nPCStatusFlags; - leg.m_nNumFEChans = cur.m_nNumFEChans; - leg.m_nNumAnainChans = cur.m_nNumAnainChans; - leg.m_nNumAnalogChans = cur.m_nNumAnalogChans; - leg.m_nNumAoutChans = cur.m_nNumAoutChans; - leg.m_nNumAudioChans = cur.m_nNumAudioChans; - leg.m_nNumAnalogoutChans = cur.m_nNumAnalogoutChans; - leg.m_nNumDiginChans = cur.m_nNumDiginChans; - leg.m_nNumSerialChans = cur.m_nNumSerialChans; - leg.m_nNumDigoutChans = cur.m_nNumDigoutChans; - leg.m_nNumTotalChans = cur.m_nNumTotalChans; - leg.m_nNspStatus[ctx.instrument_idx] = toLegacy(cur.m_nNspStatus, ctx); - leg.m_nNumNTrodesPerInstrument[ctx.instrument_idx] = cur.m_nNumNTrodesPerInstrument; - leg.m_nGeminiSystem = cur.m_nGeminiSystem; - // ignore APP_WORKSPACE - return leg; -} - -cbRECBUFF toLegacy(const NativeReceiveBuffer& cur, const TranslationContext& ctx) { - cbRECBUFF leg{}; - leg.received = cur.received; - leg.lasttime = cur.lasttime; - leg.headwrap = cur.headwrap; - leg.headindex = cur.headindex; - copyArr(leg.buffer, cur.buffer); - return leg; -} - -cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur, const TranslationContext& ctx) { - cbXMTBUFF leg{}; - leg.transmitted = cur.transmitted; - leg.headindex = cur.headindex; - leg.tailindex = cur.tailindex; - leg.last_valid_index = cur.last_valid_index; - leg.bufferlen = cur.bufferlen; - copyArr(leg.buffer, cur.buffer); - return leg; -} - -cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur, const TranslationContext& ctx) { - cbXMTBUFFLOCAL leg{}; - leg.transmitted = cur.transmitted; - leg.headindex = cur.headindex; - leg.tailindex = cur.tailindex; - leg.last_valid_index = cur.last_valid_index; - leg.bufferlen = cur.bufferlen; - copyArr(leg.buffer, cur.buffer); - return leg; -} - -} // namespace central_v4_2 - -} // namespace cbshm diff --git a/src/cbshm/src/shmem_session.cpp b/src/cbshm/src/shmem_session.cpp index baa24176..3e8e177c 100644 --- a/src/cbshm/src/shmem_session.cpp +++ b/src/cbshm/src/shmem_session.cpp @@ -34,7 +34,6 @@ #include #include -#include // TODO: Remove; should be hidden within the adapter #include #include #include @@ -99,6 +98,7 @@ inline uint32_t shm_load_relaxed_u32(const uint32_t* p) { /// @brief Platform-specific implementation details (Pimpl idiom) /// struct ShmemSession::Impl { + cbproto::InstrumentId inst; Mode mode; ShmemLayout layout; std::unique_ptr bootstrap_adapter; @@ -154,10 +154,7 @@ struct ShmemSession::Impl { uint32_t rec_tailindex; // Our read position in receive buffer uint32_t rec_tailwrap; // Our wrap counter - // Instrument filter for CENTRAL_COMPAT mode (-1 = no filter) - int32_t instrument_filter; - - // Detected protocol version for CENTRAL_COMPAT mode + // Detected protocol version for CENTRAL mode cbproto_protocol_version_t compat_protocol; // Typed accessor for config buffer @@ -166,7 +163,8 @@ struct ShmemSession::Impl { } Impl() - : mode(Mode::STANDALONE) + : inst(cbproto::InstrumentId::fromIndex(0)) + , mode(Mode::STANDALONE) , layout(ShmemLayout::NATIVE) , adapter(nullptr) , is_open(false) @@ -202,7 +200,6 @@ struct ShmemSession::Impl { , rec_buffer_len(0) , rec_tailindex(0) , rec_tailwrap(0) - , instrument_filter(-1) , compat_protocol(CBPROTO_PROTOCOL_CURRENT) {} @@ -340,6 +337,10 @@ struct ShmemSession::Impl { return Result::error("Session already open"); } + if (!inst.isValid()) { + return Result::error("Invalid instrument ID"); + } + if (mode == Mode::CLIENT && layout == ShmemLayout::CENTRAL) { // Detect protocol version for CLIENT + CENTRAL mode auto compat_result = detectCompatProtocol(); @@ -519,16 +520,16 @@ struct ShmemSession::Impl { default: /* fallthrough */ case CBPROTO_PROTOCOL_CURRENT: - adapter = std::make_unique(cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); + adapter = std::make_unique(inst.toIndex(), cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); break; case CBPROTO_PROTOCOL_410: - adapter = std::make_unique(cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); + adapter = std::make_unique(inst.toIndex(), cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); break; case CBPROTO_PROTOCOL_400: - adapter = std::make_unique(cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); + adapter = std::make_unique(inst.toIndex(), cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); break; case CBPROTO_PROTOCOL_311: - adapter = std::make_unique(cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); + adapter = std::make_unique(inst.toIndex(), cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); break; } @@ -678,7 +679,7 @@ struct ShmemSession::Impl { return Result::ok(); } - /// @brief Detect the protocol version from Central's binary (CENTRAL_COMPAT only). + /// @brief Detect the protocol version from Central's binary (CENTRAL only). Result detectCompatProtocol() { #ifdef _WIN32 // The 'version' field in Central's shared memory configuration buffer @@ -847,12 +848,13 @@ ShmemSession::~ShmemSession() = default; ShmemSession::ShmemSession(ShmemSession&& other) noexcept = default; ShmemSession& ShmemSession::operator=(ShmemSession&& other) noexcept = default; -Result ShmemSession::create(const std::string& cfg_name, const std::string& rec_name, +Result ShmemSession::create(cbproto::InstrumentId id, const std::string& cfg_name, const std::string& rec_name, const std::string& xmt_name, const std::string& xmt_local_name, const std::string& status_name, const std::string& spk_name, const std::string& signal_event_name, Mode mode, ShmemLayout layout) { ShmemSession session; + session.m_impl->inst = id; session.m_impl->cfg_name = cfg_name; session.m_impl->rec_name = rec_name; session.m_impl->xmt_name = xmt_name; @@ -883,23 +885,27 @@ ShmemLayout ShmemSession::getLayout() const { return m_impl->layout; } +uint32_t ShmemSession::getMaxProcs() const { + if (m_impl->layout == ShmemLayout::NATIVE) { + return cbMAXPROCS; + } else { + return m_impl->adapter->getMaxProcs(); + } +} + +cbproto_protocol_version_t ShmemSession::getCompatProtocolVersion() const { + return m_impl->compat_protocol; +} + /////////////////////////////////////////////////////////////////////////////////////////////////// // Instrument Status Management -Result ShmemSession::isInstrumentActive(cbproto::InstrumentId id) const { +Result ShmemSession::isInstrumentActive() const { if (!isOpen()) { return Result::error("Session not open"); } - if (!id.isValid()) { - return Result::error("Invalid instrument ID"); - } - - uint8_t idx = id.toIndex(); if (m_impl->layout == ShmemLayout::NATIVE) { - if (idx != 0) { - return Result::error("Native mode: single instrument only (index 0)"); - } bool active = (m_impl->nativeCfg()->instrument_status == static_cast(InstrumentStatus::ACTIVE)); return Result::ok(active); } else { @@ -909,112 +915,64 @@ Result ShmemSession::isInstrumentActive(cbproto::InstrumentId id) const { } } -Result ShmemSession::setInstrumentActive(cbproto::InstrumentId id, bool active) { +Result ShmemSession::setInstrumentActive(bool active) { if (!isOpen()) { return Result::error("Session not open"); } - if (!id.isValid()) { - return Result::error("Invalid instrument ID"); - } - uint8_t idx = id.toIndex(); uint32_t val = active ? static_cast(InstrumentStatus::ACTIVE) : static_cast(InstrumentStatus::INACTIVE); if (m_impl->layout == ShmemLayout::NATIVE) { - if (idx != 0) { - return Result::error("Native mode: single instrument only (index 0)"); - } m_impl->nativeCfg()->instrument_status = val; } else { - return Result::error("CENTRAL_COMPAT mode: instrument status is read-only (no instrument_status field in Central's layout)"); + return Result::error("CENTRAL mode: instrument status is read-only (no instrument_status field in Central's layout)"); } return Result::ok(); } -Result ShmemSession::getFirstActiveInstrument() const { - if (!isOpen()) { - return Result::error("Session not open"); - } - - if (m_impl->layout == ShmemLayout::NATIVE) { - if (m_impl->nativeCfg()->instrument_status == static_cast(InstrumentStatus::ACTIVE)) { - return Result::ok(cbproto::InstrumentId::fromIndex(0)); - } - } else { - // No instrument_status in legacy layout; return first instrument (always "active") - return Result::ok(cbproto::InstrumentId::fromIndex(0)); - } - - return Result::error("No active instruments"); -} - /////////////////////////////////////////////////////////////////////////////////////////////////// // Configuration Read Operations -Result ShmemSession::getProcInfo(cbproto::InstrumentId id) const { +Result ShmemSession::getProcInfo() const { if (!isOpen()) { return Result::error("Session not open"); } - if (!id.isValid()) { - return Result::error("Invalid instrument ID"); - } - - uint8_t idx = id.toIndex(); if (m_impl->layout == ShmemLayout::NATIVE) { - if (idx != 0) { - return Result::error("Native mode: single instrument only"); - } return Result::ok(m_impl->nativeCfg()->procinfo); } else { - return m_impl->adapter->getProcInfo(idx); + return m_impl->adapter->getProcInfo(); } } -Result ShmemSession::getBankInfo(cbproto::InstrumentId id, uint32_t bank) const { +Result ShmemSession::getBankInfo(uint32_t bank) const { if (!isOpen()) { return Result::error("Session not open"); } - if (!id.isValid()) { - return Result::error("Invalid instrument ID"); - } - - uint8_t idx = id.toIndex(); if (m_impl->layout == ShmemLayout::NATIVE) { - if (idx != 0) { - return Result::error("Native mode: single instrument only"); - } if (bank == 0 || bank > NATIVE_MAXBANKS) { return Result::error("Bank number out of range"); } return Result::ok(m_impl->nativeCfg()->bankinfo[bank - 1]); } else { - return m_impl->adapter->getBankInfo(idx, bank); + return m_impl->adapter->getBankInfo(bank); } } -Result ShmemSession::getFilterInfo(cbproto::InstrumentId id, uint32_t filter) const { +Result ShmemSession::getFilterInfo(uint32_t filter) const { if (!isOpen()) { return Result::error("Session not open"); } - if (!id.isValid()) { - return Result::error("Invalid instrument ID"); - } - - uint8_t idx = id.toIndex(); if (m_impl->layout == ShmemLayout::NATIVE) { - if (idx != 0) { - return Result::error("Native mode: single instrument only"); - } if (filter == 0 || filter > NATIVE_MAXFILTS) { return Result::error("Filter number out of range"); } return Result::ok(m_impl->nativeCfg()->filtinfo[filter - 1]); } else { - return m_impl->adapter->getFilterInfo(idx, filter); + return m_impl->adapter->getFilterInfo(filter); } } @@ -1045,26 +1003,18 @@ Result ShmemSession::getSysInfo() const { } } -Result ShmemSession::getGroupInfo(cbproto::InstrumentId id, uint32_t group) const { +Result ShmemSession::getGroupInfo(uint32_t group) const { if (!isOpen()) { return Result::error("Session not open"); } - if (!id.isValid()) { - return Result::error("Invalid instrument ID"); - } - - uint8_t idx = id.toIndex(); if (m_impl->layout == ShmemLayout::NATIVE) { - if (idx != 0) { - return Result::error("Native mode: single instrument only"); - } if (group >= NATIVE_MAXGROUPS) { return Result::error("Group index out of range"); } return Result::ok(m_impl->nativeCfg()->groupinfo[group]); } else { - return m_impl->adapter->getGroupInfo(idx, group); + return m_impl->adapter->getGroupInfo(group); } } @@ -1072,72 +1022,48 @@ Result ShmemSession::getGroupInfo(cbproto::InstrumentId id, uin /////////////////////////////////////////////////////////////////////////////////////////////////// // Configuration Write Operations -Result ShmemSession::setProcInfo(cbproto::InstrumentId id, const cbPKT_PROCINFO& info) { +Result ShmemSession::setProcInfo(const cbPKT_PROCINFO& info) { if (!isOpen()) { return Result::error("Session not open"); } - if (!id.isValid()) { - return Result::error("Invalid instrument ID"); - } - - uint8_t idx = id.toIndex(); if (m_impl->layout == ShmemLayout::NATIVE) { - if (idx != 0) { - return Result::error("Native mode: single instrument only"); - } m_impl->nativeCfg()->procinfo = info; return Result::ok(); } else { - return m_impl->adapter->setProcInfo(idx, info); + return m_impl->adapter->setProcInfo(info); } } -Result ShmemSession::setBankInfo(cbproto::InstrumentId id, uint32_t bank, const cbPKT_BANKINFO& info) { +Result ShmemSession::setBankInfo(uint32_t bank, const cbPKT_BANKINFO& info) { if (!isOpen()) { return Result::error("Session not open"); } - if (!id.isValid()) { - return Result::error("Invalid instrument ID"); - } - - uint8_t idx = id.toIndex(); if (m_impl->layout == ShmemLayout::NATIVE) { - if (idx != 0) { - return Result::error("Native mode: single instrument only"); - } if (bank == 0 || bank > NATIVE_MAXBANKS) { return Result::error("Bank number out of range"); } m_impl->nativeCfg()->bankinfo[bank - 1] = info; return Result::ok(); } else { - return m_impl->adapter->setBankInfo(idx, bank, info); + return m_impl->adapter->setBankInfo(bank, info); } } -Result ShmemSession::setFilterInfo(cbproto::InstrumentId id, uint32_t filter, const cbPKT_FILTINFO& info) { +Result ShmemSession::setFilterInfo(uint32_t filter, const cbPKT_FILTINFO& info) { if (!isOpen()) { return Result::error("Session not open"); } - if (!id.isValid()) { - return Result::error("Invalid instrument ID"); - } - - uint8_t idx = id.toIndex(); if (m_impl->layout == ShmemLayout::NATIVE) { - if (idx != 0) { - return Result::error("Native mode: single instrument only"); - } if (filter == 0 || filter > NATIVE_MAXFILTS) { return Result::error("Filter number out of range"); } m_impl->nativeCfg()->filtinfo[filter - 1] = info; return Result::ok(); } else { - return m_impl->adapter->setFilterInfo(idx, filter, info); + return m_impl->adapter->setFilterInfo( filter, info); } } @@ -1170,27 +1096,19 @@ Result ShmemSession::setSysInfo(const cbPKT_SYSINFO& info) { } } -Result ShmemSession::setGroupInfo(cbproto::InstrumentId id, uint32_t group, const cbPKT_GROUPINFO& info) { +Result ShmemSession::setGroupInfo(uint32_t group, const cbPKT_GROUPINFO& info) { if (!isOpen()) { return Result::error("Session not open"); } - if (!id.isValid()) { - return Result::error("Invalid instrument ID"); - } - - uint8_t idx = id.toIndex(); if (m_impl->layout == ShmemLayout::NATIVE) { - if (idx != 0) { - return Result::error("Native mode: single instrument only"); - } if (group >= NATIVE_MAXGROUPS) { return Result::error("Group index out of range"); } m_impl->nativeCfg()->groupinfo[group] = info; return Result::ok(); } else { - return m_impl->adapter->setGroupInfo(idx, group, info); + return m_impl->adapter->setGroupInfo(group, info); } } @@ -1212,12 +1130,11 @@ const NativeConfigBuffer* ShmemSession::getNativeConfigBuffer() const { return m_impl->nativeCfg(); } -Result ShmemSession::getLegacyConfigBuffer(cbproto::InstrumentId id) { +Result ShmemSession::getLegacyConfigBuffer() { if (!isOpen() || m_impl->layout != ShmemLayout::CENTRAL) { return Result::error("Not open or invalid layout"); } - uint8_t idx = id.toIndex(); - return m_impl->adapter->getConfigBuffer(idx); + return m_impl->adapter->getConfigBuffer(); } Result ShmemSession::storePacket(const cbPKT_GENERIC& pkt) { @@ -1266,7 +1183,7 @@ Result ShmemSession::enqueuePacket(const cbPKT_GENERIC& pkt) { return Result::error("Transmit buffer not initialized"); } - // In CENTRAL_COMPAT mode with an older protocol, translate to the legacy format + // In CENTRAL mode with an older protocol, translate to the legacy format const bool needs_translation = (m_impl->layout == ShmemLayout::CENTRAL && m_impl->compat_protocol != CBPROTO_PROTOCOL_CURRENT); @@ -1586,7 +1503,7 @@ Result ShmemSession::getNumTotalChans() const { if (m_impl->layout == ShmemLayout::NATIVE) { return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nNumTotalChans); } else { - auto status = m_impl->adapter->getPcStatus(0); // instrument idx doesn't matter for m_nNumTotalChans (brittle) + auto status = m_impl->adapter->getPcStatus(); if (status.isError()) { return Result::error("Unable to fetch PC status"); } @@ -1594,7 +1511,7 @@ Result ShmemSession::getNumTotalChans() const { } } -Result ShmemSession::getNspStatus(cbproto::InstrumentId id) const { +Result ShmemSession::getNspStatus() const { if (!m_impl || !m_impl->is_open) { return Result::error("Session is not open"); } @@ -1602,18 +1519,10 @@ Result ShmemSession::getNspStatus(cbproto::InstrumentId id) con return Result::error("Status buffer not initialized"); } - uint32_t index = id.toIndex(); - if (m_impl->layout == ShmemLayout::NATIVE) { - if (index != 0) { - return Result::error("Native mode: single instrument only"); - } return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nNspStatus); } else { - if (index >= central::cbMAXPROCS) { - return Result::error("Invalid instrument ID"); - } - auto status = m_impl->adapter->getPcStatus(index); + auto status = m_impl->adapter->getPcStatus(); if (status.isError()) { return Result::error("Unable to fetch PC status"); } @@ -1621,7 +1530,7 @@ Result ShmemSession::getNspStatus(cbproto::InstrumentId id) con } } -Result ShmemSession::setNspStatus(cbproto::InstrumentId id, NativeNSPStatus status) { +Result ShmemSession::setNspStatus(NativeNSPStatus status) { if (!m_impl || !m_impl->is_open) { return Result::error("Session is not open"); } @@ -1629,23 +1538,15 @@ Result ShmemSession::setNspStatus(cbproto::InstrumentId id, NativeNSPStatu return Result::error("Status buffer not initialized"); } - uint32_t index = id.toIndex(); - if (m_impl->layout == ShmemLayout::NATIVE) { - if (index != 0) { - return Result::error("Native mode: single instrument only"); - } static_cast(m_impl->status_buffer_raw)->m_nNspStatus = status; } else { - if (index >= central::cbMAXPROCS) { - return Result::error("Invalid instrument ID"); - } - auto pc_status = m_impl->adapter->getPcStatus(index); + auto pc_status = m_impl->adapter->getPcStatus(); if (pc_status.isError()) { return Result::error("Unable to fetch PC status"); } pc_status.value().m_nNspStatus = status; - return m_impl->adapter->setPcStatus(index, pc_status.value()); + return m_impl->adapter->setPcStatus(pc_status.value()); } return Result::ok(); @@ -1662,7 +1563,7 @@ Result ShmemSession::isGeminiSystem() const { if (m_impl->layout == ShmemLayout::NATIVE) { return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nGeminiSystem != 0); } else { - auto status = m_impl->adapter->getPcStatus(0); // instrument idx doesn't matter for m_nGeminiSystem (brittle) + auto status = m_impl->adapter->getPcStatus(); if (status.isError()) { return Result::error("Unable to fetch PC status"); } @@ -1681,12 +1582,12 @@ Result ShmemSession::setGeminiSystem(bool is_gemini) { if (m_impl->layout == ShmemLayout::NATIVE) { static_cast(m_impl->status_buffer_raw)->m_nGeminiSystem = is_gemini ? 1 : 0; } else { - auto status = m_impl->adapter->getPcStatus(0); // instrument idx doesn't matter for m_nGeminiSystem (brittle) + auto status = m_impl->adapter->getPcStatus(); if (status.isError()) { return Result::error("Unable to fetch PC status"); } status.value().m_nGeminiSystem = is_gemini ? 1 : 0; - return m_impl->adapter->setPcStatus(0, status.value()); // instrument idx doesn't matter for m_nGeminiSystem (brittle) + return m_impl->adapter->setPcStatus(status.value()); } return Result::ok(); @@ -1885,7 +1786,7 @@ PROCTIME ShmemSession::getLastTime() const { return 0; } PROCTIME t = m_impl->adapter->getRecLasttime(); - // In CENTRAL_COMPAT mode, Central writes lasttime using the device's native + // In CENTRAL mode, Central writes lasttime using the device's native // timestamp unit. Non-Gemini devices use clock ticks; convert to nanoseconds // for consistency with readReceiveBuffer() which translates packet timestamps. if (t != 0 && m_impl->layout == ShmemLayout::CENTRAL) { @@ -1900,21 +1801,6 @@ PROCTIME ShmemSession::getLastTime() const { return t; } -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Instrument Filtering - -void ShmemSession::setInstrumentFilter(int32_t instrument_index) { - m_impl->instrument_filter = instrument_index; -} - -int32_t ShmemSession::getInstrumentFilter() const { - return m_impl->instrument_filter; -} - -cbproto_protocol_version_t ShmemSession::getCompatProtocolVersion() const { - return m_impl->compat_protocol; -} - /////////////////////////////////////////////////////////////////////////////////////////////////// // Receive buffer reading methods @@ -2097,7 +1983,7 @@ Result ShmemSession::readReceiveBuffer(cbPKT_GENERIC* packets, size_t max_ } } - // Non-Gemini CENTRAL_COMPAT: convert header timestamp from clock ticks to nanoseconds. + // Non-Gemini CENTRAL: convert header timestamp from clock ticks to nanoseconds. // Applied after both translation and non-translation paths. if (needs_ts_conversion) { packets[packets_read].cbpkt_header.time = @@ -2111,12 +1997,9 @@ Result ShmemSession::readReceiveBuffer(cbPKT_GENERIC* packets, size_t max_ m_impl->rec_tailwrap++; } - // Apply instrument filter: skip packets not matching our instrument - if (m_impl->instrument_filter >= 0) { - uint8_t pkt_instrument = packets[packets_read].cbpkt_header.instrument; - if (pkt_instrument != static_cast(m_impl->instrument_filter)) { - continue; // Skip this packet, don't increment packets_read - } + uint8_t pkt_instrument = packets[packets_read].cbpkt_header.instrument; + if (pkt_instrument != m_impl->inst.toIndex()) { + continue; // Skip this packet, don't increment packets_read } packets_read++; @@ -2167,7 +2050,7 @@ void ShmemSession::setClockSync(int64_t offset_ns, int64_t uncertainty_ns) { cfg->clock_uncertainty_ns = uncertainty_ns; cfg->clock_sync_valid = 1; } - // CENTRAL and CENTRAL_COMPAT layouts don't have clock sync fields + // The CENTRAL layout doesn't have clock sync fields } std::optional ShmemSession::getClockOffsetNs() const { From 692066eb4fc254ae16a463248490bede3811d3fc Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Mon, 15 Jun 2026 17:02:13 -0600 Subject: [PATCH 20/62] Make cbPcStatus operations multi-instrument safe --- .../include/cbshm/central_types/adapters.h | 23 ++++++------- src/cbshm/src/central_adapters/v3_11.cpp | 32 ++++-------------- src/cbshm/src/central_adapters/v4_0.cpp | 32 ++++-------------- src/cbshm/src/central_adapters/v4_1.cpp | 33 ++++--------------- src/cbshm/src/central_adapters/v4_2.cpp | 32 ++++-------------- src/cbshm/src/shmem_session.cpp | 14 ++------ 6 files changed, 39 insertions(+), 127 deletions(-) diff --git a/src/cbshm/include/cbshm/central_types/adapters.h b/src/cbshm/include/cbshm/central_types/adapters.h index d18c06ff..5e0fb653 100644 --- a/src/cbshm/include/cbshm/central_types/adapters.h +++ b/src/cbshm/include/cbshm/central_types/adapters.h @@ -155,7 +155,8 @@ class CentralAdapterBase { virtual Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) = 0; virtual Result setSysInfo(const ::cbPKT_SYSINFO& info) = 0; virtual Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) = 0; - virtual Result setPcStatus(const NativePCStatus& status) const = 0; // TODO: currently single-instrument only! needs to be multi-instrument safe + virtual Result setNspStatus(const NativeNSPStatus& status) const = 0; + virtual Result setGeminiSystem(bool is_gemini) const = 0; }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -257,10 +258,8 @@ class Adapter : public CentralAdapterBase { cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) const; cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) const; cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) const; - // cbCFGBUFF -> NativeConfigBuffer is a lossy translation and cannot be reversed NSPStatus toLegacy(const NativeNSPStatus& cur) const; cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const; - cbPcStatus toLegacy(const NativePCStatus& cur) const; cbRECBUFF toLegacy(const NativeReceiveBuffer& cur) const; cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur) const; cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur) const; @@ -320,7 +319,8 @@ class Adapter : public CentralAdapterBase { Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; Result setSysInfo(const ::cbPKT_SYSINFO& info) override; Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; - Result setPcStatus(const NativePCStatus& status) const override; + Result setNspStatus(const NativeNSPStatus& status) const override; + Result setGeminiSystem(bool is_gemini) const override; }; } // namespace central_v4_2 @@ -424,10 +424,8 @@ class Adapter : public CentralAdapterBase { cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) const; cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) const; cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) const; - // cbCFGBUFF -> NativeConfigBuffer is a lossy translation and cannot be reversed NSPStatus toLegacy(const NativeNSPStatus& cur) const; cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const; - cbPcStatus toLegacy(const NativePCStatus& cur) const; cbRECBUFF toLegacy(const NativeReceiveBuffer& cur) const; cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur) const; cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur) const; @@ -487,7 +485,8 @@ class Adapter : public CentralAdapterBase { Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; Result setSysInfo(const ::cbPKT_SYSINFO& info) override; Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; - Result setPcStatus(const NativePCStatus& status) const override; + Result setNspStatus(const NativeNSPStatus& status) const override; + Result setGeminiSystem(bool is_gemini) const override; }; } // namespace central_v4_1 @@ -591,10 +590,8 @@ class Adapter : public CentralAdapterBase { cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) const; cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) const; cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) const; - // cbCFGBUFF -> NativeConfigBuffer is a lossy translation and cannot be reversed NSPStatus toLegacy(const NativeNSPStatus& cur) const; cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const; - cbPcStatus toLegacy(const NativePCStatus& cur) const; cbRECBUFF toLegacy(const NativeReceiveBuffer& cur) const; cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur) const; cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur) const; @@ -654,7 +651,8 @@ class Adapter : public CentralAdapterBase { Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; Result setSysInfo(const ::cbPKT_SYSINFO& info) override; Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; - Result setPcStatus(const NativePCStatus& status) const override; + Result setNspStatus(const NativeNSPStatus& status) const override; + Result setGeminiSystem(bool is_gemini) const override; }; } // namespace central_v4_0 @@ -758,10 +756,8 @@ class Adapter : public CentralAdapterBase { cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) const; cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) const; cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) const; - // cbCFGBUFF -> NativeConfigBuffer is a lossy translation and cannot be reversed NSPStatus toLegacy(const NativeNSPStatus& cur) const; cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const; - cbPcStatus toLegacy(const NativePCStatus& cur) const; cbRECBUFF toLegacy(const NativeReceiveBuffer& cur) const; cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur) const; cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur) const; @@ -821,7 +817,8 @@ class Adapter : public CentralAdapterBase { Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; Result setSysInfo(const ::cbPKT_SYSINFO& info) override; Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; - Result setPcStatus(const NativePCStatus& status) const override; + Result setNspStatus(const NativeNSPStatus& status) const override; + Result setGeminiSystem(bool is_gemini) const override; }; } // namespace central_v3_11 diff --git a/src/cbshm/src/central_adapters/v3_11.cpp b/src/cbshm/src/central_adapters/v3_11.cpp index 4c2cbf17..3e1fe1e7 100644 --- a/src/cbshm/src/central_adapters/v3_11.cpp +++ b/src/cbshm/src/central_adapters/v3_11.cpp @@ -516,7 +516,6 @@ NativePCStatus Adapter::fromLegacy(const cbPcStatus& leg) const { cur.m_nNspStatus = NativeNSPStatus::NSP_FOUND; // TODO: VERIFY cur.m_nNumNTrodesPerInstrument = cbMAXNTRODES; // TODO: VERIFY cur.m_nGeminiSystem = 1; // TODO: VERIFY - // ignore APP_WORKSPACE return cur; } @@ -969,25 +968,6 @@ cbPKT_UNIT_SELECTION Adapter::toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const return leg; } -cbPcStatus Adapter::toLegacy(const NativePCStatus& cur) const { - cbPcStatus leg{}; - leg.isSelection[instrument_idx] = toLegacy(cur.isSelection); - leg.m_iBlockRecording = cur.m_iBlockRecording; - leg.m_nPCStatusFlags = cur.m_nPCStatusFlags; - leg.m_nNumFEChans = cur.m_nNumFEChans; - leg.m_nNumAnainChans = cur.m_nNumAnainChans; - leg.m_nNumAnalogChans = cur.m_nNumAnalogChans; - leg.m_nNumAoutChans = cur.m_nNumAoutChans; - leg.m_nNumAudioChans = cur.m_nNumAudioChans; - leg.m_nNumAnalogoutChans = cur.m_nNumAnalogoutChans; - leg.m_nNumDiginChans = cur.m_nNumDiginChans; - leg.m_nNumSerialChans = cur.m_nNumSerialChans; - leg.m_nNumDigoutChans = cur.m_nNumDigoutChans; - leg.m_nNumTotalChans = cur.m_nNumTotalChans; - // ignore APP_WORKSPACE - return leg; -} - cbRECBUFF Adapter::toLegacy(const NativeReceiveBuffer& cur) const { cbRECBUFF leg{}; leg.received = cur.received; @@ -1226,12 +1206,12 @@ Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& return Result::ok(); } -Result Adapter::setPcStatus(const NativePCStatus& status) const { - if (instrument_idx >= std::size(this->status->isSelection)) { - return Result::error("Instrument index out of range"); - } - *(this->status) = toLegacy(status); - return Result::ok(); +Result Adapter::setNspStatus(const NativeNSPStatus& status) const { + return Result::error("Central v3.11 does not have fields for NSP status"); +} + +Result Adapter::setGeminiSystem(bool is_gemini) const { + return Result::error("Central v3.11 does not recognize Gemini systems"); } } // namespace central_v3_11 diff --git a/src/cbshm/src/central_adapters/v4_0.cpp b/src/cbshm/src/central_adapters/v4_0.cpp index a61e2ec8..2baf76a2 100644 --- a/src/cbshm/src/central_adapters/v4_0.cpp +++ b/src/cbshm/src/central_adapters/v4_0.cpp @@ -516,7 +516,6 @@ NativePCStatus Adapter::fromLegacy(const cbPcStatus& leg) const { cur.m_nNspStatus = fromLegacy(leg.m_nNspStatus[instrument_idx]); cur.m_nNumNTrodesPerInstrument = leg.m_nNumNTrodesPerInstrument[instrument_idx]; cur.m_nGeminiSystem = leg.m_nGeminiSystem; - // ignore APP_WORKSPACE return cur; } @@ -971,28 +970,6 @@ cbPKT_UNIT_SELECTION Adapter::toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const return leg; } -cbPcStatus Adapter::toLegacy(const NativePCStatus& cur) const { - cbPcStatus leg{}; - leg.isSelection[instrument_idx] = toLegacy(cur.isSelection); - leg.m_iBlockRecording = cur.m_iBlockRecording; - leg.m_nPCStatusFlags = cur.m_nPCStatusFlags; - leg.m_nNumFEChans = cur.m_nNumFEChans; - leg.m_nNumAnainChans = cur.m_nNumAnainChans; - leg.m_nNumAnalogChans = cur.m_nNumAnalogChans; - leg.m_nNumAoutChans = cur.m_nNumAoutChans; - leg.m_nNumAudioChans = cur.m_nNumAudioChans; - leg.m_nNumAnalogoutChans = cur.m_nNumAnalogoutChans; - leg.m_nNumDiginChans = cur.m_nNumDiginChans; - leg.m_nNumSerialChans = cur.m_nNumSerialChans; - leg.m_nNumDigoutChans = cur.m_nNumDigoutChans; - leg.m_nNumTotalChans = cur.m_nNumTotalChans; - leg.m_nNspStatus[instrument_idx] = toLegacy(cur.m_nNspStatus); - leg.m_nNumNTrodesPerInstrument[instrument_idx] = cur.m_nNumNTrodesPerInstrument; - leg.m_nGeminiSystem = cur.m_nGeminiSystem; - // ignore APP_WORKSPACE - return leg; -} - cbRECBUFF Adapter::toLegacy(const NativeReceiveBuffer& cur) const { cbRECBUFF leg{}; leg.received = cur.received; @@ -1231,11 +1208,16 @@ Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& return Result::ok(); } -Result Adapter::setPcStatus(const NativePCStatus& status) const { +Result Adapter::setNspStatus(const NativeNSPStatus& status) const { if (instrument_idx >= std::size(this->status->isSelection)) { return Result::error("Instrument index out of range"); } - *(this->status) = this->toLegacy(status); + this->status->m_nNspStatus[instrument_idx] = toLegacy(status); + return Result::ok(); +} + +Result Adapter::setGeminiSystem(bool is_gemini) const { + status->m_nGeminiSystem = is_gemini ? 1 : 0; return Result::ok(); } diff --git a/src/cbshm/src/central_adapters/v4_1.cpp b/src/cbshm/src/central_adapters/v4_1.cpp index b0be6dd5..9f2d37fa 100644 --- a/src/cbshm/src/central_adapters/v4_1.cpp +++ b/src/cbshm/src/central_adapters/v4_1.cpp @@ -470,7 +470,6 @@ NativeConfigBuffer Adapter::fromLegacy(const cbCFGBUFF& leg) const { copyArr(cur.isVideoSource, leg.isVideoSource, this, &Adapter::fromLegacy); copyArr(cur.isTrackObj, leg.isTrackObj, this, &Adapter::fromLegacy); cur.fileinfo = fromLegacy(leg.fileinfo); - return cur; } @@ -516,7 +515,6 @@ NativePCStatus Adapter::fromLegacy(const cbPcStatus& leg) const { cur.m_nNspStatus = fromLegacy(leg.m_nNspStatus[instrument_idx]); cur.m_nNumNTrodesPerInstrument = leg.m_nNumNTrodesPerInstrument[instrument_idx]; cur.m_nGeminiSystem = leg.m_nGeminiSystem; - // ignore APP_WORKSPACE return cur; } @@ -975,28 +973,6 @@ cbPKT_UNIT_SELECTION Adapter::toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const return leg; } -cbPcStatus Adapter::toLegacy(const NativePCStatus& cur) const { - cbPcStatus leg{}; - leg.isSelection[instrument_idx] = toLegacy(cur.isSelection); - leg.m_iBlockRecording = cur.m_iBlockRecording; - leg.m_nPCStatusFlags = cur.m_nPCStatusFlags; - leg.m_nNumFEChans = cur.m_nNumFEChans; - leg.m_nNumAnainChans = cur.m_nNumAnainChans; - leg.m_nNumAnalogChans = cur.m_nNumAnalogChans; - leg.m_nNumAoutChans = cur.m_nNumAoutChans; - leg.m_nNumAudioChans = cur.m_nNumAudioChans; - leg.m_nNumAnalogoutChans = cur.m_nNumAnalogoutChans; - leg.m_nNumDiginChans = cur.m_nNumDiginChans; - leg.m_nNumSerialChans = cur.m_nNumSerialChans; - leg.m_nNumDigoutChans = cur.m_nNumDigoutChans; - leg.m_nNumTotalChans = cur.m_nNumTotalChans; - leg.m_nNspStatus[instrument_idx] = toLegacy(cur.m_nNspStatus); - leg.m_nNumNTrodesPerInstrument[instrument_idx] = cur.m_nNumNTrodesPerInstrument; - leg.m_nGeminiSystem = cur.m_nGeminiSystem; - // ignore APP_WORKSPACE - return leg; -} - cbRECBUFF Adapter::toLegacy(const NativeReceiveBuffer& cur) const { cbRECBUFF leg{}; leg.received = cur.received; @@ -1235,11 +1211,16 @@ Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& return Result::ok(); } -Result Adapter::setPcStatus(const NativePCStatus& status) const { +Result Adapter::setNspStatus(const NativeNSPStatus& status) const { if (instrument_idx >= std::size(this->status->isSelection)) { return Result::error("Instrument index out of range"); } - *(this->status) = toLegacy(status); + this->status->m_nNspStatus[instrument_idx] = toLegacy(status); + return Result::ok(); +} + +Result Adapter::setGeminiSystem(bool is_gemini) const { + status->m_nGeminiSystem = is_gemini ? 1 : 0; return Result::ok(); } diff --git a/src/cbshm/src/central_adapters/v4_2.cpp b/src/cbshm/src/central_adapters/v4_2.cpp index b58e79a9..f1574dc1 100644 --- a/src/cbshm/src/central_adapters/v4_2.cpp +++ b/src/cbshm/src/central_adapters/v4_2.cpp @@ -470,7 +470,6 @@ NativeConfigBuffer Adapter::fromLegacy(const cbCFGBUFF& leg) const { copyArr(cur.isVideoSource, leg.isVideoSource, this, &Adapter::fromLegacy); copyArr(cur.isTrackObj, leg.isTrackObj, this, &Adapter::fromLegacy); cur.fileinfo = fromLegacy(leg.fileinfo); - return cur; } @@ -975,28 +974,6 @@ cbPKT_UNIT_SELECTION Adapter::toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const return leg; } -cbPcStatus Adapter::toLegacy(const NativePCStatus& cur) const { - cbPcStatus leg{}; - leg.isSelection[instrument_idx] = toLegacy(cur.isSelection); - leg.m_iBlockRecording = cur.m_iBlockRecording; - leg.m_nPCStatusFlags = cur.m_nPCStatusFlags; - leg.m_nNumFEChans = cur.m_nNumFEChans; - leg.m_nNumAnainChans = cur.m_nNumAnainChans; - leg.m_nNumAnalogChans = cur.m_nNumAnalogChans; - leg.m_nNumAoutChans = cur.m_nNumAoutChans; - leg.m_nNumAudioChans = cur.m_nNumAudioChans; - leg.m_nNumAnalogoutChans = cur.m_nNumAnalogoutChans; - leg.m_nNumDiginChans = cur.m_nNumDiginChans; - leg.m_nNumSerialChans = cur.m_nNumSerialChans; - leg.m_nNumDigoutChans = cur.m_nNumDigoutChans; - leg.m_nNumTotalChans = cur.m_nNumTotalChans; - leg.m_nNspStatus[instrument_idx] = toLegacy(cur.m_nNspStatus); - leg.m_nNumNTrodesPerInstrument[instrument_idx] = cur.m_nNumNTrodesPerInstrument; - leg.m_nGeminiSystem = cur.m_nGeminiSystem; - // ignore APP_WORKSPACE - return leg; -} - cbRECBUFF Adapter::toLegacy(const NativeReceiveBuffer& cur) const { cbRECBUFF leg{}; leg.received = cur.received; @@ -1236,11 +1213,16 @@ Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& return Result::ok(); } -Result Adapter::setPcStatus(const NativePCStatus& status) const { +Result Adapter::setNspStatus(const NativeNSPStatus& status) const { if (instrument_idx >= std::size(this->status->isSelection)) { return Result::error("Instrument index out of range"); } - *(this->status) = toLegacy(status); + this->status->m_nNspStatus[instrument_idx] = toLegacy(status); + return Result::ok(); +} + +Result Adapter::setGeminiSystem(bool is_gemini) const { + status->m_nGeminiSystem = is_gemini ? 1 : 0; return Result::ok(); } diff --git a/src/cbshm/src/shmem_session.cpp b/src/cbshm/src/shmem_session.cpp index 3e8e177c..b038f3a8 100644 --- a/src/cbshm/src/shmem_session.cpp +++ b/src/cbshm/src/shmem_session.cpp @@ -1541,12 +1541,7 @@ Result ShmemSession::setNspStatus(NativeNSPStatus status) { if (m_impl->layout == ShmemLayout::NATIVE) { static_cast(m_impl->status_buffer_raw)->m_nNspStatus = status; } else { - auto pc_status = m_impl->adapter->getPcStatus(); - if (pc_status.isError()) { - return Result::error("Unable to fetch PC status"); - } - pc_status.value().m_nNspStatus = status; - return m_impl->adapter->setPcStatus(pc_status.value()); + return m_impl->adapter->setNspStatus(status); } return Result::ok(); @@ -1582,12 +1577,7 @@ Result ShmemSession::setGeminiSystem(bool is_gemini) { if (m_impl->layout == ShmemLayout::NATIVE) { static_cast(m_impl->status_buffer_raw)->m_nGeminiSystem = is_gemini ? 1 : 0; } else { - auto status = m_impl->adapter->getPcStatus(); - if (status.isError()) { - return Result::error("Unable to fetch PC status"); - } - status.value().m_nGeminiSystem = is_gemini ? 1 : 0; - return m_impl->adapter->setPcStatus(status.value()); + return m_impl->adapter->setGeminiSystem(is_gemini); } return Result::ok(); From 5eb23ea2d92b38abfbf1e1ed0f457ebcde092c15 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Mon, 15 Jun 2026 17:50:26 -0600 Subject: [PATCH 21/62] Implement spike buffer access methods for Central compat Add translators for cbPKT_SPK, cbSPKBUFF, and cbSPKCACHE. Implement getSpikeCache and getRecentSpike for ShmemSession with layout == CENTRAL. --- .../include/cbshm/central_types/adapters.h | 21 ++++++++ src/cbshm/src/central_adapters/v3_11.cpp | 48 ++++++++++++++++++ src/cbshm/src/central_adapters/v4_0.cpp | 48 ++++++++++++++++++ src/cbshm/src/central_adapters/v4_1.cpp | 48 ++++++++++++++++++ src/cbshm/src/central_adapters/v4_2.cpp | 49 ++++++++++++++++++- src/cbshm/src/shmem_session.cpp | 30 +++++------- 6 files changed, 226 insertions(+), 18 deletions(-) diff --git a/src/cbshm/include/cbshm/central_types/adapters.h b/src/cbshm/include/cbshm/central_types/adapters.h index 5e0fb653..63afbf1a 100644 --- a/src/cbshm/include/cbshm/central_types/adapters.h +++ b/src/cbshm/include/cbshm/central_types/adapters.h @@ -147,6 +147,7 @@ class CentralAdapterBase { virtual Result<::cbPKT_GROUPINFO> getGroupInfo(uint32_t group_idx) const = 0; virtual Result getConfigBuffer() const = 0; virtual Result getPcStatus() const = 0; + virtual Result getSpikeCache(uint32_t channel_idx) const = 0; /// Config write operations virtual Result setProcInfo(const ::cbPKT_PROCINFO& info) = 0; @@ -227,6 +228,9 @@ class Adapter : public CentralAdapterBase { NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg) const; NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg) const; NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg) const; + ::cbPKT_SPK fromLegacy(const cbPKT_SPK& leg) const; + NativeSpikeCache fromLegacy(const cbSPKCACHE& leg) const; + NativeSpikeBuffer fromLegacy(const cbSPKBUFF& leg) const; cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) const; cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) const; @@ -263,6 +267,7 @@ class Adapter : public CentralAdapterBase { cbRECBUFF toLegacy(const NativeReceiveBuffer& cur) const; cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur) const; cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur) const; + cbPKT_SPK toLegacy(const ::cbPKT_SPK& cur) const; public: Adapter( @@ -311,6 +316,7 @@ class Adapter : public CentralAdapterBase { Result<::cbPKT_GROUPINFO> getGroupInfo(uint32_t group_idx) const override; Result getConfigBuffer() const override; Result getPcStatus() const override; + Result getSpikeCache(uint32_t channel_idx) const override; /// Config write operations Result setProcInfo(const ::cbPKT_PROCINFO& info) override; @@ -393,6 +399,9 @@ class Adapter : public CentralAdapterBase { NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg) const; NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg) const; NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg) const; + ::cbPKT_SPK fromLegacy(const cbPKT_SPK& leg) const; + NativeSpikeCache fromLegacy(const cbSPKCACHE& leg) const; + NativeSpikeBuffer fromLegacy(const cbSPKBUFF& leg) const; cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) const; cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) const; @@ -429,6 +438,7 @@ class Adapter : public CentralAdapterBase { cbRECBUFF toLegacy(const NativeReceiveBuffer& cur) const; cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur) const; cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur) const; + cbPKT_SPK toLegacy(const ::cbPKT_SPK& cur) const; public: Adapter( @@ -477,6 +487,7 @@ class Adapter : public CentralAdapterBase { Result<::cbPKT_GROUPINFO> getGroupInfo(uint32_t group_idx) const override; Result getConfigBuffer() const override; Result getPcStatus() const override; + Result getSpikeCache(uint32_t channel_idx) const override; /// Config write operations Result setProcInfo(const ::cbPKT_PROCINFO& info) override; @@ -559,6 +570,9 @@ class Adapter : public CentralAdapterBase { NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg) const; NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg) const; NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg) const; + ::cbPKT_SPK fromLegacy(const cbPKT_SPK& leg) const; + NativeSpikeCache fromLegacy(const cbSPKCACHE& leg) const; + NativeSpikeBuffer fromLegacy(const cbSPKBUFF& leg) const; cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) const; cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) const; @@ -595,6 +609,7 @@ class Adapter : public CentralAdapterBase { cbRECBUFF toLegacy(const NativeReceiveBuffer& cur) const; cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur) const; cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur) const; + cbPKT_SPK toLegacy(const ::cbPKT_SPK& cur) const; public: Adapter( @@ -643,6 +658,7 @@ class Adapter : public CentralAdapterBase { Result<::cbPKT_GROUPINFO> getGroupInfo(uint32_t group_idx) const override; Result getConfigBuffer() const override; Result getPcStatus() const override; + Result getSpikeCache(uint32_t channel_idx) const override; /// Config write operations Result setProcInfo(const ::cbPKT_PROCINFO& info) override; @@ -725,6 +741,9 @@ class Adapter : public CentralAdapterBase { NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg) const; NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg) const; NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg) const; + ::cbPKT_SPK fromLegacy(const cbPKT_SPK& leg) const; + NativeSpikeCache fromLegacy(const cbSPKCACHE& leg) const; + NativeSpikeBuffer fromLegacy(const cbSPKBUFF& leg) const; cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) const; cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) const; @@ -761,6 +780,7 @@ class Adapter : public CentralAdapterBase { cbRECBUFF toLegacy(const NativeReceiveBuffer& cur) const; cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur) const; cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur) const; + cbPKT_SPK toLegacy(const ::cbPKT_SPK& cur) const; public: Adapter( @@ -809,6 +829,7 @@ class Adapter : public CentralAdapterBase { Result<::cbPKT_GROUPINFO> getGroupInfo(uint32_t group_idx) const override; Result getConfigBuffer() const override; Result getPcStatus() const override; + Result getSpikeCache(uint32_t channel_idx) const override; /// Config write operations Result setProcInfo(const ::cbPKT_PROCINFO& info) override; diff --git a/src/cbshm/src/central_adapters/v3_11.cpp b/src/cbshm/src/central_adapters/v3_11.cpp index 3e1fe1e7..225b2074 100644 --- a/src/cbshm/src/central_adapters/v3_11.cpp +++ b/src/cbshm/src/central_adapters/v3_11.cpp @@ -551,6 +551,37 @@ NativeTransmitBufferLocal Adapter::fromLegacy(const cbXMTBUFFLOCAL& leg) const { return cur; } +::cbPKT_SPK Adapter::fromLegacy(const cbPKT_SPK& leg) const { + ::cbPKT_SPK cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + copyArr(cur.fPattern, leg.fPattern); + cur.nPeak = leg.nPeak; + cur.nValley = leg.nValley; + copyArr(cur.wave, leg.wave); + return cur; +} + +NativeSpikeCache Adapter::fromLegacy(const cbSPKCACHE& leg) const { + NativeSpikeCache cur{}; + cur.chid = leg.chid; + cur.pktcnt = leg.pktcnt; + cur.pktsize = leg.pktsize; + cur.head = leg.head; + cur.valid = leg.valid; + copyArr(cur.spkpkt, leg.spkpkt, this, &Adapter::fromLegacy); + return cur; +} + +NativeSpikeBuffer Adapter::fromLegacy(const cbSPKBUFF& leg) const { + NativeSpikeBuffer cur{}; + cur.flags = leg.flags; + cur.chidmax = leg.chidmax; + cur.linesize = leg.linesize; + cur.spkcount = leg.spkcount; + copyArr(cur.cache, leg.cache, this, &Adapter::fromLegacy); + return cur; +} + cbPKT_HEADER Adapter::toLegacy(const ::cbPKT_HEADER& cur) const { cbPKT_HEADER leg{}; leg.time = cur.time; @@ -1000,6 +1031,16 @@ cbXMTBUFFLOCAL Adapter::toLegacy(const NativeTransmitBufferLocal& cur) const { return leg; } +cbPKT_SPK Adapter::toLegacy(const ::cbPKT_SPK& cur) const { + cbPKT_SPK leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + copyArr(leg.fPattern, leg.fPattern); + leg.nPeak = cur.nPeak; + leg.nValley = cur.nValley; + copyArr(leg.wave, cur.wave); + return leg; +} + Adapter::Adapter(uint8_t instrument_idx, void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) : instrument_idx(instrument_idx) , cfg(static_cast(cfg_ptr)) @@ -1150,6 +1191,13 @@ Result Adapter::getPcStatus() const { return Result::ok(fromLegacy(*status)); } +Result Adapter::getSpikeCache(uint32_t channel_idx) const { + if (channel_idx >= std::size(spike->cache)) { + return Result::error("Channel index out of range"); + } + return Result::ok(fromLegacy(spike->cache[channel_idx])); +} + Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { if (instrument_idx >= std::size(cfg->procinfo)) { return Result::error("Instrument index out of range"); diff --git a/src/cbshm/src/central_adapters/v4_0.cpp b/src/cbshm/src/central_adapters/v4_0.cpp index 2baf76a2..83502786 100644 --- a/src/cbshm/src/central_adapters/v4_0.cpp +++ b/src/cbshm/src/central_adapters/v4_0.cpp @@ -551,6 +551,37 @@ NativeTransmitBufferLocal Adapter::fromLegacy(const cbXMTBUFFLOCAL& leg) const { return cur; } +::cbPKT_SPK Adapter::fromLegacy(const cbPKT_SPK& leg) const { + ::cbPKT_SPK cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + copyArr(cur.fPattern, leg.fPattern); + cur.nPeak = leg.nPeak; + cur.nValley = leg.nValley; + copyArr(cur.wave, leg.wave); + return cur; +} + +NativeSpikeCache Adapter::fromLegacy(const cbSPKCACHE& leg) const { + NativeSpikeCache cur{}; + cur.chid = leg.chid; + cur.pktcnt = leg.pktcnt; + cur.pktsize = leg.pktsize; + cur.head = leg.head; + cur.valid = leg.valid; + copyArr(cur.spkpkt, leg.spkpkt, this, &Adapter::fromLegacy); + return cur; +} + +NativeSpikeBuffer Adapter::fromLegacy(const cbSPKBUFF& leg) const { + NativeSpikeBuffer cur{}; + cur.flags = leg.flags; + cur.chidmax = leg.chidmax; + cur.linesize = leg.linesize; + cur.spkcount = leg.spkcount; + copyArr(cur.cache, leg.cache, this, &Adapter::fromLegacy); + return cur; +} + cbPKT_HEADER Adapter::toLegacy(const ::cbPKT_HEADER& cur) const { cbPKT_HEADER leg{}; leg.time = cur.time; @@ -1002,6 +1033,16 @@ cbXMTBUFFLOCAL Adapter::toLegacy(const NativeTransmitBufferLocal& cur) const { return leg; } +cbPKT_SPK Adapter::toLegacy(const ::cbPKT_SPK& cur) const { + cbPKT_SPK leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + copyArr(leg.fPattern, leg.fPattern); + leg.nPeak = cur.nPeak; + leg.nValley = cur.nValley; + copyArr(leg.wave, cur.wave); + return leg; +} + Adapter::Adapter(uint8_t instrument_idx, void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) : instrument_idx(instrument_idx) , cfg(static_cast(cfg_ptr)) @@ -1152,6 +1193,13 @@ Result Adapter::getPcStatus() const { return Result::ok(fromLegacy(*status)); } +Result Adapter::getSpikeCache(uint32_t channel_idx) const { + if (channel_idx >= std::size(spike->cache)) { + return Result::error("Channel index out of range"); + } + return Result::ok(fromLegacy(spike->cache[channel_idx])); +} + Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { if (instrument_idx >= std::size(cfg->procinfo)) { return Result::error("Instrument index out of range"); diff --git a/src/cbshm/src/central_adapters/v4_1.cpp b/src/cbshm/src/central_adapters/v4_1.cpp index 9f2d37fa..dcc643d2 100644 --- a/src/cbshm/src/central_adapters/v4_1.cpp +++ b/src/cbshm/src/central_adapters/v4_1.cpp @@ -550,6 +550,37 @@ NativeTransmitBufferLocal Adapter::fromLegacy(const cbXMTBUFFLOCAL& leg) const { return cur; } +::cbPKT_SPK Adapter::fromLegacy(const cbPKT_SPK& leg) const { + ::cbPKT_SPK cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + copyArr(cur.fPattern, leg.fPattern); + cur.nPeak = leg.nPeak; + cur.nValley = leg.nValley; + copyArr(cur.wave, leg.wave); + return cur; +} + +NativeSpikeCache Adapter::fromLegacy(const cbSPKCACHE& leg) const { + NativeSpikeCache cur{}; + cur.chid = leg.chid; + cur.pktcnt = leg.pktcnt; + cur.pktsize = leg.pktsize; + cur.head = leg.head; + cur.valid = leg.valid; + copyArr(cur.spkpkt, leg.spkpkt, this, &Adapter::fromLegacy); + return cur; +} + +NativeSpikeBuffer Adapter::fromLegacy(const cbSPKBUFF& leg) const { + NativeSpikeBuffer cur{}; + cur.flags = leg.flags; + cur.chidmax = leg.chidmax; + cur.linesize = leg.linesize; + cur.spkcount = leg.spkcount; + copyArr(cur.cache, leg.cache, this, &Adapter::fromLegacy); + return cur; +} + cbPKT_HEADER Adapter::toLegacy(const ::cbPKT_HEADER& cur) const { cbPKT_HEADER leg{}; leg.time = cur.time; @@ -1005,6 +1036,16 @@ cbXMTBUFFLOCAL Adapter::toLegacy(const NativeTransmitBufferLocal& cur) const { return leg; } +cbPKT_SPK Adapter::toLegacy(const ::cbPKT_SPK& cur) const { + cbPKT_SPK leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + copyArr(leg.fPattern, leg.fPattern); + leg.nPeak = cur.nPeak; + leg.nValley = cur.nValley; + copyArr(leg.wave, cur.wave); + return leg; +} + Adapter::Adapter(uint8_t instrument_idx, void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) : instrument_idx(instrument_idx) , cfg(static_cast(cfg_ptr)) @@ -1155,6 +1196,13 @@ Result Adapter::getPcStatus() const { return Result::ok(fromLegacy(*status)); } +Result Adapter::getSpikeCache(uint32_t channel_idx) const { + if (channel_idx >= std::size(spike->cache)) { + return Result::error("Channel index out of range"); + } + return Result::ok(fromLegacy(spike->cache[channel_idx])); +} + Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { if (instrument_idx >= std::size(cfg->procinfo)) { return Result::error("Instrument index out of range"); diff --git a/src/cbshm/src/central_adapters/v4_2.cpp b/src/cbshm/src/central_adapters/v4_2.cpp index f1574dc1..df4fd5f7 100644 --- a/src/cbshm/src/central_adapters/v4_2.cpp +++ b/src/cbshm/src/central_adapters/v4_2.cpp @@ -551,6 +551,37 @@ NativeTransmitBufferLocal Adapter::fromLegacy(const cbXMTBUFFLOCAL& leg) const { return cur; } +::cbPKT_SPK Adapter::fromLegacy(const cbPKT_SPK& leg) const { + ::cbPKT_SPK cur{}; + cur.cbpkt_header = fromLegacy(leg.cbpkt_header); + copyArr(cur.fPattern, leg.fPattern); + cur.nPeak = leg.nPeak; + cur.nValley = leg.nValley; + copyArr(cur.wave, leg.wave); + return cur; +} + +NativeSpikeCache Adapter::fromLegacy(const cbSPKCACHE& leg) const { + NativeSpikeCache cur{}; + cur.chid = leg.chid; + cur.pktcnt = leg.pktcnt; + cur.pktsize = leg.pktsize; + cur.head = leg.head; + cur.valid = leg.valid; + copyArr(cur.spkpkt, leg.spkpkt, this, &Adapter::fromLegacy); + return cur; +} + +NativeSpikeBuffer Adapter::fromLegacy(const cbSPKBUFF& leg) const { + NativeSpikeBuffer cur{}; + cur.flags = leg.flags; + cur.chidmax = leg.chidmax; + cur.linesize = leg.linesize; + cur.spkcount = leg.spkcount; + copyArr(cur.cache, leg.cache, this, &Adapter::fromLegacy); + return cur; +} + cbPKT_HEADER Adapter::toLegacy(const ::cbPKT_HEADER& cur) const { cbPKT_HEADER leg{}; leg.time = cur.time; @@ -1006,6 +1037,16 @@ cbXMTBUFFLOCAL Adapter::toLegacy(const NativeTransmitBufferLocal& cur) const { return leg; } +cbPKT_SPK Adapter::toLegacy(const ::cbPKT_SPK& cur) const { + cbPKT_SPK leg{}; + leg.cbpkt_header = toLegacy(cur.cbpkt_header); + copyArr(leg.fPattern, leg.fPattern); + leg.nPeak = cur.nPeak; + leg.nValley = cur.nValley; + copyArr(leg.wave, cur.wave); + return leg; +} + Adapter::Adapter(uint8_t instrument_idx, void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) : instrument_idx(instrument_idx) , cfg(static_cast(cfg_ptr)) @@ -1068,7 +1109,6 @@ uint32_t* Adapter::getXmtBufferPtr() { return xmt->buffer; } - uint32_t& Adapter::getLocalXmtTransmittedPtr() { return xmt->transmitted; } @@ -1157,6 +1197,13 @@ Result Adapter::getPcStatus() const { return Result::ok(fromLegacy(*status)); } +Result Adapter::getSpikeCache(uint32_t channel_idx) const { + if (channel_idx >= std::size(spike->cache)) { + return Result::error("Channel index out of range"); + } + return Result::ok(fromLegacy(spike->cache[channel_idx])); +} + Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { if (instrument_idx >= std::size(cfg->procinfo)) { return Result::error("Instrument index out of range"); diff --git a/src/cbshm/src/shmem_session.cpp b/src/cbshm/src/shmem_session.cpp index b038f3a8..ff2926ef 100644 --- a/src/cbshm/src/shmem_session.cpp +++ b/src/cbshm/src/shmem_session.cpp @@ -1598,7 +1598,7 @@ Result ShmemSession::getSpikeCache(uint32_t channel, NativeSpikeCache& cac if (channel >= NATIVE_cbPKT_SPKCACHELINECNT) { return Result::error("Invalid channel number"); } - // Copy from NativeSpikeCache to CentralSpikeCache (same field layout) + // Copy from the buffer (same field layout) auto* spike = static_cast(m_impl->spike_buffer_raw); auto& src = spike->cache[channel]; cache.chid = src.chid; @@ -1608,13 +1608,12 @@ Result ShmemSession::getSpikeCache(uint32_t channel, NativeSpikeCache& cac cache.valid = src.valid; std::memcpy(cache.spkpkt, src.spkpkt, sizeof(cbPKT_SPK) * src.pktcnt); } else { - // TODO: Use adapter instead - if (channel >= central::cbPKT_SPKCACHELINECNT) { - return Result::error("Invalid channel number"); + auto res = m_impl->adapter->getSpikeCache(channel); + if (res.isError()) { + return Result::error(res.error()); } - auto* spike = static_cast(m_impl->spike_buffer_raw); - // // TODO: Implement fromLegacy for cbSPKCACHE - // cache = fromLegacy(spike->cache[channel]); + cache = res.value(); + return Result::ok(); } return Result::ok(); @@ -1641,19 +1640,17 @@ Result ShmemSession::getRecentSpike(uint32_t channel, cbPKT_SPK& spike) co spike = cache.spkpkt[recent_idx]; return Result::ok(true); } else { - // TODO: Use adapter instead - if (channel >= central::cbPKT_SPKCACHELINECNT) { - return Result::error("Invalid channel number"); + // TODO: Duplicate logic + auto res = m_impl->adapter->getSpikeCache(channel); + if (res.isError()) { + return Result::error(res.error()); } - auto* buf = static_cast(m_impl->spike_buffer_raw); - const auto& cache = buf->cache[channel]; + const auto& cache = res.value(); if (cache.valid == 0) { return Result::ok(false); } uint32_t recent_idx = (cache.head == 0) ? (cache.pktcnt - 1) : (cache.head - 1); - // TODO: Use adapter instead - // TODO: Implement fromLegacy - // spike = central::fromLegacy(cache.spkpkt[recent_idx]); + spike = cache.spkpkt[recent_idx]; return Result::ok(true); } } @@ -1820,7 +1817,6 @@ Result ShmemSession::readReceiveBuffer(cbPKT_GENERIC* packets, size_t max_ return Result::ok(); } - // TODO: Use the Central adapter instead const bool needs_translation = (m_impl->layout == ShmemLayout::CENTRAL && m_impl->compat_protocol != CBPROTO_PROTOCOL_CURRENT); @@ -1835,7 +1831,7 @@ Result ShmemSession::readReceiveBuffer(cbPKT_GENERIC* packets, size_t max_ m_impl->status_buffer_raw) { auto gemini = isGeminiSystem(); if (gemini.isOk() && !gemini.value()) { - uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check + uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check the return value if (sysfreq == 0) sysfreq = 30000; uint64_t g = std::gcd(uint64_t(1000000000), uint64_t(sysfreq)); ts_num = 1000000000 / g; From 08abe088d70d858f425019e43af920a92f0ff0e4 Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Tue, 2 Jun 2026 17:44:21 -0400 Subject: [PATCH 22/62] Update file_recording example. --- pycbsdk/examples/{test_recording.py => file_recording.py} | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) rename pycbsdk/examples/{test_recording.py => file_recording.py} (89%) diff --git a/pycbsdk/examples/test_recording.py b/pycbsdk/examples/file_recording.py similarity index 89% rename from pycbsdk/examples/test_recording.py rename to pycbsdk/examples/file_recording.py index ec670f52..eb648091 100644 --- a/pycbsdk/examples/test_recording.py +++ b/pycbsdk/examples/file_recording.py @@ -12,8 +12,8 @@ import sys import time -sys.path.insert(0, str(__import__("pathlib").Path(__file__).resolve().parents[1] / "pycbsdk" / "src")) from pycbsdk import Session +from pycbsdk.src.pycbsdk import Session device_type = sys.argv[1] if len(sys.argv) > 1 else "HUB1" @@ -23,7 +23,7 @@ print(f"Connected. running={session.running}\n") # Start recording -filename = "cerelink_test" +filename = "C:\\Blackrock Microsystems\\cerelink_test" comment = "CereLink recording test" print(f"Starting Central recording: filename='{filename}', comment='{comment}'") session.start_central_recording(filename, comment) @@ -40,5 +40,7 @@ print(" -> stop_central_recording() returned OK") print(" Check Central: file.exe should have stopped.\n") +session.close_central_file_dialog() + session.close() print("Done.") From 6c56626b28b966bd2cac9deb0ace786fb6eaf0e3 Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Tue, 2 Jun 2026 17:55:04 -0400 Subject: [PATCH 23/62] Delete line that somehow added itself. --- pycbsdk/examples/file_recording.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pycbsdk/examples/file_recording.py b/pycbsdk/examples/file_recording.py index eb648091..2e23b838 100644 --- a/pycbsdk/examples/file_recording.py +++ b/pycbsdk/examples/file_recording.py @@ -13,7 +13,6 @@ import time from pycbsdk import Session -from pycbsdk.src.pycbsdk import Session device_type = sys.argv[1] if len(sys.argv) > 1 else "HUB1" From 879fa54389f06e4dcdd6025dce5bc8e253651a2f Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Tue, 2 Jun 2026 18:38:52 -0400 Subject: [PATCH 24/62] Ignore .codegraph --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3a1f1fba..d1606680 100644 --- a/.gitignore +++ b/.gitignore @@ -54,4 +54,5 @@ Release/ upstream */uv.lock -.test_cache/ \ No newline at end of file +.test_cache/ +.codegraph/ \ No newline at end of file From 165b380c597f8fb6b019758b09f782a823d0f8ca Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Tue, 2 Jun 2026 21:55:30 -0400 Subject: [PATCH 25/62] =?UTF-8?q?CMP:=20match=20by=20(bank,=20term),=20hea?= =?UTF-8?q?der-driven=20columns,=20positions=20in=20=C2=B5m?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework how Blackrock .cmp channel-map files are applied to a device's in-memory channel config. Matching: rows are now matched to live channels by the device's own (bank, term) read from chaninfo, instead of by an ordinal channel ID (the old sort-and-assign start_chan+N scheme). start_chan shifts the CMP's bank letters by start_chan/32 banks to target a headstage's banks (129 -> +4 -> bank A maps to device bank E), which makes (bank, term) a globally-unique join key. This is robust to incomplete CMPs. position[]: the four cbPKT_CHANINFO.position slots now carry real geometry {x, y, size, headstage_id} instead of {col, row, bank, elec}. Columns: the //-comment header line immediately before the data (when present) is the ground truth for column order, matched by name (col/c, row/r, bank/b, elec/e, size/s, label/l); no header falls back to the legacy "col row bank electrode [label]" order, so existing files parse unchanged. Units: with no size column and a unit-spaced index grid (every non-zero col/row delta is exactly 1), values are electrode indices -> size 1 and x/y/size scaled by the 400 um Utah-array pitch. With a size column, or non-uniform spacing, values are taken at face value. Labels: stored verbatim; the hs{N}- prefix is dropped since the stored headstage id disambiguates reused labels. pycbsdk/cmp.py is kept in sync with the C++ parser; session.py docstrings corrected. C++ and Python unit tests updated; the hardware-gated nplay integration tests join device readback to parser output via ChanInfoField.BANK/TERM. Co-Authored-By: Claude Opus 4.8 (1M context) --- pycbsdk/src/pycbsdk/cmp.py | 260 +++++++++++++++++++--------- pycbsdk/src/pycbsdk/session.py | 28 +-- pycbsdk/tests/test_cmp.py | 156 +++++++++++++---- pycbsdk/tests/test_configuration.py | 151 +++++++++------- src/cbsdk/src/cmp_parser.cpp | 172 ++++++++++++++---- src/cbsdk/src/cmp_parser.h | 92 +++++++--- src/cbsdk/src/sdk_session.cpp | 78 ++++++--- tests/unit/test_cmp_parser.cpp | 201 +++++++++++++++++---- 8 files changed, 820 insertions(+), 318 deletions(-) diff --git a/pycbsdk/src/pycbsdk/cmp.py b/pycbsdk/src/pycbsdk/cmp.py index 7d272f18..a011d5db 100644 --- a/pycbsdk/src/pycbsdk/cmp.py +++ b/pycbsdk/src/pycbsdk/cmp.py @@ -1,25 +1,39 @@ """Parse and apply Blackrock ``.cmp`` channel-map files. -A ``.cmp`` file describes one headstage's electrode layout. Each data row -has the form:: - - col row bank electrode [label] - -where ``bank`` is a letter (``A``-``H``) and ``electrode`` is 1-based within -the bank. Rows are not guaranteed to be in channel order; this module sorts -by ``(bank, electrode)`` and assigns each sorted row an absolute 1-based -channel ID starting at a caller-supplied ``start_chan``. - -Labels commonly collide across headstages (every file may use -``elec1-1`` … ``elec1-128``), so each label is prefixed with ``"hs{hs_id}-"``. -Pass ``hs_id=0`` (the default) to skip prefixing — appropriate for -single-headstage rigs where the original labels are already unique. +A ``.cmp`` file describes one headstage's electrode layout. A data row holds +``col row bank electrode [size] [label]``. When a column-header comment line +immediately precedes the data (e.g. ``//col row bank elec label`` or +``//col row bank elec size label``) it is the ground truth for column order; +names are matched case-insensitively (col/c, row/r, bank/b, elec/e, size/s, +label/l), so the order is not assumed. With no header the legacy positional +order ``col row bank electrode [label]`` is used. + +Units: when no size column is supplied and the col/row values form a +unit-spaced index grid (every non-zero delta among the distinct col/row values +is exactly 1 — the manufacturer default), they are interpreted as electrode +indices: ``size`` becomes 1 and x/y/size are scaled by the 400 µm Utah-array +electrode pitch. Otherwise (a size column is present, or the spacing is +non-uniform) col/row/size are taken at face value. + +Entries are keyed by device ``(bank, term)`` — the same join key the C++ SDK +uses to match rows to live channels — not by an ordinal channel ID. Each +row's bank letter is shifted by ``start_chan // 32`` banks so a CMP can target +a specific headstage's banks (``start_chan=129`` → ``+4`` banks → CMP bank A +maps to device bank E). + +Labels are stored verbatim. ``hs_id`` identifies the headstage and is stored +in each entry's ``headstage`` field (it is **not** mixed into the label — the +stored headstage id already disambiguates labels reused across headstages). + +This module mirrors the C++ parser in ``src/cbsdk/src/cmp_parser.{h,cpp}``; the +device is configured through that C++ path (``Session.load_channel_map`` hands +it the file path), so this module is for inspection/CLI use. Typical use:: entries = parse_cmp("/path/to/headstage1.cmp", start_chan=1, hs_id=1) - for chan_id, entry in sorted(entries.items()): - print(chan_id, entry.label, entry.position) + for (bank, term), entry in sorted(entries.items()): + print(bank, term, entry.label, entry.x, entry.y) To apply CMPs to a live session, prefer :meth:`pycbsdk.Session.load_channel_map`. @@ -38,78 +52,166 @@ @dataclass(frozen=True) class CmpEntry: - """One parsed CMP row, ready to apply to an absolute channel.""" + """One parsed CMP row. - chan_id: int # 1-based absolute channel - position: tuple[int, int, int, int] # (col, row, bank_idx, electrode) - label: str # prefixed (e.g. "hs1-chan3") + The geometry fields populate ``cbPKT_CHANINFO.position[0..3]``; the device + ``(bank, term)`` are the keys used to find which channel the row applies to. + """ + + x: int # electrode x (µm for index grids, else face value) → position[0] + y: int # electrode y (µm for index grids, else face value) → position[1] + size: int # electrode size, same units as x/y (0 = unspecified) → position[2] + headstage: int # 1-based headstage id (== hs_id; 0 = none) → position[3] + bank: int # 1-based device bank (CMP bank + start_chan // 32); match key + term: int # 1-based terminal within bank (CMP electrode); match key + label: str # verbatim label (e.g. "chan12") + + +# Blackrock Utah arrays have 400 µm inter-electrode spacing; default index grids +# are scaled by this to convert electrode indices to micrometers. +_PITCH_UM = 400 + +_COLUMN_ALIASES = { + "col": "col", + "column": "col", + "c": "col", + "x": "col", + "row": "row", + "r": "row", + "y": "row", + "bank": "bank", + "b": "bank", + "elec": "elec", + "electrode": "elec", + "e": "elec", + "term": "elec", + "terminal": "elec", + "size": "size", + "s": "size", + "sz": "size", + "label": "label", + "l": "label", + "name": "label", +} + + +def _classify_column(tok: str) -> str: + """Map a header token to a column kind (or ``"unknown"``).""" + return _COLUMN_ALIASES.get(tok.strip().strip("',\"").lower(), "unknown") + + +def _resolve_columns(header: str | None) -> tuple[list[str], bool]: + """Resolve column order from a header comment, else the legacy order. + + Returns (columns, has_size). + """ + if header: + cols = [_classify_column(t) for t in header.split()] + if {"col", "row", "bank", "elec"} <= set(cols): + return cols, ("size" in cols) + return ["col", "row", "bank", "elec", "label"], False + + +def _parse_row(tokens: list[str], columns: list[str]) -> dict | None: + """Parse one data row per ``columns``. Returns None to skip a bad row.""" + out = {"col": None, "row": None, "bank": None, "elec": None, "size": 0, "label": ""} + for kind, tok in zip(columns, tokens): + if kind in ("col", "row", "elec", "size"): + try: + out[kind] = int(tok) + except ValueError: + return None + elif kind == "bank": + if not tok[:1].isalpha(): + return None + out["bank"] = ord(tok[0].upper()) - ord("A") + 1 + elif kind == "label": + out["label"] = tok + # unknown: ignore + if None in (out["col"], out["row"], out["bank"], out["elec"]): + return None + return out + + +def _is_unit_spaced_grid(raw: list[dict]) -> bool: + """True if every non-zero delta among distinct col and row values is 1.""" + deltas: set[int] = set() + for key in ("col", "row"): + vals = sorted({r[key] for r in raw}) + deltas.update(b - a for a, b in zip(vals, vals[1:])) + return deltas == {1} def parse_cmp( filepath: str | Path, start_chan: int = 1, hs_id: int = 0, -) -> dict[int, CmpEntry]: - """Parse a single CMP file and assign absolute channel IDs. +) -> dict[tuple[int, int], CmpEntry]: + """Parse a single CMP file into entries keyed by device ``(bank, term)``. Args: filepath: Path to the ``.cmp`` file. - start_chan: 1-based channel assigned to the first sorted row. - hs_id: Headstage identifier; labels are prefixed ``"hs{hs_id}-"``. - Pass ``0`` (the default) to leave labels un-prefixed. + start_chan: 1-based channel selecting the target banks; the CMP's bank + letters are shifted by ``start_chan // 32`` banks (1 → banks A…, + 129 → banks E…). + hs_id: Headstage identifier stored in each entry's ``headstage`` field + (0 = none). Does not affect labels. Returns: - Dict mapping absolute 1-based ``chan_id`` → :class:`CmpEntry`. + Dict mapping ``(bank, term)`` → :class:`CmpEntry`. Raises: - ValueError: If the file is malformed or contains no valid rows. + ValueError: If the file contains no valid rows. FileNotFoundError: If the file does not exist. """ - raw: list[tuple[int, int, int, int, str]] = [] # (col, row, bank_idx, elec, label) - description: str | None = None + raw: list[dict] = [] + description_seen = False + header_candidate: str | None = None + columns: list[str] | None = None + has_size = False with open(filepath) as fh: for line in fh: stripped = line.strip() - if not stripped or stripped.startswith("//"): + if not stripped: continue - if description is None: - description = stripped + if stripped.startswith("//"): + # A comment after the description may be the column header. + if description_seen: + header_candidate = stripped[2:] continue - parts = stripped.split() - if len(parts) < 4: - raise ValueError( - f"{filepath}: malformed row (need 'col row bank elec [label]'): " - f"{line.rstrip()!r}" - ) - bank = parts[2] - if len(bank) != 1 or not bank[0].isalpha(): - raise ValueError(f"{filepath}: invalid bank letter {bank!r}") - bank_idx = ord(bank[0].upper()) - ord("A") + 1 - raw.append( - ( - int(parts[0]), - int(parts[1]), - bank_idx, - int(parts[3]), - parts[4] if len(parts) > 4 else "", - ) - ) + if not description_seen: + description_seen = True + header_candidate = None + continue + # First data row: lock in the column order. + if columns is None: + columns, has_size = _resolve_columns(header_candidate) + entry = _parse_row(stripped.split(), columns) + if entry is not None: + raw.append(entry) if not raw: raise ValueError(f"{filepath}: no valid entries") - raw.sort(key=lambda r: (r[2], r[3])) - - # hs_id == 0 means "single headstage, no prefix needed". - prefix = "" if hs_id == 0 else f"hs{hs_id}-" - entries: dict[int, CmpEntry] = {} - for i, (col, row, bank_idx, elec, label) in enumerate(raw): - chan_id = start_chan + i - entries[chan_id] = CmpEntry( - chan_id=chan_id, - position=(col, row, bank_idx, elec), - label=f"{prefix}{label}", + # No size column + a unit-spaced index grid → electrode indices: size is 1 + # and x/y/size scale by the 400 µm pitch. Otherwise take values at face value. + scale = not has_size and _is_unit_spaced_grid(raw) + factor = _PITCH_UM if scale else 1 + + bank_offset = start_chan // 32 + entries: dict[tuple[int, int], CmpEntry] = {} + for r in raw: + dev_bank = r["bank"] + bank_offset + term = r["elec"] + entries[(dev_bank, term)] = CmpEntry( + x=r["col"] * factor, + y=r["row"] * factor, + size=_PITCH_UM if scale else (r["size"] if has_size else 0), + headstage=hs_id, + bank=dev_bank, + term=term, + label=r["label"], ) return entries @@ -122,9 +224,9 @@ def parse_cmp( def _parse_spec(spec: str) -> tuple[Path, int, int]: """Parse a ``FILE:START_CHAN:HS_ID`` or ``FILE:START_CHAN`` spec. - ``HS_ID`` defaults to ``0`` (no label prefix) when omitted; ``START_CHAN`` - defaults to ``1``. The CLI does not auto-stack headstages — callers must - pass each spec explicitly. + ``HS_ID`` defaults to ``0`` when omitted; ``START_CHAN`` defaults to ``1``. + The CLI does not auto-stack headstages — callers must pass each spec + explicitly. """ parts = spec.split(":") if not parts or not parts[0]: @@ -142,27 +244,26 @@ def _parse_spec(spec: str) -> tuple[Path, int, int]: def _dump(specs: list[tuple[Path, int, int]]) -> None: - """Parse each spec and print its entries, checking for chan_id collisions.""" - seen: dict[int, tuple[Path, str]] = {} + """Parse each spec and print its entries, checking for (bank, term) collisions.""" + seen: dict[tuple[int, int], tuple[Path, str]] = {} for path, start_chan, hs_id in specs: entries = parse_cmp(path, start_chan=start_chan, hs_id=hs_id) print( f"# {path} start_chan={start_chan} hs_id={hs_id} ({len(entries)} chans)" ) - for chan_id in sorted(entries): - e = entries[chan_id] - col, row, bank_idx, elec = e.position - if chan_id in seen: - prev_path, prev_label = seen[chan_id] + for key in sorted(entries): + e = entries[key] + if key in seen: + prev_path, prev_label = seen[key] print( - f" # WARNING: chan {chan_id} already claimed by " + f" # WARNING: (bank {e.bank}, term {e.term}) already claimed by " f"{prev_path.name} as {prev_label!r}", file=sys.stderr, ) - seen[chan_id] = (path, e.label) + seen[key] = (path, e.label) print( - f" chan {chan_id:>3} {e.label:<16s} col={col} row={row} " - f"bank={bank_idx} elec={elec}" + f" bank={e.bank} term={e.term:>2} {e.label:<16s} " + f"x={e.x} y={e.y} size={e.size} hs={e.headstage}" ) @@ -197,7 +298,7 @@ def main(argv: list[str] | None = None) -> int: description=( "Parse or apply Blackrock .cmp channel-map files. " "Each SPEC is FILE[:START_CHAN[:HS_ID]] " - "(defaults: START_CHAN=1, HS_ID=0 → no label prefix)." + "(defaults: START_CHAN=1, HS_ID=0)." ), ) parser.add_argument( @@ -205,10 +306,7 @@ def main(argv: list[str] | None = None) -> int: nargs="+", type=_parse_spec, metavar="SPEC", - help=( - "one or more FILE:START_CHAN:HS_ID specs " - "(START_CHAN default 1, HS_ID default 0 → no prefix)" - ), + help="one or more FILE:START_CHAN:HS_ID specs (START_CHAN default 1, HS_ID default 0)", ) parser.add_argument( "--dump", diff --git a/pycbsdk/src/pycbsdk/session.py b/pycbsdk/src/pycbsdk/session.py index 2c2c39a0..80ad8181 100644 --- a/pycbsdk/src/pycbsdk/session.py +++ b/pycbsdk/src/pycbsdk/session.py @@ -952,16 +952,16 @@ def get_channels_positions( ) -> list[tuple[int, int, int, int]]: """Get positions from all channels matching a type. - Each position is a 4-tuple ``(x, y, z, w)`` of ``int32`` values, - corresponding to the ``cbPKT_CHANINFO.position[4]`` field. + Each position is a 4-tuple of ``int32`` values from the + ``cbPKT_CHANINFO.position[4]`` field. For channels configured from a + CMP the slots are ``(x, y, size, headstage_id)``. Args: channel_type: Channel type filter (e.g., ``ChannelType.FRONTEND``). n_chans: Max channels to query (0 or omit for all). Returns: - List of ``(x, y, z, w)`` tuples (same order as - :meth:`get_matching_channel_ids`). + List of 4-tuples (same order as :meth:`get_matching_channel_ids`). """ _lib = _get_lib() max_chans = _lib.cbsdk_get_max_chans() @@ -1284,22 +1284,24 @@ def configure_channel(self, chan_id: int, *, auto_sync: bool = False, **kwargs): def load_channel_map(self, filepath: str, start_chan: int = 1, hs_id: int = 0): """Load a channel mapping file (.cmp) for one headstage. - CMP files describe one headstage's electrode layout. The file's rows - are sorted by (bank, electrode) and assigned absolute channel IDs - starting at ``start_chan``. Positions are stored locally and overlaid - onto chaninfo; labels are prefixed ``"hs{hs_id}-"`` and pushed to the - device so they persist in chaninfo. + CMP files describe one headstage's electrode layout. Rows are matched + to live channels by device ``(bank, term)``; ``start_chan`` shifts the + file's bank letters by ``start_chan // 32`` banks to select the target + headstage's banks (1 → banks A…, 129 → banks E…). The geometry is + stored locally and overlaid onto chaninfo as + ``position = (x, y, size, headstage_id)``; labels are taken verbatim + and pushed to the device so they persist in chaninfo. Call once per headstage — subsequent calls merge into the overlay, so multiple headstages can coexist on one device. Args: filepath: Path to the .cmp file. - start_chan: 1-based channel to assign the first sorted row. - Typical: 1 for the first headstage, 129 for the second of a + start_chan: 1-based channel selecting the target banks. Typical: + 1 for the first headstage, 129 for the second of a 128-channel headstage, etc. - hs_id: Headstage identifier used to prefix labels. Pass ``0`` - (the default) to leave labels un-prefixed. + hs_id: Headstage identifier stored in the ``headstage`` slot of + ``position`` (0 = none). Does not affect labels. """ _check( _get_lib().cbsdk_session_load_channel_map( diff --git a/pycbsdk/tests/test_cmp.py b/pycbsdk/tests/test_cmp.py index 40057e4a..c684245c 100644 --- a/pycbsdk/tests/test_cmp.py +++ b/pycbsdk/tests/test_cmp.py @@ -10,39 +10,54 @@ from pycbsdk.cmp import CmpEntry, main, parse_cmp -def test_parse_single_file_assigns_chans_from_one(cmp_path: Path): +def test_parse_keys_by_bank_term(cmp_path: Path): + # 96-channel file: banks A, B, C (1..3) each with 32 electrodes. + # start_chan=1 → bank offset 0, so keys are (bank, term) for banks 1..3. entries = parse_cmp(cmp_path) assert len(entries) == 96 - assert set(entries) == set(range(1, 97)) assert all(isinstance(e, CmpEntry) for e in entries.values()) + expected_keys = {(bank, term) for bank in (1, 2, 3) for term in range(1, 33)} + assert set(entries) == expected_keys + for (bank, term), entry in entries.items(): + assert entry.bank == bank + assert entry.term == term -def test_parse_labels_are_prefixed_with_hs_id(cmp_path: Path): +def test_parse_labels_are_verbatim(cmp_path: Path): + # Labels are taken straight from the file; hs_id never prefixes them. entries = parse_cmp(cmp_path, hs_id=3) for entry in entries.values(): - assert entry.label.startswith("hs3-") + assert not entry.label.startswith("hs") + # The file's first electrode (bank A, term 1) is labelled "chan1". + assert entries[(1, 1)].label == "chan1" -def test_parse_sorts_by_bank_then_electrode(cmp_path: Path): - entries = parse_cmp(cmp_path) - # 96-channel file: banks A, B, C each with 32 electrodes. - # chan 1 → (bank_idx=1, elec=1), chan 33 → (bank_idx=2, elec=1), … - assert entries[1].position[2:] == (1, 1) - assert entries[32].position[2:] == (1, 32) - assert entries[33].position[2:] == (2, 1) - assert entries[64].position[2:] == (2, 32) - assert entries[65].position[2:] == (3, 1) - assert entries[96].position[2:] == (3, 32) +def test_hs_id_sets_headstage_not_label(cmp_path: Path): + # Same file with hs_id=0 vs hs_id=3: identical labels, differing headstage. + bare = parse_cmp(cmp_path) + with_hs = parse_cmp(cmp_path, hs_id=3) + for key, entry in with_hs.items(): + assert entry.headstage == 3 + assert bare[key].headstage == 0 + assert entry.label == bare[key].label -def test_parse_start_chan_offsets_chan_ids(cmp_path: Path): +def test_parse_start_chan_offsets_banks(cmp_path: Path): + # start_chan=129 → offset 129 // 32 = 4, so CMP banks A,B,C → device 5,6,7. entries = parse_cmp(cmp_path, start_chan=129, hs_id=2) - assert set(entries) == set(range(129, 129 + 96)) - assert entries[129].position[2:] == (1, 1) # bank A elec 1 - assert all(e.label.startswith("hs2-") for e in entries.values()) - - -def test_parse_unsorted_rows(tmp_path: Path): + assert len(entries) == 96 + assert {bank for bank, _ in entries} == {5, 6, 7} + # chan1 row "0 5 A 1 chan1" → device (bank 5, term 1). Default index grid + # → ×400: x=0, y=2000, size=400. + first = entries[(5, 1)] + assert (first.x, first.y) == (0, 2000) + assert first.size == 400 + assert first.label == "chan1" + assert all(e.headstage == 2 for e in entries.values()) + + +def test_parse_matches_by_bank_term(tmp_path: Path): + # Row order doesn't matter — entries are keyed by (bank, term). f = tmp_path / "unsorted.cmp" f.write_text( "// scratch\n" @@ -53,20 +68,90 @@ def test_parse_unsorted_rows(tmp_path: Path): "0 0 A 2 label_a2\n" ) entries = parse_cmp(f, hs_id=1) - # (A,1), (A,2), (A,3), (B,1) → chans 1..4 - assert entries[1].label == "hs1-label_a1" - assert entries[2].label == "hs1-label_a2" - assert entries[3].label == "hs1-label_a3" - assert entries[4].label == "hs1-label_b1" + assert entries[(1, 1)].label == "label_a1" + assert entries[(1, 2)].label == "label_a2" + assert entries[(1, 3)].label == "label_a3" + assert entries[(2, 1)].label == "label_b1" + assert all(e.headstage == 1 for e in entries.values()) -def test_parse_default_hs_id_omits_prefix(cmp_path: Path): - """Default hs_id=0 leaves labels unmodified.""" - bare = parse_cmp(cmp_path) - prefixed = parse_cmp(cmp_path, hs_id=3) - for chan_id, entry in bare.items(): - assert not entry.label.startswith("hs") - assert prefixed[chan_id].label == f"hs3-{entry.label}" +def test_header_declared_size_takes_face_value(tmp_path: Path): + # A header naming a size column → parsed by name; with size present the + # col/row/size values are taken at face value (no µm scaling). + f = tmp_path / "size.cmp" + f.write_text( + "// scratch\n" + "size test\n" + "//col row bank elec size label\n" + "0 0 A 1 4 elec_a1\n" + "1 0 A 2 7 elec_a2\n" + "2 0 A 3 0 elec_a3\n" + "3 0 A 4 9\n" # size=9, no label + ) + entries = parse_cmp(f, hs_id=5) + assert len(entries) == 4 + + assert entries[(1, 1)].size == 4 + assert entries[(1, 1)].label == "elec_a1" + assert entries[(1, 2)].size == 7 + assert entries[(1, 2)].label == "elec_a2" + assert entries[(1, 3)].size == 0 + assert entries[(1, 3)].label == "elec_a3" + # Size present, no label → empty label. + assert entries[(1, 4)].size == 9 + assert entries[(1, 4)].label == "" + # Face value: x is the raw col (no ×400) because a size column was supplied. + assert (entries[(1, 4)].x, entries[(1, 4)].y) == (3, 0) + + +def test_header_driven_column_order(tmp_path: Path): + # The header determines column order — here columns are reordered and a + # size column is present, so values are taken at face value. + f = tmp_path / "reorder.cmp" + f.write_text( + "// scratch\n" + "reordered columns\n" + "//label bank elec col row size\n" + "foo A 1 7 9 2\n" + ) + entries = parse_cmp(f) + assert len(entries) == 1 + e = entries[(1, 1)] + assert e.label == "foo" + assert (e.x, e.y, e.size) == (7, 9, 2) + + +def test_non_uniform_grid_takes_face_value(tmp_path: Path): + # No size column, but non-uniform spacing (row delta 4) → not a default + # index grid → face value, size 0. + f = tmp_path / "nonuniform.cmp" + f.write_text( + "// scratch\n" + "non-uniform\n" + "//col row bank elec label\n" + "0 0 A 1 e1\n" + "0 4 A 2 e2\n" + ) + entries = parse_cmp(f) + assert entries[(1, 2)].y == 4 # raw row, not scaled + assert entries[(1, 2)].size == 0 + assert entries[(1, 1)].size == 0 + + +def test_default_grid_scales_to_microns(tmp_path: Path): + # No size column + unit-spaced grid → indices scaled ×400, size = 400. + f = tmp_path / "grid.cmp" + f.write_text( + "// scratch\n" + "unit grid\n" + "0 0 A 1 e1\n" + "1 0 A 2 e2\n" + "0 1 A 3 e3\n" + ) + entries = parse_cmp(f) + assert entries[(1, 2)].x == 400 # col 1 → 400 µm + assert entries[(1, 3)].y == 400 # row 1 → 400 µm + assert all(e.size == 400 for e in entries.values()) def test_parse_rejects_missing_file(tmp_path: Path): @@ -106,5 +191,6 @@ def test_main_dump_prints_entries(cmp_path: Path, capsys): stdout = capsys.readouterr().out assert "start_chan=1" in stdout assert "hs_id=1" in stdout - assert "chan 1" in stdout # formatted with width - assert "hs1-" in stdout + assert "bank=1 term= 1" in stdout # formatted (bank, term) + assert "hs=1" in stdout # headstage column + assert "chan1" in stdout # verbatim label, no prefix diff --git a/pycbsdk/tests/test_configuration.py b/pycbsdk/tests/test_configuration.py index 1edbf37c..53210fee 100644 --- a/pycbsdk/tests/test_configuration.py +++ b/pycbsdk/tests/test_configuration.py @@ -884,6 +884,23 @@ def _frontend_view(session): labels = session.get_channels_labels(ChannelType.FRONTEND) return {c: (p, l) for c, p, l in zip(chan_ids, positions, labels)} + @staticmethod + def _frontend_by_bank_term(session): + """Return ``{(bank, term): (chan_id, position, label)}`` for present FE chans. + + CMP entries are keyed by device ``(bank, term)`` (the same join key the + SDK matches on), so device readback is re-keyed the same way to compare. + """ + chan_ids = session.get_matching_channel_ids(ChannelType.FRONTEND) + positions = session.get_channels_positions(ChannelType.FRONTEND) + labels = session.get_channels_labels(ChannelType.FRONTEND) + out = {} + for c, p, l in zip(chan_ids, positions, labels): + bank = session.get_channel_field(c, ChanInfoField.BANK) + term = session.get_channel_field(c, ChanInfoField.TERM) + out[(bank, term)] = (c, p, l) + return out + def test_load_channel_map_smoke(self, nplay_session, cmp_path): """Loading a CMP and syncing succeeds without raising.""" nplay_session.load_channel_map(str(cmp_path)) @@ -902,76 +919,75 @@ def test_positions_match_parsed(self, nplay_session, cmp_path): nplay_session.sync() expected = parse_cmp(str(cmp_path)) - view = self._frontend_view(nplay_session) + view = self._frontend_by_bank_term(nplay_session) intersect = sorted(set(expected) & set(view)) assert intersect, "no FRONTEND chans overlap parsed CMP entries" - for chan_id in intersect: - actual_pos, _ = view[chan_id] - assert actual_pos == expected[chan_id].position, ( - f"chan {chan_id}: expected {expected[chan_id].position}, got {actual_pos}" + for key in intersect: + _, actual_pos, _ = view[key] + e = expected[key] + assert actual_pos == (e.x, e.y, e.size, e.headstage), ( + f"{key}: expected {(e.x, e.y, e.size, e.headstage)}, got {actual_pos}" ) def test_labels_round_trip_through_device(self, nplay_session, cmp_path): - """After load + sync, labels read back through the device match the prefix.""" + """After load + sync, labels read back through the device verbatim.""" from pycbsdk.cmp import parse_cmp nplay_session.load_channel_map(str(cmp_path), hs_id=7) nplay_session.sync() expected = parse_cmp(str(cmp_path), hs_id=7) - view = self._frontend_view(nplay_session) + view = self._frontend_by_bank_term(nplay_session) intersect = sorted(set(expected) & set(view)) assert intersect - for chan_id in intersect: - _, actual_label = view[chan_id] - assert actual_label == expected[chan_id].label, ( - f"chan {chan_id}: expected {expected[chan_id].label!r}, " - f"got {actual_label!r}" + for key in intersect: + _, _, actual_label = view[key] + assert actual_label == expected[key].label, ( + f"{key}: expected {expected[key].label!r}, got {actual_label!r}" ) - # All labels carry the hs7 prefix we requested. - assert actual_label.startswith("hs7-") + # Labels are verbatim — hs_id never prefixes them. + assert not actual_label.startswith("hs") - def test_hs_id_prefix_changes_label(self, nplay_session, cmp_path): - """Loading with a different hs_id rewrites labels on the device.""" + def test_hs_id_sets_headstage(self, nplay_session, cmp_path): + """hs_id lands in the headstage slot of position, not the label.""" from pycbsdk.cmp import parse_cmp - cmp_chans = set(parse_cmp(str(cmp_path))) - nplay_session.load_channel_map(str(cmp_path), hs_id=4) nplay_session.sync() - before = self._frontend_view(nplay_session) - + before = self._frontend_by_bank_term(nplay_session) + covered = sorted(set(parse_cmp(str(cmp_path), hs_id=4)) & set(before)) + assert covered + for key in covered: + _, pos, label = before[key] + assert pos[3] == 4 # headstage slot (position[3]) carries hs_id + assert not label.startswith("hs") + + # Reloading with a different hs_id updates the headstage slot; the + # (verbatim) label is unchanged. nplay_session.load_channel_map(str(cmp_path), hs_id=5) nplay_session.sync() - after = self._frontend_view(nplay_session) - - # Only chans the CMP covers carry the hs prefix; the rest keep their - # device-default labels. Restrict the check to covered chans that are - # also visible on the device. - relabeled = sorted(set(before) & set(after) & cmp_chans) - assert relabeled - for chan_id in relabeled: - assert before[chan_id][1].startswith("hs4-") - assert after[chan_id][1].startswith("hs5-") - # The original (un-prefixed) label is unchanged across the two loads. - assert before[chan_id][1].split("-", 1)[1] == after[chan_id][1].split("-", 1)[1] + after = self._frontend_by_bank_term(nplay_session) + for key in covered: + _, pos, label = after[key] + assert pos[3] == 5 + assert label == before[key][2] def test_start_chan_assignment( self, nplay_session, manufacturer_cmp_path ): """Loading the same file at start_chan=1 vs 129 produces matching layouts. - Parser output for ``(start_chan=1, hs_id=1)`` and ``(start_chan=129, - hs_id=2)`` must agree on (col, row, bank, electrode) at offset chans — - e.g. chan 1 under hs1 has the same position as chan 129 under hs2 — and - whichever of those chans the device actually reports must reflect the - right layout. + The two loads target disjoint banks (start_chan=129 shifts by 4 banks), + so an electrode at ``(bank, term)`` under hs1 corresponds to + ``(bank+4, term)`` under hs2 with identical geometry/label and differing + only in the headstage id. Whichever chans the device reports must + reflect the right layout. """ from pycbsdk.cmp import parse_cmp - # Load both headstages so chans 1.. and 129.. are populated. + # Load both headstages so banks A.. and E.. are populated. nplay_session.load_channel_map( str(manufacturer_cmp_path), start_chan=1, hs_id=1 ) @@ -983,24 +999,26 @@ def test_start_chan_assignment( hs1 = parse_cmp(str(manufacturer_cmp_path), start_chan=1, hs_id=1) hs2 = parse_cmp(str(manufacturer_cmp_path), start_chan=129, hs_id=2) - # Shared invariant: corresponding (chan, chan+128) entries describe the - # same electrode and differ only in the hs prefix. - for sorted_idx in range(min(len(hs1), len(hs2))): - assert hs1[1 + sorted_idx].position == hs2[129 + sorted_idx].position - assert hs1[1 + sorted_idx].label == hs2[129 + sorted_idx].label.replace( - "hs2-", "hs1-", 1 - ) + # Shared invariant: (bank, term) and (bank+4, term) describe the same + # electrode and differ only in the headstage id. + for (bank, term), e1 in hs1.items(): + e2 = hs2[(bank + 4, term)] + assert (e1.x, e1.y, e1.size) == (e2.x, e2.y, e2.size) + assert e1.label == e2.label + assert e1.headstage == 1 and e2.headstage == 2 # And on the device, every present FE chan that falls in either range # matches its parsed entry. - view = self._frontend_view(nplay_session) - for chan_id, (pos, label) in view.items(): - if chan_id in hs1: - assert pos == hs1[chan_id].position - assert label == hs1[chan_id].label - elif chan_id in hs2: - assert pos == hs2[chan_id].position - assert label == hs2[chan_id].label + view = self._frontend_by_bank_term(nplay_session) + for key, (_, pos, label) in view.items(): + if key in hs1: + e = hs1[key] + elif key in hs2: + e = hs2[key] + else: + continue + assert pos == (e.x, e.y, e.size, e.headstage) + assert label == e.label def test_overlay_survives_chanrep_refresh(self, nplay_session, cmp_path): """A CHANREP echoed back from the device should not erase our overlay. @@ -1016,11 +1034,12 @@ def test_overlay_survives_chanrep_refresh(self, nplay_session, cmp_path): nplay_session.sync() expected = parse_cmp(str(cmp_path), hs_id=9) - view = self._frontend_view(nplay_session) - for chan_id in sorted(set(expected) & set(view)): - pos, label = view[chan_id] - assert pos == expected[chan_id].position - assert label == expected[chan_id].label + view = self._frontend_by_bank_term(nplay_session) + for key in sorted(set(expected) & set(view)): + _, pos, label = view[key] + e = expected[key] + assert pos == (e.x, e.y, e.size, e.headstage) + assert label == e.label def test_clear_channel_map_resets_labels(self, nplay_session, cmp_path): """clear_channel_map() reverts labels to the device default ("chanN").""" @@ -1030,19 +1049,21 @@ def test_clear_channel_map_resets_labels(self, nplay_session, cmp_path): nplay_session.sync() expected = parse_cmp(str(cmp_path), hs_id=11) - view_before = self._frontend_view(nplay_session) + view_before = self._frontend_by_bank_term(nplay_session) loaded = sorted(set(expected) & set(view_before)) assert loaded - for chan_id in loaded: - _, label = view_before[chan_id] - assert label.startswith("hs11-") + # Labels are verbatim from the CMP (no hs prefix). + for key in loaded: + _, _, label = view_before[key] + assert label == expected[key].label + assert not label.startswith("hs") nplay_session.clear_channel_map() nplay_session.sync() - view_after = self._frontend_view(nplay_session) - for chan_id in loaded: - _, label = view_after[chan_id] + view_after = self._frontend_by_bank_term(nplay_session) + for key in loaded: + chan_id, _, label = view_after[key] assert label == f"chan{chan_id}", ( f"chan {chan_id}: expected default label, got {label!r}" ) diff --git a/src/cbsdk/src/cmp_parser.cpp b/src/cbsdk/src/cmp_parser.cpp index e0287a00..8b580822 100644 --- a/src/cbsdk/src/cmp_parser.cpp +++ b/src/cbsdk/src/cmp_parser.cpp @@ -7,22 +7,117 @@ #include #include -#include +#include #include +#include +#include #include namespace cbsdk { namespace { +/// Blackrock Utah arrays have 400 µm inter-electrode spacing. Default index +/// grids (unit-spaced col/row indices, no explicit size) are scaled by this to +/// convert electrode indices to micrometers. +constexpr int32_t kElectrodePitchUm = 400; + +/// A column kind in a CMP data row. +enum class Column { Col, Row, Bank, Elec, Size, Label, Unknown }; + +/// Classify a header token (case-insensitive, punctuation-stripped). +Column classifyColumn(std::string tok) { + for (auto& c : tok) c = static_cast(std::tolower(static_cast(c))); + while (!tok.empty() && !std::isalnum(static_cast(tok.back()))) tok.pop_back(); + while (!tok.empty() && !std::isalnum(static_cast(tok.front()))) tok.erase(tok.begin()); + if (tok == "col" || tok == "column" || tok == "c" || tok == "x") return Column::Col; + if (tok == "row" || tok == "r" || tok == "y") return Column::Row; + if (tok == "bank" || tok == "b") return Column::Bank; + if (tok == "elec" || tok == "electrode" || tok == "e" || tok == "term" || tok == "terminal") + return Column::Elec; + if (tok == "size" || tok == "s" || tok == "sz") return Column::Size; + if (tok == "label" || tok == "l" || tok == "name") return Column::Label; + return Column::Unknown; +} + +/// Resolve the column order from a candidate header line. Returns true and +/// fills @c columns / @c has_size if the line names all of col/row/bank/elec. +bool columnsFromHeader(const std::string& header, std::vector& columns, bool& has_size) { + std::istringstream hs(header); + std::vector cols; + std::string tok; + while (hs >> tok) cols.push_back(classifyColumn(tok)); + auto has = [&](Column c) { return std::find(cols.begin(), cols.end(), c) != cols.end(); }; + if (has(Column::Col) && has(Column::Row) && has(Column::Bank) && has(Column::Elec)) { + has_size = has(Column::Size); // before the move — has() reads cols + columns = std::move(cols); + return true; + } + return false; +} + struct RawEntry { int32_t col; int32_t row; int32_t bank_idx; ///< 1-based (A=1, B=2, …) int32_t electrode; ///< 1-based within bank + int32_t size; ///< from a size column, else 0 std::string label; }; +/// Parse one data row per the resolved column order. Returns false (skip row) +/// if any required column (col/row/bank/elec) is missing or unparseable. +bool parseRow(const std::string& line, const std::vector& columns, RawEntry& out) { + std::istringstream iss(line); + std::vector toks; + std::string t; + while (iss >> t) toks.push_back(std::move(t)); + + out = RawEntry{0, 0, 0, 0, 0, ""}; + bool got_col = false, got_row = false, got_bank = false, got_elec = false; + for (size_t i = 0; i < columns.size(); ++i) { + if (i >= toks.size()) break; // optional trailing columns simply absent + const std::string& tk = toks[i]; + try { + switch (columns[i]) { + case Column::Col: out.col = std::stoi(tk); got_col = true; break; + case Column::Row: out.row = std::stoi(tk); got_row = true; break; + case Column::Elec: out.electrode = std::stoi(tk); got_elec = true; break; + case Column::Size: out.size = std::stoi(tk); break; + case Column::Bank: + if (tk.empty() || !std::isalpha(static_cast(tk[0]))) return false; + out.bank_idx = std::toupper(static_cast(tk[0])) - 'A' + 1; + got_bank = true; + break; + case Column::Label: out.label = tk; break; + case Column::Unknown: break; // consume and ignore + } + } catch (...) { + return false; // non-numeric in a numeric column + } + } + return got_col && got_row && got_bank && got_elec; +} + +/// True if every non-zero delta among the distinct col and row values is +/// exactly 1 — i.e. a contiguous, unit-spaced index grid (the manufacturer +/// default), as opposed to values already in physical units. +bool isUnitSpacedGrid(const std::vector& raw) { + std::set cols, rows; + for (const auto& r : raw) { cols.insert(r.col); rows.insert(r.row); } + std::set deltas; + for (const auto* s : {&cols, &rows}) { + int32_t prev = 0; + bool first = true; + for (int32_t v : *s) { + if (!first) deltas.insert(v - prev); + prev = v; + first = false; + } + } + return deltas.size() == 1 && *deltas.begin() == 1; +} + } // namespace cbutil::Result parseCmpFile( @@ -35,7 +130,11 @@ cbutil::Result parseCmpFile( } std::vector raw; - bool found_description = false; + bool description_seen = false; + std::string header_candidate; // most recent comment line after the description + std::vector columns; + bool columns_resolved = false; + bool has_size = false; std::string line; while (std::getline(file, line)) { @@ -44,54 +143,61 @@ cbutil::Result parseCmpFile( line.pop_back(); } if (line.empty()) continue; - if (line.size() >= 2 && line[0] == '/' && line[1] == '/') continue; - // First non-comment line is the description — skip it - if (!found_description) { - found_description = true; + if (line.size() >= 2 && line[0] == '/' && line[1] == '/') { + // A comment after the description may be the column header. + if (description_seen) header_candidate = line.substr(2); continue; } - // Data line: col row bank electrode [label] - std::istringstream iss(line); - int32_t col = 0, row = 0, electrode = 0; - std::string bank_str; - if (!(iss >> col >> row >> bank_str >> electrode)) continue; - if (bank_str.empty() || !std::isalpha(static_cast(bank_str[0]))) continue; - - int32_t bank_idx = std::toupper(static_cast(bank_str[0])) - 'A' + 1; + // First non-comment line is the description — skip it. + if (!description_seen) { + description_seen = true; + header_candidate.clear(); + continue; + } - std::string label; - iss >> label; // optional + // First data row: lock in the column order from the header if it names + // the required columns, else fall back to the legacy positional order. + if (!columns_resolved) { + if (header_candidate.empty() || !columnsFromHeader(header_candidate, columns, has_size)) { + columns = {Column::Col, Column::Row, Column::Bank, Column::Elec, Column::Label}; + has_size = false; + } + columns_resolved = true; + } - raw.push_back({col, row, bank_idx, electrode, std::move(label)}); + RawEntry entry; + if (parseRow(line, columns, entry)) raw.push_back(std::move(entry)); } if (raw.empty()) { return cbutil::Result::error("No valid entries found in CMP file: " + filepath); } - // Rows are not guaranteed to be in channel order. Sort so the Nth - // sorted entry maps to (start_chan + N). - std::sort(raw.begin(), raw.end(), [](const RawEntry& a, const RawEntry& b) { - if (a.bank_idx != b.bank_idx) return a.bank_idx < b.bank_idx; - return a.electrode < b.electrode; - }); + // When no size column is supplied and the col/row values form a unit-spaced + // index grid, treat them as electrode indices: size is 1 and all of + // x/y/size scale by the 400 µm electrode pitch. Otherwise take col/row (and + // any supplied size) at face value. + const bool scale = !has_size && isUnitSpacedGrid(raw); + const int32_t factor = scale ? kElectrodePitchUm : 1; - // hs_id == 0 means "single headstage, no prefix needed". - std::string prefix = (hs_id == 0) - ? std::string{} - : "hs" + std::to_string(hs_id) + "-"; + // start_chan selects the target banks: shift every CMP bank by this many + // banks (32 terminals each). start_chan 1 → +0 (banks A…), 129 → +4 (E…). + const int32_t bank_offset = static_cast(start_chan / 32); CmpEntries entries; entries.reserve(raw.size()); - for (size_t i = 0; i < raw.size(); ++i) { - const auto& r = raw[i]; - uint32_t chan_id = start_chan + static_cast(i); + for (auto& r : raw) { CmpEntry entry; - entry.position = {r.col, r.row, r.bank_idx, r.electrode}; - entry.label = prefix + r.label; - entries.emplace(chan_id, std::move(entry)); + entry.x = r.col * factor; + entry.y = r.row * factor; + entry.size = scale ? kElectrodePitchUm : (has_size ? r.size : 0); + entry.headstage = static_cast(hs_id); + entry.bank = r.bank_idx + bank_offset; + entry.term = r.electrode; + entry.label = std::move(r.label); + entries.emplace(cmpKey(entry.bank, entry.term), std::move(entry)); } return cbutil::Result::ok(std::move(entries)); diff --git a/src/cbsdk/src/cmp_parser.h b/src/cbsdk/src/cmp_parser.h index 68c297e9..1b772eb0 100644 --- a/src/cbsdk/src/cmp_parser.h +++ b/src/cbsdk/src/cmp_parser.h @@ -5,24 +5,41 @@ /// CMP files define electrode positions for a single headstage. Format: /// - Lines starting with // are comments /// - First non-comment line is a description string -/// - Subsequent lines: col row bank electrode [label] -/// - col: 0-based column (left to right) -/// - row: 0-based row (bottom to top) +/// - An optional column-header comment immediately before the data names the +/// columns, e.g. "//col row bank elec label" or "//col row bank elec size +/// label". When present it is the ground truth for column order; column +/// names are matched case-insensitively (col/c, row/r, bank/b, elec/e, +/// size/s, label/l), so the order is not assumed. With no header the +/// legacy positional order "col row bank electrode [label]" is used. +/// - Data rows hold: +/// - col: column index or coordinate (left to right) +/// - row: row index or coordinate (bottom to top) /// - bank: letter A-H (32 electrodes per bank within the headstage) /// - electrode: 1-based electrode within bank (1-32) +/// - size: electrode size, same units as col/row (optional) /// - label: free-form label (optional) /// -/// Rows in a CMP file are not guaranteed to be in channel order. The parser -/// sorts by (bank_letter, electrode) and assigns each sorted entry a 1-based -/// absolute channel ID starting at @c start_chan. This is how a CMP gets -/// applied to a contiguous range of channels — callers control the starting -/// channel so multiple CMPs (one per headstage) can be loaded on one device. +/// Units: when no size column is supplied and the col/row values form a +/// unit-spaced index grid (every non-zero delta among the distinct col/row +/// values is exactly 1 — the manufacturer default), they are interpreted as +/// electrode indices: size becomes 1 and x/y/size are scaled by the 400 µm +/// Utah-array electrode pitch. Otherwise (a size column is present, or the +/// spacing is non-uniform) col/row/size are taken at face value. /// -/// Labels are reused across CMP files (e.g. "elec1-1"..."elec1-128" in every -/// file), so the parser prefixes each label with "hs{hs_id}-" to keep them -/// unique on the device. Pass @c hs_id == 0 to skip prefixing entirely -/// (sensible for single-headstage rigs where the original labels are already -/// unique). +/// Each parsed row carries the electrode geometry plus the device (bank, term) +/// it belongs to. Entries are matched to live channels by (bank, term) — read +/// from the device's own chaninfo — rather than by an ordinal channel ID, so a +/// CMP that is missing channels still lands on the right ones. @c start_chan +/// selects which physical banks the CMP targets: the CMP's bank letters are +/// offset by @c start_chan/32 banks. e.g. a @c start_chan of 129 (= 4 banks) +/// maps CMP bank A onto device bank E, bank C onto bank G, and so on. This is +/// how multiple CMPs (one per headstage) land on disjoint banks of one device. +/// +/// @c hs_id identifies the headstage and is stored in each entry's +/// @c headstage field (→ position[3]). Labels are taken verbatim from the CMP +/// file — even though labels are reused across CMP files (e.g. "elec1-1" in +/// every headstage's file), the stored headstage id disambiguates them, so no +/// "hs{hs_id}-" label prefix is applied. /// /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -30,36 +47,55 @@ #define CBSDK_CMP_PARSER_H #include -#include #include #include #include namespace cbsdk { -/// One parsed CMP entry, ready to apply to an absolute channel. +/// One parsed CMP entry. The geometry fields (@c x, @c y, @c size, +/// @c headstage) populate cbPKT_CHANINFO.position[0..3]; the device +/// (@c bank, @c term) are the keys used to find which channel that is. struct CmpEntry { - std::array position; ///< {col, row, bank_letter_idx, electrode} - std::string label; ///< prefixed label (e.g. "hs1-chan12") + int32_t x = 0; ///< electrode x (µm for index grids, else face value) → position[0] + int32_t y = 0; ///< electrode y (µm for index grids, else face value) → position[1] + int32_t size = 0; ///< electrode size, same units as x/y (0 = unspecified) → position[2] + int32_t headstage = 0; ///< 1-based headstage id (== hs_id; 0 = none) → position[3] + int32_t bank = 0; ///< 1-based device bank (CMP bank + start_chan/32); match key + int32_t term = 0; ///< 1-based terminal within bank (CMP electrode); match key + std::string label; ///< verbatim label (e.g. "chan12") }; -/// Map from 1-based absolute channel ID to parsed entry. +/// Encode a (bank, term) pair into a single CmpEntries lookup key. +/// @c bank is the 1-based device bank, @c term the 1-based terminal within +/// it. Collision-free for the valid hardware ranges (bank ≤ 8, term ≤ 32). +inline uint32_t cmpKey(const int32_t bank, const int32_t term) { + return (static_cast(bank) << 8) | (static_cast(term) & 0xFFu); +} + +/// Map from cmpKey(bank, term) to the parsed entry for that device terminal. using CmpEntries = std::unordered_map; -/// Parse a CMP file and assign each row an absolute channel ID. +/// Parse a CMP file into entries keyed by device (bank, term). +/// +/// Columns come from the header comment immediately before the data when +/// present (matched by name, any order), else the legacy "col row bank +/// electrode [label]" order. col/row/size are scaled from electrode indices to +/// µm for a unit-spaced index grid with no size column, and taken at face value +/// otherwise (see the file header for details). /// -/// Rows are sorted by (bank_letter, electrode) and the Nth sorted row is -/// assigned @c chan_id = @c start_chan + N. Labels get an "hs{hs_id}-" -/// prefix. +/// Each row's CMP bank letter is offset by @c start_chan/32 banks to produce +/// the target device bank; the electrode becomes the terminal. Callers join +/// these against live chaninfo by (bank, term). /// /// @param filepath Path to the .cmp file. -/// @param start_chan 1-based channel to assign the first sorted entry. -/// Typical values: 1 (single headstage), 129 (second +/// @param start_chan 1-based channel selecting the target banks: the CMP is +/// shifted by @c start_chan/32 banks. Typical values: 1 +/// (banks A…, single headstage), 129 (banks E…, second /// headstage of 128 channels), etc. -/// @param hs_id Headstage identifier used to prefix labels. The final -/// label is "hs{hs_id}-{original_label}". Pass 0 (the -/// default) to leave labels un-prefixed. -/// @return Map of chan_id → CmpEntry on success, or error message. +/// @param hs_id Headstage identifier stored in each entry's @c headstage +/// field (→ position[3]; 0 = none). Does not affect labels. +/// @return Map of cmpKey(bank, term) → CmpEntry on success, or error message. cbutil::Result parseCmpFile( const std::string& filepath, uint32_t start_chan = 1, diff --git a/src/cbsdk/src/sdk_session.cpp b/src/cbsdk/src/sdk_session.cpp index ea267fc9..f6bf1867 100644 --- a/src/cbsdk/src/sdk_session.cpp +++ b/src/cbsdk/src/sdk_session.cpp @@ -281,8 +281,8 @@ struct SdkSession::Impl { std::array channel_type_cache; bool channel_cache_valid = false; - // CMP (channel mapping) overlay. Keyed by 1-based absolute chan_id → - // {position[4], prefixed label}. Loaded rarely, read on every CHANREP. + // CMP (channel mapping) overlay. Keyed by cmpKey(bank, term) → + // {x, y, size, headstage, label}. Loaded rarely, read on every CHANREP. CmpEntries cmp_entries; std::mutex cmp_mutex; @@ -379,16 +379,15 @@ struct SdkSession::Impl { return Result::error("Channel information not available"); } - /// Apply CMP overlay (position + label) to all existing chaninfo entries. - /// Called after loading a CMP file. Writes the updated chaninfo to shmem. - /// Label push to the device is done separately by SdkSession::loadChannelMap. + /// Apply CMP overlay (position + label) to every channel whose device + /// (bank, term) matches a loaded CMP entry. Called after loading a CMP + /// file. Writes the updated chaninfo to shmem. Label push to the device + /// is done separately by SdkSession::loadChannelMap. void applyCmpToAllChannels() { std::lock_guard lock(cmp_mutex); if (cmp_entries.empty()) return; - for (const auto& [chan_id, entry] : cmp_entries) { - if (chan_id < 1 || chan_id > cbMAXCHANS) continue; - + for (uint32_t chan_id = 1; chan_id <= cbMAXCHANS; ++chan_id) { // Snapshot chaninfo to avoid racing with the receive thread cbPKT_CHANINFO ci{}; bool valid = false; @@ -401,8 +400,15 @@ struct SdkSession::Impl { } if (!valid) continue; - std::memcpy(ci.position, entry.position.data(), sizeof(int32_t) * 4); - std::strncpy(ci.label, entry.label.c_str(), sizeof(ci.label) - 1); + // Match the CMP row by the channel's own (bank, term). + auto it = cmp_entries.find(cmpKey(ci.bank, ci.term)); + if (it == cmp_entries.end()) continue; + + ci.position[0] = it->second.x; + ci.position[1] = it->second.y; + ci.position[2] = it->second.size; + ci.position[3] = it->second.headstage; + std::strncpy(ci.label, it->second.label.c_str(), sizeof(ci.label) - 1); ci.label[sizeof(ci.label) - 1] = '\0'; if (shmem_session) { @@ -937,11 +943,13 @@ Result SdkSession::start() { { std::lock_guard lock(impl->cmp_mutex); if (!impl->cmp_entries.empty()) { - auto it = impl->cmp_entries.find(chaninfo_copy.chan); + auto it = impl->cmp_entries.find( + cmpKey(chaninfo_copy.bank, chaninfo_copy.term)); if (it != impl->cmp_entries.end()) { - std::memcpy(chaninfo_copy.position, - it->second.position.data(), - sizeof(int32_t) * 4); + chaninfo_copy.position[0] = it->second.x; + chaninfo_copy.position[1] = it->second.y; + chaninfo_copy.position[2] = it->second.size; + chaninfo_copy.position[3] = it->second.headstage; std::strncpy(chaninfo_copy.label, it->second.label.c_str(), sizeof(chaninfo_copy.label) - 1); @@ -2063,14 +2071,11 @@ Result SdkSession::loadChannelMap( return Result::error(parse_result.error()); } - // Snapshot labels before moving entries into the overlay map — we - // need a stable list to push to the device outside the cmp_mutex. - std::vector> labels_to_push; + // Merge parsed entries (keyed by device bank/term) into the overlay map. { std::lock_guard lock(m_impl->cmp_mutex); - for (auto& [chan_id, entry] : parse_result.value()) { - labels_to_push.emplace_back(chan_id, entry.label); - m_impl->cmp_entries[chan_id] = std::move(entry); + for (auto& [key, entry] : parse_result.value()) { + m_impl->cmp_entries[key] = std::move(entry); } } @@ -2079,8 +2084,22 @@ Result SdkSession::loadChannelMap( // Push labels to the device so they persist in chaninfo and are echoed // back in future CHANREP packets. Positions aren't persisted by the - // device, so no analogous push for position. + // device, so no analogous push for position. We discover which channels + // matched a CMP row by joining live chaninfo on (bank, term) — the same + // way applyCmpToAllChannels does — then snapshot (chan_id, label) so the + // network sends happen outside cmp_mutex. if (m_impl->device_session || m_impl->shmem_session) { + std::vector> labels_to_push; + { + std::lock_guard lock(m_impl->cmp_mutex); + for (uint32_t chan_id = 1; chan_id <= cbMAXCHANS; ++chan_id) { + auto info = getChanInfo(chan_id); + if (info.isError() || info.value().chan == 0) continue; + auto it = m_impl->cmp_entries.find(cmpKey(info.value().bank, info.value().term)); + if (it == m_impl->cmp_entries.end()) continue; + labels_to_push.emplace_back(chan_id, it->second.label); + } + } for (const auto& [chan_id, label] : labels_to_push) { auto info = getChanInfo(chan_id); if (info.isError()) continue; @@ -2097,15 +2116,20 @@ Result SdkSession::loadChannelMap( } Result SdkSession::clearChannelMap() { - // Snapshot the previously-mapped channel ids and drop the overlay so - // future CHANREPs land in chaninfo as the device sends them. Any further - // applyCmpToAllChannels() call is now a no-op. + // Find which channels currently match a loaded CMP entry (by bank/term), + // then drop the overlay so future CHANREPs land in chaninfo as the device + // sends them. Any further applyCmpToAllChannels() call is now a no-op. std::vector mapped_chans; { std::lock_guard lock(m_impl->cmp_mutex); - mapped_chans.reserve(m_impl->cmp_entries.size()); - for (const auto& [chan_id, _] : m_impl->cmp_entries) { - mapped_chans.push_back(chan_id); + if (!m_impl->cmp_entries.empty()) { + for (uint32_t chan_id = 1; chan_id <= cbMAXCHANS; ++chan_id) { + auto info = getChanInfo(chan_id); + if (info.isError() || info.value().chan == 0) continue; + if (m_impl->cmp_entries.count(cmpKey(info.value().bank, info.value().term))) { + mapped_chans.push_back(chan_id); + } + } } m_impl->cmp_entries.clear(); } diff --git a/tests/unit/test_cmp_parser.cpp b/tests/unit/test_cmp_parser.cpp index c38cfc46..5ef4296c 100644 --- a/tests/unit/test_cmp_parser.cpp +++ b/tests/unit/test_cmp_parser.cpp @@ -27,10 +27,27 @@ TEST(CmpParser, Parse8Channel) { const auto& entries = result.value(); EXPECT_EQ(entries.size(), 8u); - // Defaults: start_chan=1, hs_id=0 → chans 1..8, no label prefix. - std::set chans; - for (const auto& [chan_id, _] : entries) chans.insert(chan_id); - EXPECT_EQ(chans, std::set({1, 2, 3, 4, 5, 6, 7, 8})); + // 8ch file is bank A, electrodes 1..8. Default start_chan=1 → bank offset 0, + // so entries are keyed by (bank 1, term 1..8). + for (int32_t term = 1; term <= 8; ++term) { + auto it = entries.find(cbsdk::cmpKey(1, term)); + ASSERT_NE(it, entries.end()) << "missing (bank 1, term " << term << ")"; + EXPECT_EQ(it->second.bank, 1); + EXPECT_EQ(it->second.term, term); + } + + // No size column + unit-spaced index grid → scaled by the 400 µm pitch. + // Row "0 1 A 1" → x=0, y=400; row "0 0 A 5" → x=0, y=0. + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 1)).x, 0); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 1)).y, 400); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 5)).x, 0); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 5)).y, 0); + + // Default index grid → size is 1 electrode-pitch (400 µm); hs_id=0 → headstage 0. + for (const auto& [_, entry] : entries) { + EXPECT_EQ(entry.size, 400); + EXPECT_EQ(entry.headstage, 0); + } // hs_id=0 leaves labels un-prefixed. for (const auto& [_, entry] : entries) { @@ -38,17 +55,116 @@ TEST(CmpParser, Parse8Channel) { } } -TEST(CmpParser, HsIdZeroLeavesLabelsUnprefixed) { - // Same file, default hs_id=0 vs explicit hs_id=3, comparing stripped labels. +TEST(CmpParser, HeaderDeclaredSizeColumnTakesFaceValue) { + // A header naming a size column → columns parsed by name; with size present + // the col/row/size values are taken at face value (no µm scaling). + auto path = (std::filesystem::temp_directory_path() / "cmp_size_tmp.cmp").string(); + { + std::ofstream out(path); + out << "// scratch file\n" + << "size column test map\n" + << "//col row bank elec size label\n" + << "0 0 A 1 4 elec_a1\n" // size=4, label=elec_a1 + << "1 0 A 2 7 elec_a2\n" // size=7, label=elec_a2 + << "2 0 A 3 0 elec_a3\n" // size=0, label=elec_a3 + << "3 0 A 4 9\n"; // size=9, no label + } + + auto result = cbsdk::parseCmpFile(path, /*start_chan=*/1, /*hs_id=*/5); + ASSERT_TRUE(result.isOk()) << result.error(); + + const auto& entries = result.value(); + ASSERT_EQ(entries.size(), 4u); + + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 1)).size, 4); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 1)).label, "elec_a1"); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 2)).size, 7); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 2)).label, "elec_a2"); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 3)).size, 0); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 3)).label, "elec_a3"); + + // Size present, no label → empty label. + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 4)).size, 9); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 4)).label, ""); + + // Face value: x is the raw col (no ×400) because a size column was supplied. + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 4)).x, 3); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 4)).y, 0); + + // hs_id seeds the headstage field (→ position[3]). + for (const auto& [_, entry] : entries) { + EXPECT_EQ(entry.headstage, 5); + } + + std::filesystem::remove(path); +} + +TEST(CmpParser, HeaderDrivenColumnOrder) { + // The header determines column order — here columns are reordered and a + // size column is present, so values are taken at face value. + auto path = (std::filesystem::temp_directory_path() / "cmp_reorder_tmp.cmp").string(); + { + std::ofstream out(path); + out << "// scratch file\n" + << "reordered columns map\n" + << "//label bank elec col row size\n" + << "foo A 1 7 9 2\n"; + } + + auto result = cbsdk::parseCmpFile(path); + ASSERT_TRUE(result.isOk()) << result.error(); + + const auto& entries = result.value(); + ASSERT_EQ(entries.size(), 1u); + const auto& e = entries.at(cbsdk::cmpKey(1, 1)); + EXPECT_EQ(e.label, "foo"); + EXPECT_EQ(e.bank, 1); + EXPECT_EQ(e.term, 1); + EXPECT_EQ(e.x, 7); + EXPECT_EQ(e.y, 9); + EXPECT_EQ(e.size, 2); +} + +TEST(CmpParser, NonUniformGridTakesFaceValue) { + // No size column, but the row spacing is non-uniform (delta 4, not 1), so + // it is not a default index grid → values taken at face value, size 0. + auto path = (std::filesystem::temp_directory_path() / "cmp_nonuniform_tmp.cmp").string(); + { + std::ofstream out(path); + out << "// scratch file\n" + << "non-uniform grid map\n" + << "//col row bank elec label\n" + << "0 0 A 1 e1\n" + << "0 4 A 2 e2\n"; // row delta 4 → not unit-spaced + } + + auto result = cbsdk::parseCmpFile(path); + ASSERT_TRUE(result.isOk()) << result.error(); + + const auto& entries = result.value(); + ASSERT_EQ(entries.size(), 2u); + // Face value: y is the raw row (4), not scaled; size stays unspecified (0). + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 2)).y, 4); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 2)).size, 0); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 1)).size, 0); +} + +TEST(CmpParser, HsIdSetsHeadstageNotLabel) { + // hs_id is stored in the headstage field, never mixed into the label. + // The same file parsed with hs_id=0 vs hs_id=3 yields identical labels, + // differing only in the headstage value. auto bare = cbsdk::parseCmpFile(testFile("8ChannelDefaultMapping.cmp")); auto with_hs = cbsdk::parseCmpFile(testFile("8ChannelDefaultMapping.cmp"), 1, 3); ASSERT_TRUE(bare.isOk()); ASSERT_TRUE(with_hs.isOk()); - for (const auto& [chan_id, prefixed] : with_hs.value()) { - const auto it = bare.value().find(chan_id); + for (const auto& [key, entry] : with_hs.value()) { + const auto it = bare.value().find(key); ASSERT_NE(it, bare.value().end()); - EXPECT_EQ(prefixed.label, "hs3-" + it->second.label); + EXPECT_EQ(entry.label, it->second.label); // label unchanged by hs_id + EXPECT_EQ(entry.headstage, 3); + EXPECT_EQ(it->second.headstage, 0); + EXPECT_NE(entry.label.substr(0, 2), "hs"); // no "hs3-" prefix } } @@ -59,23 +175,22 @@ TEST(CmpParser, Parse128Channel) { const auto& entries = result.value(); EXPECT_EQ(entries.size(), 128u); - // 128 contiguous channel IDs starting at 1. - for (uint32_t ch = 1; ch <= 128; ++ch) { - ASSERT_TRUE(entries.count(ch)) << "missing chan " << ch; + // 128ch = banks A..D (1..4), each electrodes 1..32. start_chan=1 → offset 0. + for (int32_t bank = 1; bank <= 4; ++bank) { + for (int32_t term = 1; term <= 32; ++term) { + auto it = entries.find(cbsdk::cmpKey(bank, term)); + ASSERT_NE(it, entries.end()) + << "missing (bank " << bank << ", term " << term << ")"; + EXPECT_EQ(it->second.bank, bank); + EXPECT_EQ(it->second.term, term); + } } - - // Bank layout after sort: chan 1 → (bank 1, elec 1), chan 33 → (bank 2, elec 1), - // chan 65 → (bank 3, elec 1), chan 128 → (bank 4, elec 32). - EXPECT_EQ(entries.at(1).position[2], 1); - EXPECT_EQ(entries.at(1).position[3], 1); - EXPECT_EQ(entries.at(33).position[2], 2); - EXPECT_EQ(entries.at(33).position[3], 1); - EXPECT_EQ(entries.at(128).position[2], 4); - EXPECT_EQ(entries.at(128).position[3], 32); } -TEST(CmpParser, StartChanOffsetsChanIds) { - // Second headstage: same 96-channel CMP mapped to chans 129..224. +TEST(CmpParser, StartChanOffsetsBanks) { + // Second headstage: same 96-channel CMP (banks A,B,C) mapped onto the + // device's second set of banks. start_chan=129 → offset 129/32 = 4, so + // CMP bank A→E (5), B→F (6), C→G (7). auto result = cbsdk::parseCmpFile( testFile("96ChannelDefaultMapping.cmp"), /*start_chan=*/129, /*hs_id=*/2); ASSERT_TRUE(result.isOk()) << result.error(); @@ -83,24 +198,39 @@ TEST(CmpParser, StartChanOffsetsChanIds) { const auto& entries = result.value(); EXPECT_EQ(entries.size(), 96u); - std::set chans; - for (const auto& [chan_id, _] : entries) chans.insert(chan_id); - EXPECT_EQ(*chans.begin(), 129u); - EXPECT_EQ(*chans.rbegin(), 129u + 95u); + // Every entry sits in device banks 5, 6 or 7. + std::set banks; + for (const auto& [_, entry] : entries) banks.insert(entry.bank); + EXPECT_EQ(banks, std::set({5, 6, 7})); + // chan1 row "0 5 A 1" → device (bank 5, term 1). Default index grid → ×400, + // so x=0, y=2000, size=400. + auto first = entries.find(cbsdk::cmpKey(5, 1)); + ASSERT_NE(first, entries.end()); + EXPECT_EQ(first->second.x, 0); + EXPECT_EQ(first->second.y, 2000); + EXPECT_EQ(first->second.size, 400); + + // chan96 row "15 0 C 32" → device (bank 7, term 32). + ASSERT_TRUE(entries.count(cbsdk::cmpKey(7, 32))); + + // Labels are verbatim from the file (no "hs2-" prefix); hs_id lands in + // the headstage field instead. + EXPECT_EQ(entries.at(cbsdk::cmpKey(5, 1)).label, "chan1"); for (const auto& [_, entry] : entries) { - EXPECT_EQ(entry.label.substr(0, 4), "hs2-"); + EXPECT_NE(entry.label.substr(0, 2), "hs"); + EXPECT_EQ(entry.headstage, 2); // hs_id → headstage (position[3]) } } -TEST(CmpParser, SortsOutOfOrderRows) { - // Synthesize a tiny CMP whose rows are deliberately out of (bank, elec) order. +TEST(CmpParser, MatchesRowsByBankAndTerm) { + // Rows given out of (bank, elec) order — order no longer matters since + // entries are keyed by (bank, term), not an ordinal channel id. auto path = (std::filesystem::temp_directory_path() / "cmp_unsorted_tmp.cmp").string(); { std::ofstream out(path); out << "// scratch file\n" << "unsorted test map\n" - // Rows given in reverse electrode order within bank A, then bank B first. << "0 0 B 1 label_b1\n" << "0 0 A 3 label_a3\n" << "0 0 A 1 label_a1\n" @@ -114,11 +244,10 @@ TEST(CmpParser, SortsOutOfOrderRows) { const auto& entries = result.value(); ASSERT_EQ(entries.size(), 4u); - // Sort puts (A,1), (A,2), (A,3), (B,1) at chans 1..4. - EXPECT_EQ(entries.at(1).label, "hs1-label_a1"); - EXPECT_EQ(entries.at(2).label, "hs1-label_a2"); - EXPECT_EQ(entries.at(3).label, "hs1-label_a3"); - EXPECT_EQ(entries.at(4).label, "hs1-label_b1"); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 1)).label, "label_a1"); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 2)).label, "label_a2"); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 3)).label, "label_a3"); + EXPECT_EQ(entries.at(cbsdk::cmpKey(2, 1)).label, "label_b1"); std::filesystem::remove(path); } From 64e327f53ae704bf82e184cd70484e5b680eda59 Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Wed, 3 Jun 2026 17:28:57 -0400 Subject: [PATCH 26/62] CMP: Check for unit-indexing (min-spacing) rather than all grid spacing, because some arrays will have gaps in their grid and therefore have >1 spacing in some dimensions. --- pycbsdk/src/pycbsdk/cmp.py | 28 ++++++++++++++--------- pycbsdk/tests/test_cmp.py | 31 ++++++++++++++++++++----- src/cbsdk/src/cmp_parser.cpp | 21 ++++++++--------- src/cbsdk/src/cmp_parser.h | 12 +++++----- tests/unit/test_cmp_parser.cpp | 41 +++++++++++++++++++++++++++++----- 5 files changed, 96 insertions(+), 37 deletions(-) diff --git a/pycbsdk/src/pycbsdk/cmp.py b/pycbsdk/src/pycbsdk/cmp.py index a011d5db..dd35f917 100644 --- a/pycbsdk/src/pycbsdk/cmp.py +++ b/pycbsdk/src/pycbsdk/cmp.py @@ -9,11 +9,13 @@ order ``col row bank electrode [label]`` is used. Units: when no size column is supplied and the col/row values form a -unit-spaced index grid (every non-zero delta among the distinct col/row values -is exactly 1 — the manufacturer default), they are interpreted as electrode -indices: ``size`` becomes 1 and x/y/size are scaled by the 400 µm Utah-array -electrode pitch. Otherwise (a size column is present, or the spacing is -non-uniform) col/row/size are taken at face value. +unit-indexed grid (the smallest non-zero delta among the distinct col/row +values is 1 — so some electrodes are adjacent, the manufacturer default), they +are interpreted as electrode indices: ``size`` becomes 1 and x/y/size are +scaled by the 400 µm Utah-array electrode pitch. Larger deltas (e.g. the gap +between two arrays in a multi-array map) are allowed and scale through. +Otherwise (a size column is present, or no two electrodes are unit-spaced) +col/row/size are taken at face value. Entries are keyed by device ``(bank, term)`` — the same join key the C++ SDK uses to match rows to live channels — not by an ordinal channel ID. Each @@ -133,13 +135,17 @@ def _parse_row(tokens: list[str], columns: list[str]) -> dict | None: return out -def _is_unit_spaced_grid(raw: list[dict]) -> bool: - """True if every non-zero delta among distinct col and row values is 1.""" +def _is_unit_indexed_grid(raw: list[dict]) -> bool: + """True if the smallest non-zero delta among distinct col/row values is 1. + + A single unit step is enough — larger deltas (e.g. the gap between two + arrays in a multi-array map) are allowed and scale through. + """ deltas: set[int] = set() for key in ("col", "row"): vals = sorted({r[key] for r in raw}) deltas.update(b - a for a, b in zip(vals, vals[1:])) - return deltas == {1} + return 1 in deltas def parse_cmp( @@ -194,9 +200,9 @@ def parse_cmp( if not raw: raise ValueError(f"{filepath}: no valid entries") - # No size column + a unit-spaced index grid → electrode indices: size is 1 - # and x/y/size scale by the 400 µm pitch. Otherwise take values at face value. - scale = not has_size and _is_unit_spaced_grid(raw) + # No size column + a unit-indexed grid → electrode indices: size is 1 and + # x/y/size scale by the 400 µm pitch. Otherwise take values at face value. + scale = not has_size and _is_unit_indexed_grid(raw) factor = _PITCH_UM if scale else 1 bank_offset = start_chan // 32 diff --git a/pycbsdk/tests/test_cmp.py b/pycbsdk/tests/test_cmp.py index c684245c..a605fdef 100644 --- a/pycbsdk/tests/test_cmp.py +++ b/pycbsdk/tests/test_cmp.py @@ -121,13 +121,13 @@ def test_header_driven_column_order(tmp_path: Path): assert (e.x, e.y, e.size) == (7, 9, 2) -def test_non_uniform_grid_takes_face_value(tmp_path: Path): - # No size column, but non-uniform spacing (row delta 4) → not a default - # index grid → face value, size 0. - f = tmp_path / "nonuniform.cmp" +def test_no_unit_step_takes_face_value(tmp_path: Path): + # No size column and no two electrodes unit-spaced (only delta is 4) → not + # a unit-indexed grid → face value, size 0. + f = tmp_path / "nounit.cmp" f.write_text( "// scratch\n" - "non-uniform\n" + "no unit step\n" "//col row bank elec label\n" "0 0 A 1 e1\n" "0 4 A 2 e2\n" @@ -154,6 +154,27 @@ def test_default_grid_scales_to_microns(tmp_path: Path): assert all(e.size == 400 for e in entries.values()) +def test_multi_array_gap_still_scales(tmp_path: Path): + # Unit-indexed grid with an inter-array gap (rows 0,1,2 then 6 → deltas + # {1,4}). The unit step means it's still indices → scales ×400; the gap + # scales through (row 6 → 2400 µm). Mirrors a real two-array .cmp. + f = tmp_path / "gap.cmp" + f.write_text( + "// scratch\n" + "multi-array gap\n" + "//col row bank elec label\n" + "0 0 A 1 e1\n" + "0 1 A 2 e2\n" + "0 2 A 3 e3\n" + "0 6 A 4 e4\n" + ) + entries = parse_cmp(f) + assert entries[(1, 1)].y == 0 + assert entries[(1, 2)].y == 400 + assert entries[(1, 4)].y == 2400 # gap scaled through + assert all(e.size == 400 for e in entries.values()) + + def test_parse_rejects_missing_file(tmp_path: Path): with pytest.raises(FileNotFoundError): parse_cmp(tmp_path / "nope.cmp") diff --git a/src/cbsdk/src/cmp_parser.cpp b/src/cbsdk/src/cmp_parser.cpp index 8b580822..1e7b22e9 100644 --- a/src/cbsdk/src/cmp_parser.cpp +++ b/src/cbsdk/src/cmp_parser.cpp @@ -99,10 +99,11 @@ bool parseRow(const std::string& line, const std::vector& columns, RawEn return got_col && got_row && got_bank && got_elec; } -/// True if every non-zero delta among the distinct col and row values is -/// exactly 1 — i.e. a contiguous, unit-spaced index grid (the manufacturer -/// default), as opposed to values already in physical units. -bool isUnitSpacedGrid(const std::vector& raw) { +/// True if the smallest non-zero delta among the distinct col and row values is +/// 1 — i.e. a unit-indexed electrode grid, as opposed to values already in +/// physical units. Larger deltas are allowed (e.g. the gap between two arrays +/// in a multi-array map), so a single unit step anywhere is enough. +bool isUnitIndexedGrid(const std::vector& raw) { std::set cols, rows; for (const auto& r : raw) { cols.insert(r.col); rows.insert(r.row); } std::set deltas; @@ -115,7 +116,7 @@ bool isUnitSpacedGrid(const std::vector& raw) { first = false; } } - return deltas.size() == 1 && *deltas.begin() == 1; + return deltas.count(1) > 0; } } // namespace @@ -175,11 +176,11 @@ cbutil::Result parseCmpFile( return cbutil::Result::error("No valid entries found in CMP file: " + filepath); } - // When no size column is supplied and the col/row values form a unit-spaced - // index grid, treat them as electrode indices: size is 1 and all of - // x/y/size scale by the 400 µm electrode pitch. Otherwise take col/row (and - // any supplied size) at face value. - const bool scale = !has_size && isUnitSpacedGrid(raw); + // When no size column is supplied and the col/row values form a unit-indexed + // grid (some adjacent electrodes are 1 apart), treat them as electrode + // indices: size is 1 and all of x/y/size scale by the 400 µm electrode + // pitch. Otherwise take col/row (and any supplied size) at face value. + const bool scale = !has_size && isUnitIndexedGrid(raw); const int32_t factor = scale ? kElectrodePitchUm : 1; // start_chan selects the target banks: shift every CMP bank by this many diff --git a/src/cbsdk/src/cmp_parser.h b/src/cbsdk/src/cmp_parser.h index 1b772eb0..78da9ad6 100644 --- a/src/cbsdk/src/cmp_parser.h +++ b/src/cbsdk/src/cmp_parser.h @@ -20,11 +20,13 @@ /// - label: free-form label (optional) /// /// Units: when no size column is supplied and the col/row values form a -/// unit-spaced index grid (every non-zero delta among the distinct col/row -/// values is exactly 1 — the manufacturer default), they are interpreted as -/// electrode indices: size becomes 1 and x/y/size are scaled by the 400 µm -/// Utah-array electrode pitch. Otherwise (a size column is present, or the -/// spacing is non-uniform) col/row/size are taken at face value. +/// unit-indexed grid (the smallest non-zero delta among the distinct col/row +/// values is 1 — so some electrodes are adjacent, the manufacturer default), +/// they are interpreted as electrode indices: size becomes 1 and x/y/size are +/// scaled by the 400 µm Utah-array electrode pitch. Larger deltas (e.g. the +/// gap between two arrays in a multi-array map) are allowed and scale through. +/// Otherwise (a size column is present, or no two electrodes are unit-spaced) +/// col/row/size are taken at face value. /// /// Each parsed row carries the electrode geometry plus the device (bank, term) /// it belongs to. Entries are matched to live channels by (bank, term) — read diff --git a/tests/unit/test_cmp_parser.cpp b/tests/unit/test_cmp_parser.cpp index 5ef4296c..f44756d6 100644 --- a/tests/unit/test_cmp_parser.cpp +++ b/tests/unit/test_cmp_parser.cpp @@ -125,17 +125,17 @@ TEST(CmpParser, HeaderDrivenColumnOrder) { EXPECT_EQ(e.size, 2); } -TEST(CmpParser, NonUniformGridTakesFaceValue) { - // No size column, but the row spacing is non-uniform (delta 4, not 1), so - // it is not a default index grid → values taken at face value, size 0. - auto path = (std::filesystem::temp_directory_path() / "cmp_nonuniform_tmp.cmp").string(); +TEST(CmpParser, NoUnitStepTakesFaceValue) { + // No size column and no two electrodes are unit-spaced (only delta is 4), + // so it is not a unit-indexed grid → values taken at face value, size 0. + auto path = (std::filesystem::temp_directory_path() / "cmp_nounit_tmp.cmp").string(); { std::ofstream out(path); out << "// scratch file\n" - << "non-uniform grid map\n" + << "no unit step map\n" << "//col row bank elec label\n" << "0 0 A 1 e1\n" - << "0 4 A 2 e2\n"; // row delta 4 → not unit-spaced + << "0 4 A 2 e2\n"; // only delta is 4 → no unit step } auto result = cbsdk::parseCmpFile(path); @@ -149,6 +149,35 @@ TEST(CmpParser, NonUniformGridTakesFaceValue) { EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 1)).size, 0); } +TEST(CmpParser, MultiArrayGapStillScales) { + // A unit-indexed grid with an inter-array gap (rows 0,1,2 then 6 → deltas + // {1,4}). The unit step means it's still electrode indices, so it scales by + // 400 µm; the gap scales through (row 6 → 2400 µm). + auto path = (std::filesystem::temp_directory_path() / "cmp_gap_tmp.cmp").string(); + { + std::ofstream out(path); + out << "// scratch file\n" + << "multi-array gap map\n" + << "//col row bank elec label\n" + << "0 0 A 1 e1\n" + << "0 1 A 2 e2\n" + << "0 2 A 3 e3\n" + << "0 6 A 4 e4\n"; // gap of 4 between the two arrays + } + + auto result = cbsdk::parseCmpFile(path); + ASSERT_TRUE(result.isOk()) << result.error(); + + const auto& entries = result.value(); + ASSERT_EQ(entries.size(), 4u); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 1)).y, 0); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 2)).y, 400); + EXPECT_EQ(entries.at(cbsdk::cmpKey(1, 4)).y, 2400); // gap scaled through + for (const auto& [_, entry] : entries) EXPECT_EQ(entry.size, 400); + + std::filesystem::remove(path); +} + TEST(CmpParser, HsIdSetsHeadstageNotLabel) { // hs_id is stored in the headstage field, never mixed into the label. // The same file parsed with hs_id=0 vs hs_id=3 yields identical labels, From 5d89f0d94a18f8f7df116322d689611d633c64d8 Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Wed, 3 Jun 2026 19:28:40 -0400 Subject: [PATCH 27/62] pycbsdk - ignore shared objects in case we put one here for quick testing --- pycbsdk/.gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pycbsdk/.gitignore b/pycbsdk/.gitignore index f3c1db24..7528c0ae 100644 --- a/pycbsdk/.gitignore +++ b/pycbsdk/.gitignore @@ -1 +1,6 @@ src/pycbsdk/_version.py +*.dylib +*.dll +*.bin +*.so +*.a From 74a876354ac80026f14076ea5161e92de1e25d3e Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Fri, 12 Jun 2026 00:23:11 -0400 Subject: [PATCH 28/62] Add more socket error reporting --- src/cbdev/src/protocol_detector.cpp | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/cbdev/src/protocol_detector.cpp b/src/cbdev/src/protocol_detector.cpp index 57d2e05f..b51fa6cc 100644 --- a/src/cbdev/src/protocol_detector.cpp +++ b/src/cbdev/src/protocol_detector.cpp @@ -59,6 +59,19 @@ namespace cbdev { +/// Format the last socket error as " (errno N: description)" (POSIX) or +/// " (winsock err N)" (Windows). Captures the error code immediately, so call +/// at the very first opportunity after the failing syscall. +static std::string lastSocketErrorSuffix() { +#ifdef _WIN32 + const int err = WSAGetLastError(); + return " (winsock err " + std::to_string(err) + ")"; +#else + const int err = errno; + return " (errno " + std::to_string(err) + ": " + std::strerror(err) + ")"; +#endif +} + /// State shared between main thread and receive thread struct DetectionState { std::atomic send_config{false}; @@ -355,11 +368,12 @@ Result detectProtocol(const char* device_addr, uint16_t send_po } if (bind(sock, reinterpret_cast(&client_sockaddr), sizeof(client_sockaddr)) == SOCKET_ERROR_VALUE) { + const std::string err_suffix = lastSocketErrorSuffix(); closesocket(sock); #ifdef _WIN32 WSACleanup(); #endif - return Result::error("Failed to bind probe socket"); + return Result::error("Failed to bind probe socket" + err_suffix); } // Set socket timeout for receive (for the thread) @@ -447,28 +461,34 @@ Result detectProtocol(const char* device_addr, uint16_t send_po // Send the runlev packets if (sendto(sock, reinterpret_cast(&runlev), sizeof(cbPKT_SYSINFO), 0, reinterpret_cast(&device_sockaddr), sizeof(device_sockaddr)) == SOCKET_ERROR_VALUE) { + const std::string err_suffix = lastSocketErrorSuffix(); state.done = true; recv_thread.join(); closesocket(sock); - return Result::error("Failed to send 4.1 runlev packet"); + return Result::error("Failed to send 4.1 runlev packet to " + + std::string(device_addr) + ":" + std::to_string(send_port) + err_suffix); } std::this_thread::sleep_for(std::chrono::microseconds(50)); if (sendto(sock, reinterpret_cast(runlev_400), sizeof(runlev_400), 0, reinterpret_cast(&device_sockaddr), sizeof(device_sockaddr)) == SOCKET_ERROR_VALUE) { + const std::string err_suffix = lastSocketErrorSuffix(); state.done = true; recv_thread.join(); closesocket(sock); - return Result::error("Failed to send 4.0 runlev packet"); + return Result::error("Failed to send 4.0 runlev packet to " + + std::string(device_addr) + ":" + std::to_string(send_port) + err_suffix); } std::this_thread::sleep_for(std::chrono::microseconds(50)); if (sendto(sock, reinterpret_cast(runlev_311), sizeof(runlev_311), 0, reinterpret_cast(&device_sockaddr), sizeof(device_sockaddr)) == SOCKET_ERROR_VALUE) { + const std::string err_suffix = lastSocketErrorSuffix(); state.done = true; recv_thread.join(); closesocket(sock); - return Result::error("Failed to send 3.11 runlev packet"); + return Result::error("Failed to send 3.11 runlev packet to " + + std::string(device_addr) + ":" + std::to_string(send_port) + err_suffix); } // Wait for receive thread to detect protocol or timeout From 891c05790351d1526ab5a9f100b406d9c75190ba Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Fri, 12 Jun 2026 00:23:49 -0400 Subject: [PATCH 29/62] Get a little more info from some example apps --- examples/GeminiExample/gemini_example.cpp | 5 +++++ pycbsdk/examples/session_info.py | 11 ++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/examples/GeminiExample/gemini_example.cpp b/examples/GeminiExample/gemini_example.cpp index e3b20354..d73d090d 100644 --- a/examples/GeminiExample/gemini_example.cpp +++ b/examples/GeminiExample/gemini_example.cpp @@ -150,6 +150,11 @@ int main(int argc, char* argv[]) { hub3->type = cbsdk::DeviceType::HUB3; devices.push_back(std::move(hub3)); + auto nplay = std::make_unique(); + nplay->name = "NPlay"; + nplay->type = cbsdk::DeviceType::NPLAY; + devices.push_back(std::move(nplay)); + try { // === Clean up any stale shared memory segments === #ifndef _WIN32 diff --git a/pycbsdk/examples/session_info.py b/pycbsdk/examples/session_info.py index ecf31323..32dda3fb 100644 --- a/pycbsdk/examples/session_info.py +++ b/pycbsdk/examples/session_info.py @@ -9,7 +9,7 @@ import sys import time -sys.path.insert(0, str(__import__("pathlib").Path(__file__).resolve().parents[1] / "pycbsdk" / "src")) +sys.path.insert(0, str(__import__("pathlib").Path(__file__).resolve().parents[1] / "src")) from pycbsdk import Session, DeviceType, ProtocolVersion device_type = sys.argv[1] if len(sys.argv) > 1 else "NPLAY" @@ -47,3 +47,12 @@ def on_event(header, data): print(f" clock_offset_ns: {session.clock_offset_ns}") print(f" clock_uncertainty: {session.clock_uncertainty_ns}") print(f" stats: {session.stats}") + + print("\nChannel config:") + n = session.num_analog_chans() + active = {ch: session.get_channel_smpgroup(ch) for ch in range(1, n + 1)} + active = {ch: g for ch, g in active.items() if g > 0} + print(f" {len(active)}/{n} analog channels in a sample group") + for ch, g in active.items(): + print(f" ch {ch:3d} ({session.get_channel_label(ch)}): " + f"group {g}, spkopts 0x{session.get_channel_spkopts(ch):x}") From 870ef9a589f6da2d0ddf8c89994cc14f109aa994 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Mon, 8 Jun 2026 11:15:56 -0600 Subject: [PATCH 30/62] Change call sites in cbsdk for the new ShmemSession API --- src/cbsdk/src/sdk_session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cbsdk/src/sdk_session.cpp b/src/cbsdk/src/sdk_session.cpp index f6bf1867..746dda18 100644 --- a/src/cbsdk/src/sdk_session.cpp +++ b/src/cbsdk/src/sdk_session.cpp @@ -395,7 +395,7 @@ struct SdkSession::Impl { const auto* p = device_session->getChanInfo(chan_id); if (p && p->chan > 0) { ci = *p; valid = true; } } else if (shmem_session) { - auto r = shmem_session->getChanInfo(chan_id - 1); + auto r = shmem_session->getChanInfo(chan_id); if (r.isOk() && r.value().chan > 0) { ci = r.value(); valid = true; } } if (!valid) continue; From 0bc700328e662258533aa77aae6b6293c331f1a7 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Thu, 18 Jun 2026 11:20:00 -0600 Subject: [PATCH 31/62] FIX: Stack overflow from translating large structs --- src/cbsdk/src/sdk_session.cpp | 38 +- .../include/cbshm/central_types/adapters.h | 714 +++++++++--------- src/cbshm/include/cbshm/central_types/v3_11.h | 9 + src/cbshm/include/cbshm/central_types/v4_0.h | 9 + src/cbshm/include/cbshm/central_types/v4_1.h | 9 + src/cbshm/include/cbshm/central_types/v4_2.h | 9 + src/cbshm/include/cbshm/shmem_session.h | 3 +- src/cbshm/src/central_adapters/v3_11.cpp | 599 ++++++--------- src/cbshm/src/central_adapters/v4_0.cpp | 607 ++++++--------- src/cbshm/src/central_adapters/v4_1.cpp | 606 ++++++--------- src/cbshm/src/central_adapters/v4_2.cpp | 606 ++++++--------- src/cbshm/src/shmem_session.cpp | 117 ++- 12 files changed, 1377 insertions(+), 1949 deletions(-) diff --git a/src/cbsdk/src/sdk_session.cpp b/src/cbsdk/src/sdk_session.cpp index 746dda18..250d56af 100644 --- a/src/cbsdk/src/sdk_session.cpp +++ b/src/cbsdk/src/sdk_session.cpp @@ -294,6 +294,20 @@ struct SdkSession::Impl { channel_cache_valid = true; } + // Helper: get chaninfo for a 1-based channel ID + Result getChanInfo(const uint32_t chan_id) const { + // Prefer shmem over device_config because CMP position overlays are + // written to shmem (device_config is owned by the receive thread and + // we avoid writing to it from other threads). + if (shmem_session && chan_id >= 1 && chan_id <= cbMAXCHANS) { + return shmem_session->getChanInfo(chan_id); + } + // Fallback to device_config (no shmem available) + if (device_session) + return Result::ok(*device_session->getChanInfo(chan_id)); + return Result::error("Channel information not available"); + } + // Clock sync periodic probing std::chrono::steady_clock::time_point last_clock_probe_time{}; @@ -366,19 +380,6 @@ struct SdkSession::Impl { // (e.g., during the handshake phase in start()). std::atomic shutting_down{false}; - Result getChanInfo(const uint32_t chan_id) const { - // Prefer shmem over device_config because CMP position overlays are - // written to shmem (device_config is owned by the receive thread and - // we avoid writing to it from other threads). - if (shmem_session && chan_id >= 1 && chan_id <= cbMAXCHANS) { - return shmem_session->getChanInfo(chan_id); - } - // Fallback to device_config (no shmem available) - if (device_session) - return Result::ok(*device_session->getChanInfo(chan_id)); - return Result::error("Channel information not available"); - } - /// Apply CMP overlay (position + label) to every channel whose device /// (bank, term) matches a loaded CMP entry. Called after loading a CMP /// file. Writes the updated chaninfo to shmem. Label push to the device @@ -1410,16 +1411,7 @@ Result SdkSession::getSysInfo() const { } Result SdkSession::getChanInfo(const uint32_t chan_id) const { - // Prefer shmem over device_config because CMP position overlays are - // written to shmem (device_config is owned by the receive thread and - // we avoid writing to it from other threads). - if (m_impl->shmem_session && chan_id >= 1 && chan_id <= cbMAXCHANS) { - return m_impl->shmem_session->getChanInfo(chan_id - 1); - } - // Fallback to device_config (no shmem available) - if (m_impl->device_session) - return Result::ok(*m_impl->device_session->getChanInfo(chan_id - 1)); - return Result::error("Channel information not available"); + return m_impl->getChanInfo(chan_id); } Result SdkSession::getGroupInfo(uint32_t group_id) const { diff --git a/src/cbshm/include/cbshm/central_types/adapters.h b/src/cbshm/include/cbshm/central_types/adapters.h index 63afbf1a..6922ef64 100644 --- a/src/cbshm/include/cbshm/central_types/adapters.h +++ b/src/cbshm/include/cbshm/central_types/adapters.h @@ -53,14 +53,14 @@ class CentralAdapterBase { } template - static void copyArr(LHS_T(&lhs)[lhs_n], const RHS_T(&rhs)[rhs_n], const A* adapter, LHS_T(A::*translation_func)(const RHS_T&) const) { + static void copyArr(LHS_T(&lhs)[lhs_n], const RHS_T(&rhs)[rhs_n], const A* adapter, void(A::*translation_func)(LHS_T&, const RHS_T&) const) { if (lhs_n <= rhs_n) { for (size_t i = 0; i < lhs_n; ++i) { - lhs[i] = (adapter->*translation_func)(rhs[i]); + (adapter->*translation_func)(lhs[i], rhs[i]); } } else { for (size_t i = 0; i < rhs_n; ++i) { - lhs[i] = (adapter->*translation_func)(rhs[i]); + (adapter->*translation_func)(lhs[i], rhs[i]); } std::memset(lhs + rhs_n, 0, (lhs_n - rhs_n) * sizeof(LHS_T)); } @@ -89,7 +89,7 @@ class CentralAdapterBase { } template - static const void copyArr2D(LHS_T(&lhs)[lhs_ny][lhs_nx], const RHS_T(&rhs)[rhs_ny][rhs_nx], const A* adapter, LHS_T(A::*translation_func)(const RHS_T&) const) { + static const void copyArr2D(LHS_T(&lhs)[lhs_ny][lhs_nx], const RHS_T(&rhs)[rhs_ny][rhs_nx], const A* adapter, void(A::*translation_func)(LHS_T&, const RHS_T&) const) { if (lhs_ny <= rhs_ny) { for (size_t i = 0; i < lhs_ny; ++i) { copyArr(lhs[i], rhs[i], adapter, translation_func); @@ -139,15 +139,15 @@ class CentralAdapterBase { /////////////////////////////////////////////////////////////////////////////////////////////// /// Config read operations - virtual Result<::cbPKT_PROCINFO> getProcInfo() const = 0; - virtual Result<::cbPKT_BANKINFO> getBankInfo(uint32_t bank) const = 0; - virtual Result<::cbPKT_FILTINFO> getFilterInfo(uint32_t filter) const = 0; - virtual Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const = 0; - virtual Result<::cbPKT_SYSINFO> getSysInfo() const = 0; - virtual Result<::cbPKT_GROUPINFO> getGroupInfo(uint32_t group_idx) const = 0; - virtual Result getConfigBuffer() const = 0; - virtual Result getPcStatus() const = 0; - virtual Result getSpikeCache(uint32_t channel_idx) const = 0; + virtual Result getProcInfo(::cbPKT_PROCINFO& buf) const = 0; + virtual Result getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const = 0; + virtual Result getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const = 0; + virtual Result getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const = 0; + virtual Result getSysInfo(::cbPKT_SYSINFO& buf) const = 0; + virtual Result getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const = 0; + virtual Result getConfigBuffer(NativeConfigBuffer& buf) const = 0; + virtual Result getPcStatus(NativePCStatus& buf) const = 0; + virtual Result getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const = 0; /// Config write operations virtual Result setProcInfo(const ::cbPKT_PROCINFO& info) = 0; @@ -191,83 +191,83 @@ class Adapter : public CentralAdapterBase { cbPcStatus* status; cbSPKBUFF* spike; - ::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) const; - ::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) const; - ::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) const; - ::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) const; - ::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) const; - ::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) const; - ::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) const; - ::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg) const; - ::cbSCALING fromLegacy(const cbSCALING& leg) const; - ::cbFILTDESC fromLegacy(const cbFILTDESC& leg) const; - ::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) const; - ::cbHOOP fromLegacy(const cbHOOP& leg) const; - ::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) const; - ::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) const; - ::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) const; - ::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg) const; - ::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) const; - ::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) const; - ::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) const; - ::cbAdaptControl fromLegacy(const cbAdaptControl& leg) const; - ::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg) const; - ::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg) const; - ::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg) const; - ::cbWaveformData fromLegacy(const cbWaveformData& leg) const; - ::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const; - ::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg) const; - ::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) const; - ::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg) const; - ::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) const; - ::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) const; - NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg) const; - NativeNSPStatus fromLegacy(const NSPStatus& leg) const; - ::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg) const; - NativePCStatus fromLegacy(const cbPcStatus& leg) const; - NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg) const; - NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg) const; - NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg) const; - ::cbPKT_SPK fromLegacy(const cbPKT_SPK& leg) const; - NativeSpikeCache fromLegacy(const cbSPKCACHE& leg) const; - NativeSpikeBuffer fromLegacy(const cbSPKBUFF& leg) const; - - cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) const; - cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) const; - cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) const; - cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) const; - cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) const; - cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) const; - cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) const; - cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur) const; - cbSCALING toLegacy(const ::cbSCALING& cur) const; - cbFILTDESC toLegacy(const ::cbFILTDESC& cur) const; - cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) const; - cbHOOP toLegacy(const ::cbHOOP& cur) const; - cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) const; - cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) const; - cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) const; - cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur) const; - cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) const; - cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; - cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) const; - cbAdaptControl toLegacy(const ::cbAdaptControl& cur) const; - cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur) const; - cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur) const; - cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur) const; - cbWaveformData toLegacy(const ::cbWaveformData& cur) const; - cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const; - cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur) const; - cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) const; - cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) const; - cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) const; - cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) const; - NSPStatus toLegacy(const NativeNSPStatus& cur) const; - cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const; - cbRECBUFF toLegacy(const NativeReceiveBuffer& cur) const; - cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur) const; - cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur) const; - cbPKT_SPK toLegacy(const ::cbPKT_SPK& cur) const; + void fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const; + void fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const; + void fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const; + void fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const; + void fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const; + void fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const; + void fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const; + void fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const; + void fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const; + void fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const; + void fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const; + void fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const; + void fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const; + void fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const; + void fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const; + void fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const; + void fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const; + void fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const; + void fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const; + void fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const; + void fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const; + void fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const; + void fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const; + void fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const; + void fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const; + void fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const; + void fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const; + void fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const; + void fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const; + void fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const; + void fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const; + void fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const; + void fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const; + void fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const; + void fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const; + void fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const; + void fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const; + void fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const; + void fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const; + void fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const; + + void toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const; + void toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const; + void toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const; + void toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const; + void toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const; + void toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const; + void toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const; + void toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const; + void toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const; + void toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const; + void toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const; + void toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const; + void toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const; + void toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const; + void toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const; + void toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const; + void toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const; + void toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; + void toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const; + void toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const; + void toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const; + void toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const; + void toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const; + void toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const; + void toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const; + void toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const; + void toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const; + void toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const; + void toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const; + void toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const; + void toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const; + void toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const; + void toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const; + void toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const; + void toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const; + void toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const; public: Adapter( @@ -308,15 +308,15 @@ class Adapter : public CentralAdapterBase { uint32_t* getLocalXmtBufferPtr() override; /// Config read operations - Result<::cbPKT_PROCINFO> getProcInfo() const override; - Result<::cbPKT_BANKINFO> getBankInfo(uint32_t bank_num) const override; - Result<::cbPKT_FILTINFO> getFilterInfo(uint32_t filter_num) const override; - Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const override; - Result<::cbPKT_SYSINFO> getSysInfo() const override; - Result<::cbPKT_GROUPINFO> getGroupInfo(uint32_t group_idx) const override; - Result getConfigBuffer() const override; - Result getPcStatus() const override; - Result getSpikeCache(uint32_t channel_idx) const override; + Result getProcInfo(::cbPKT_PROCINFO& buf) const override; + Result getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const override; + Result getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const override; + Result getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const override; + Result getSysInfo(::cbPKT_SYSINFO& buf) const override; + Result getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const override; + Result getConfigBuffer(NativeConfigBuffer& buf) const override; + Result getPcStatus(NativePCStatus& buf) const override; + Result getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const override; /// Config write operations Result setProcInfo(const ::cbPKT_PROCINFO& info) override; @@ -362,83 +362,83 @@ class Adapter : public CentralAdapterBase { cbPcStatus* status; cbSPKBUFF* spike; - ::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) const; - ::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) const; - ::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) const; - ::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) const; - ::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) const; - ::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) const; - ::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) const; - ::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg) const; - ::cbSCALING fromLegacy(const cbSCALING& leg) const; - ::cbFILTDESC fromLegacy(const cbFILTDESC& leg) const; - ::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) const; - ::cbHOOP fromLegacy(const cbHOOP& leg) const; - ::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) const; - ::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) const; - ::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) const; - ::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg) const; - ::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) const; - ::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) const; - ::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) const; - ::cbAdaptControl fromLegacy(const cbAdaptControl& leg) const; - ::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg) const; - ::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg) const; - ::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg) const; - ::cbWaveformData fromLegacy(const cbWaveformData& leg) const; - ::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const; - ::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg) const; - ::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) const; - ::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg) const; - ::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) const; - ::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) const; - NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg) const; - NativeNSPStatus fromLegacy(const NSPStatus& leg) const; - ::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg) const; - NativePCStatus fromLegacy(const cbPcStatus& leg) const; - NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg) const; - NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg) const; - NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg) const; - ::cbPKT_SPK fromLegacy(const cbPKT_SPK& leg) const; - NativeSpikeCache fromLegacy(const cbSPKCACHE& leg) const; - NativeSpikeBuffer fromLegacy(const cbSPKBUFF& leg) const; - - cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) const; - cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) const; - cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) const; - cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) const; - cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) const; - cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) const; - cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) const; - cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur) const; - cbSCALING toLegacy(const ::cbSCALING& cur) const; - cbFILTDESC toLegacy(const ::cbFILTDESC& cur) const; - cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) const; - cbHOOP toLegacy(const ::cbHOOP& cur) const; - cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) const; - cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) const; - cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) const; - cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur) const; - cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) const; - cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; - cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) const; - cbAdaptControl toLegacy(const ::cbAdaptControl& cur) const; - cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur) const; - cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur) const; - cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur) const; - cbWaveformData toLegacy(const ::cbWaveformData& cur) const; - cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const; - cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur) const; - cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) const; - cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) const; - cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) const; - cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) const; - NSPStatus toLegacy(const NativeNSPStatus& cur) const; - cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const; - cbRECBUFF toLegacy(const NativeReceiveBuffer& cur) const; - cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur) const; - cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur) const; - cbPKT_SPK toLegacy(const ::cbPKT_SPK& cur) const; + void fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const; + void fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const; + void fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const; + void fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const; + void fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const; + void fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const; + void fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const; + void fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const; + void fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const; + void fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const; + void fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const; + void fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const; + void fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const; + void fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const; + void fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const; + void fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const; + void fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const; + void fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const; + void fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const; + void fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const; + void fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const; + void fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const; + void fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const; + void fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const; + void fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const; + void fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const; + void fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const; + void fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const; + void fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const; + void fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const; + void fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const; + void fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const; + void fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const; + void fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const; + void fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const; + void fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const; + void fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const; + void fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const; + void fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const; + void fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const; + + void toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const; + void toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const; + void toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const; + void toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const; + void toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const; + void toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const; + void toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const; + void toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const; + void toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const; + void toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const; + void toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const; + void toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const; + void toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const; + void toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const; + void toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const; + void toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const; + void toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const; + void toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; + void toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const; + void toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const; + void toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const; + void toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const; + void toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const; + void toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const; + void toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const; + void toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const; + void toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const; + void toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const; + void toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const; + void toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const; + void toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const; + void toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const; + void toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const; + void toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const; + void toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const; + void toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const; public: Adapter( @@ -479,15 +479,15 @@ class Adapter : public CentralAdapterBase { uint32_t* getLocalXmtBufferPtr() override; /// Config read operations - Result<::cbPKT_PROCINFO> getProcInfo() const override; - Result<::cbPKT_BANKINFO> getBankInfo(uint32_t bank_num) const override; - Result<::cbPKT_FILTINFO> getFilterInfo(uint32_t filter_num) const override; - Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const override; - Result<::cbPKT_SYSINFO> getSysInfo() const override; - Result<::cbPKT_GROUPINFO> getGroupInfo(uint32_t group_idx) const override; - Result getConfigBuffer() const override; - Result getPcStatus() const override; - Result getSpikeCache(uint32_t channel_idx) const override; + Result getProcInfo(::cbPKT_PROCINFO& buf) const override; + Result getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const override; + Result getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const override; + Result getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const override; + Result getSysInfo(::cbPKT_SYSINFO& buf) const override; + Result getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const override; + Result getConfigBuffer(NativeConfigBuffer& buf) const override; + Result getPcStatus(NativePCStatus& buf) const override; + Result getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const override; /// Config write operations Result setProcInfo(const ::cbPKT_PROCINFO& info) override; @@ -533,83 +533,83 @@ class Adapter : public CentralAdapterBase { cbPcStatus* status; cbSPKBUFF* spike; - ::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) const; - ::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) const; - ::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) const; - ::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) const; - ::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) const; - ::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) const; - ::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) const; - ::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg) const; - ::cbSCALING fromLegacy(const cbSCALING& leg) const; - ::cbFILTDESC fromLegacy(const cbFILTDESC& leg) const; - ::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) const; - ::cbHOOP fromLegacy(const cbHOOP& leg) const; - ::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) const; - ::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) const; - ::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) const; - ::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg) const; - ::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) const; - ::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) const; - ::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) const; - ::cbAdaptControl fromLegacy(const cbAdaptControl& leg) const; - ::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg) const; - ::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg) const; - ::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg) const; - ::cbWaveformData fromLegacy(const cbWaveformData& leg) const; - ::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const; - ::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg) const; - ::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) const; - ::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg) const; - ::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) const; - ::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) const; - NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg) const; - NativeNSPStatus fromLegacy(const NSPStatus& leg) const; - ::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg) const; - NativePCStatus fromLegacy(const cbPcStatus& leg) const; - NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg) const; - NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg) const; - NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg) const; - ::cbPKT_SPK fromLegacy(const cbPKT_SPK& leg) const; - NativeSpikeCache fromLegacy(const cbSPKCACHE& leg) const; - NativeSpikeBuffer fromLegacy(const cbSPKBUFF& leg) const; - - cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) const; - cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) const; - cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) const; - cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) const; - cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) const; - cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) const; - cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) const; - cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur) const; - cbSCALING toLegacy(const ::cbSCALING& cur) const; - cbFILTDESC toLegacy(const ::cbFILTDESC& cur) const; - cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) const; - cbHOOP toLegacy(const ::cbHOOP& cur) const; - cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) const; - cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) const; - cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) const; - cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur) const; - cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) const; - cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; - cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) const; - cbAdaptControl toLegacy(const ::cbAdaptControl& cur) const; - cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur) const; - cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur) const; - cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur) const; - cbWaveformData toLegacy(const ::cbWaveformData& cur) const; - cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const; - cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur) const; - cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) const; - cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) const; - cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) const; - cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) const; - NSPStatus toLegacy(const NativeNSPStatus& cur) const; - cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const; - cbRECBUFF toLegacy(const NativeReceiveBuffer& cur) const; - cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur) const; - cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur) const; - cbPKT_SPK toLegacy(const ::cbPKT_SPK& cur) const; + void fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const; + void fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const; + void fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const; + void fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const; + void fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const; + void fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const; + void fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const; + void fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const; + void fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const; + void fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const; + void fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const; + void fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const; + void fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const; + void fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const; + void fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const; + void fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const; + void fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const; + void fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const; + void fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const; + void fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const; + void fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const; + void fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const; + void fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const; + void fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const; + void fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const; + void fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const; + void fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const; + void fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const; + void fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const; + void fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const; + void fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const; + void fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const; + void fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const; + void fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const; + void fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const; + void fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const; + void fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const; + void fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const; + void fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const; + void fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const; + + void toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const; + void toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const; + void toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const; + void toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const; + void toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const; + void toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const; + void toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const; + void toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const; + void toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const; + void toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const; + void toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const; + void toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const; + void toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const; + void toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const; + void toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const; + void toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const; + void toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const; + void toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; + void toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const; + void toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const; + void toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const; + void toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const; + void toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const; + void toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const; + void toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const; + void toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const; + void toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const; + void toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const; + void toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const; + void toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const; + void toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const; + void toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const; + void toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const; + void toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const; + void toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const; + void toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const; public: Adapter( @@ -650,15 +650,15 @@ class Adapter : public CentralAdapterBase { uint32_t* getLocalXmtBufferPtr() override; /// Config read operations - Result<::cbPKT_PROCINFO> getProcInfo() const override; - Result<::cbPKT_BANKINFO> getBankInfo(uint32_t bank_num) const override; - Result<::cbPKT_FILTINFO> getFilterInfo(uint32_t filter_num) const override; - Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const override; - Result<::cbPKT_SYSINFO> getSysInfo() const override; - Result<::cbPKT_GROUPINFO> getGroupInfo(uint32_t group_idx) const override; - Result getConfigBuffer() const override; - Result getPcStatus() const override; - Result getSpikeCache(uint32_t channel_idx) const override; + Result getProcInfo(::cbPKT_PROCINFO& buf) const override; + Result getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const override; + Result getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const override; + Result getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const override; + Result getSysInfo(::cbPKT_SYSINFO& buf) const override; + Result getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const override; + Result getConfigBuffer(NativeConfigBuffer& buf) const override; + Result getPcStatus(NativePCStatus& buf) const override; + Result getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const override; /// Config write operations Result setProcInfo(const ::cbPKT_PROCINFO& info) override; @@ -704,83 +704,83 @@ class Adapter : public CentralAdapterBase { cbPcStatus* status; cbSPKBUFF* spike; - ::cbPKT_HEADER fromLegacy(const cbPKT_HEADER& leg) const; - ::cbPKT_SYSINFO fromLegacy(const cbPKT_SYSINFO& leg) const; - ::cbPKT_PROCINFO fromLegacy(const cbPKT_PROCINFO& leg) const; - ::cbPKT_BANKINFO fromLegacy(const cbPKT_BANKINFO& leg) const; - ::cbPKT_GROUPINFO fromLegacy(const cbPKT_GROUPINFO& leg) const; - ::cbPKT_FILTINFO fromLegacy(const cbPKT_FILTINFO& leg) const; - ::cbPKT_ADAPTFILTINFO fromLegacy(const cbPKT_ADAPTFILTINFO& leg) const; - ::cbPKT_REFELECFILTINFO fromLegacy(const cbPKT_REFELECFILTINFO& leg) const; - ::cbSCALING fromLegacy(const cbSCALING& leg) const; - ::cbFILTDESC fromLegacy(const cbFILTDESC& leg) const; - ::cbMANUALUNITMAPPING fromLegacy(const cbMANUALUNITMAPPING& leg) const; - ::cbHOOP fromLegacy(const cbHOOP& leg) const; - ::cbPKT_CHANINFO fromLegacy(const cbPKT_CHANINFO& leg) const; - ::cbPKT_FS_BASIS fromLegacy(const cbPKT_FS_BASIS& leg) const; - ::cbPKT_SS_MODELSET fromLegacy(const cbPKT_SS_MODELSET& leg) const; - ::cbPKT_SS_DETECT fromLegacy(const cbPKT_SS_DETECT& leg) const; - ::cbPKT_SS_ARTIF_REJECT fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) const; - ::cbPKT_SS_NOISE_BOUNDARY fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) const; - ::cbPKT_SS_STATISTICS fromLegacy(const cbPKT_SS_STATISTICS& leg) const; - ::cbAdaptControl fromLegacy(const cbAdaptControl& leg) const; - ::cbPKT_SS_STATUS fromLegacy(const cbPKT_SS_STATUS& leg) const; - ::cbproto::SpikeSorting fromLegacy(const cbSPIKE_SORTING& leg) const; - ::cbPKT_NTRODEINFO fromLegacy(const cbPKT_NTRODEINFO& leg) const; - ::cbWaveformData fromLegacy(const cbWaveformData& leg) const; - ::cbPKT_AOUT_WAVEFORM fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const; - ::cbPKT_LNC fromLegacy(const cbPKT_LNC& leg) const; - ::cbPKT_NPLAY fromLegacy(const cbPKT_NPLAY& leg) const; - ::cbVIDEOSOURCE fromLegacy(const cbVIDEOSOURCE& leg) const; - ::cbTRACKOBJ fromLegacy(const cbTRACKOBJ& leg) const; - ::cbPKT_FILECFG fromLegacy(const cbPKT_FILECFG& leg) const; - NativeConfigBuffer fromLegacy(const cbCFGBUFF& leg) const; - NativeNSPStatus fromLegacy(const NSPStatus& leg) const; - ::cbPKT_UNIT_SELECTION fromLegacy(const cbPKT_UNIT_SELECTION& leg) const; - NativePCStatus fromLegacy(const cbPcStatus& leg) const; - NativeReceiveBuffer fromLegacy(const cbRECBUFF& leg) const; - NativeTransmitBuffer fromLegacy(const cbXMTBUFF& leg) const; - NativeTransmitBufferLocal fromLegacy(const cbXMTBUFFLOCAL& leg) const; - ::cbPKT_SPK fromLegacy(const cbPKT_SPK& leg) const; - NativeSpikeCache fromLegacy(const cbSPKCACHE& leg) const; - NativeSpikeBuffer fromLegacy(const cbSPKBUFF& leg) const; - - cbPKT_HEADER toLegacy(const ::cbPKT_HEADER& cur) const; - cbPKT_SYSINFO toLegacy(const ::cbPKT_SYSINFO& cur) const; - cbPKT_PROCINFO toLegacy(const ::cbPKT_PROCINFO& cur) const; - cbPKT_BANKINFO toLegacy(const ::cbPKT_BANKINFO& cur) const; - cbPKT_GROUPINFO toLegacy(const ::cbPKT_GROUPINFO& cur) const; - cbPKT_FILTINFO toLegacy(const ::cbPKT_FILTINFO& cur) const; - cbPKT_ADAPTFILTINFO toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) const; - cbPKT_REFELECFILTINFO toLegacy(const ::cbPKT_REFELECFILTINFO& cur) const; - cbSCALING toLegacy(const ::cbSCALING& cur) const; - cbFILTDESC toLegacy(const ::cbFILTDESC& cur) const; - cbMANUALUNITMAPPING toLegacy(const ::cbMANUALUNITMAPPING& cur) const; - cbHOOP toLegacy(const ::cbHOOP& cur) const; - cbPKT_CHANINFO toLegacy(const ::cbPKT_CHANINFO& cur) const; - cbPKT_FS_BASIS toLegacy(const ::cbPKT_FS_BASIS& cur) const; - cbPKT_SS_MODELSET toLegacy(const ::cbPKT_SS_MODELSET& cur) const; - cbPKT_SS_DETECT toLegacy(const ::cbPKT_SS_DETECT& cur) const; - cbPKT_SS_ARTIF_REJECT toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) const; - cbPKT_SS_NOISE_BOUNDARY toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; - cbPKT_SS_STATISTICS toLegacy(const ::cbPKT_SS_STATISTICS& cur) const; - cbAdaptControl toLegacy(const ::cbAdaptControl& cur) const; - cbPKT_SS_STATUS toLegacy(const ::cbPKT_SS_STATUS& cur) const; - cbSPIKE_SORTING toLegacy(const ::cbproto::SpikeSorting& cur) const; - cbPKT_NTRODEINFO toLegacy(const ::cbPKT_NTRODEINFO& cur) const; - cbWaveformData toLegacy(const ::cbWaveformData& cur) const; - cbPKT_AOUT_WAVEFORM toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const; - cbPKT_LNC toLegacy(const ::cbPKT_LNC& cur) const; - cbPKT_NPLAY toLegacy(const ::cbPKT_NPLAY& cur) const; - cbVIDEOSOURCE toLegacy(const ::cbVIDEOSOURCE& cur) const; - cbTRACKOBJ toLegacy(const ::cbTRACKOBJ& cur) const; - cbPKT_FILECFG toLegacy(const ::cbPKT_FILECFG& cur) const; - NSPStatus toLegacy(const NativeNSPStatus& cur) const; - cbPKT_UNIT_SELECTION toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const; - cbRECBUFF toLegacy(const NativeReceiveBuffer& cur) const; - cbXMTBUFF toLegacy(const NativeTransmitBuffer& cur) const; - cbXMTBUFFLOCAL toLegacy(const NativeTransmitBufferLocal& cur) const; - cbPKT_SPK toLegacy(const ::cbPKT_SPK& cur) const; + void fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const; + void fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const; + void fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const; + void fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const; + void fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const; + void fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const; + void fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const; + void fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const; + void fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const; + void fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const; + void fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const; + void fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const; + void fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const; + void fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const; + void fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const; + void fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const; + void fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const; + void fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const; + void fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const; + void fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const; + void fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const; + void fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const; + void fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const; + void fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const; + void fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const; + void fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const; + void fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const; + void fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const; + void fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const; + void fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const; + void fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const; + void fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const; + void fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const; + void fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const; + void fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const; + void fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const; + void fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const; + void fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const; + void fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const; + void fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const; + + void toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const; + void toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const; + void toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const; + void toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const; + void toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const; + void toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const; + void toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const; + void toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const; + void toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const; + void toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const; + void toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const; + void toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const; + void toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const; + void toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const; + void toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const; + void toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const; + void toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const; + void toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; + void toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const; + void toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const; + void toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const; + void toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const; + void toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const; + void toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const; + void toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const; + void toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const; + void toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const; + void toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const; + void toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const; + void toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const; + void toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const; + void toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const; + void toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const; + void toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const; + void toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const; + void toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const; public: Adapter( @@ -821,15 +821,15 @@ class Adapter : public CentralAdapterBase { uint32_t* getLocalXmtBufferPtr() override; /// Config read operations - Result<::cbPKT_PROCINFO> getProcInfo() const override; - Result<::cbPKT_BANKINFO> getBankInfo(uint32_t bank_num) const override; - Result<::cbPKT_FILTINFO> getFilterInfo(uint32_t filter_num) const override; - Result<::cbPKT_CHANINFO> getChanInfo(uint32_t channel_idx) const override; - Result<::cbPKT_SYSINFO> getSysInfo() const override; - Result<::cbPKT_GROUPINFO> getGroupInfo(uint32_t group_idx) const override; - Result getConfigBuffer() const override; - Result getPcStatus() const override; - Result getSpikeCache(uint32_t channel_idx) const override; + Result getProcInfo(::cbPKT_PROCINFO& buf) const override; + Result getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const override; + Result getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const override; + Result getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const override; + Result getSysInfo(::cbPKT_SYSINFO& buf) const override; + Result getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const override; + Result getConfigBuffer(NativeConfigBuffer& buf) const override; + Result getPcStatus(NativePCStatus& buf) const override; + Result getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const override; /// Config write operations Result setProcInfo(const ::cbPKT_PROCINFO& info) override; diff --git a/src/cbshm/include/cbshm/central_types/v3_11.h b/src/cbshm/include/cbshm/central_types/v3_11.h index 612f4502..a7a5df19 100644 --- a/src/cbshm/include/cbshm/central_types/v3_11.h +++ b/src/cbshm/include/cbshm/central_types/v3_11.h @@ -24,6 +24,15 @@ namespace cbshm { namespace central_v3_11 { +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Protocol Version +/// @{ + +constexpr uint32_t cbVERSION_MAJOR = 3; +constexpr uint32_t cbVERSION_MINOR = 11; + +/// @} + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @name Central Constants /// @{ diff --git a/src/cbshm/include/cbshm/central_types/v4_0.h b/src/cbshm/include/cbshm/central_types/v4_0.h index 70de771f..ebd1f637 100644 --- a/src/cbshm/include/cbshm/central_types/v4_0.h +++ b/src/cbshm/include/cbshm/central_types/v4_0.h @@ -24,6 +24,15 @@ namespace cbshm { namespace central_v4_0 { +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Protocol Version +/// @{ + +constexpr uint32_t cbVERSION_MAJOR = 4; +constexpr uint32_t cbVERSION_MINOR = 0; + +/// @} + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @name Central Constants /// @{ diff --git a/src/cbshm/include/cbshm/central_types/v4_1.h b/src/cbshm/include/cbshm/central_types/v4_1.h index 22447d9d..99b95acf 100644 --- a/src/cbshm/include/cbshm/central_types/v4_1.h +++ b/src/cbshm/include/cbshm/central_types/v4_1.h @@ -24,6 +24,15 @@ namespace cbshm { namespace central_v4_1 { +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Protocol Version +/// @{ + +constexpr uint32_t cbVERSION_MAJOR = 4; +constexpr uint32_t cbVERSION_MINOR = 1; + +/// @} + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @name Central Constants /// @{ diff --git a/src/cbshm/include/cbshm/central_types/v4_2.h b/src/cbshm/include/cbshm/central_types/v4_2.h index 339098f6..5ccc5d69 100644 --- a/src/cbshm/include/cbshm/central_types/v4_2.h +++ b/src/cbshm/include/cbshm/central_types/v4_2.h @@ -24,6 +24,15 @@ namespace cbshm { namespace central_v4_2 { +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Protocol Version +/// @{ + +constexpr uint32_t cbVERSION_MAJOR = 4; +constexpr uint32_t cbVERSION_MINOR = 2; + +/// @} + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @name Central Constants /// @{ diff --git a/src/cbshm/include/cbshm/shmem_session.h b/src/cbshm/include/cbshm/shmem_session.h index e601fb50..5ae42cd2 100644 --- a/src/cbshm/include/cbshm/shmem_session.h +++ b/src/cbshm/include/cbshm/shmem_session.h @@ -224,8 +224,9 @@ class ShmemSession { const NativeConfigBuffer* getNativeConfigBuffer() const; /// @brief Get a translated copy of Central's configuration buffer + /// @param buf Output parameter to receive the configuration buffer (very large, allocate on the heap!) /// @return Result::value containing the configuration buffer, or Result::error if not CENTRAL layout - Result getLegacyConfigBuffer(); + Result getLegacyConfigBuffer(NativeConfigBuffer& buf); /// @} diff --git a/src/cbshm/src/central_adapters/v3_11.cpp b/src/cbshm/src/central_adapters/v3_11.cpp index 225b2074..de8758e9 100644 --- a/src/cbshm/src/central_adapters/v3_11.cpp +++ b/src/cbshm/src/central_adapters/v3_11.cpp @@ -42,32 +42,27 @@ size_t BootstrapAdapter::getReceiveBufferLen() const { return sizeof(cbRECBUFFLEN); } -::cbPKT_HEADER Adapter::fromLegacy(const cbPKT_HEADER& leg) const { - ::cbPKT_HEADER cur{}; +void Adapter::fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const { cur.time = leg.time; // TODO: explicit or implicit conversion here (?) (and for all PROCTIME) cur.chid = leg.chid; cur.type = static_cast(leg.type); cur.dlen = static_cast(leg.dlen); cur.instrument = 0; cur.reserved = 0; - return cur; } -::cbPKT_SYSINFO Adapter::fromLegacy(const cbPKT_SYSINFO& leg) const { - ::cbPKT_SYSINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.sysfreq = leg.sysfreq; cur.spikelen = leg.spikelen; cur.spikepre = leg.spikepre; cur.resetque = leg.resetque; cur.runlevel = leg.runlevel; cur.runflags = leg.runflags; - return cur; } -::cbPKT_PROCINFO Adapter::fromLegacy(const cbPKT_PROCINFO& leg) const { - ::cbPKT_PROCINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.idcode = leg.idcode; cur.idcode = leg.idcode; @@ -82,12 +77,10 @@ ::cbPKT_PROCINFO Adapter::fromLegacy(const cbPKT_PROCINFO& leg) const { cur.hoopcount = leg.hoopcount; cur.reserved = leg.sortmethod; cur.version = leg.version; - return cur; } -::cbPKT_BANKINFO Adapter::fromLegacy(const cbPKT_BANKINFO& leg) const { - ::cbPKT_BANKINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.bank = leg.bank; cur.idcode = leg.idcode; @@ -95,24 +88,20 @@ ::cbPKT_BANKINFO Adapter::fromLegacy(const cbPKT_BANKINFO& leg) const { copyArr(cur.label, leg.label); cur.chanbase = leg.chanbase; cur.chancount = leg.chancount; - return cur; } -::cbPKT_GROUPINFO Adapter::fromLegacy(const cbPKT_GROUPINFO& leg) const { - ::cbPKT_GROUPINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.group = leg.group; copyArr(cur.label, leg.label); cur.period = leg.period; cur.length = leg.length; copyArr(cur.list, leg.list); - return cur; } -::cbPKT_FILTINFO Adapter::fromLegacy(const cbPKT_FILTINFO& leg) const { - ::cbPKT_FILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.filt = leg.filt; copyArr(cur.label, leg.label); @@ -131,73 +120,59 @@ ::cbPKT_FILTINFO Adapter::fromLegacy(const cbPKT_FILTINFO& leg) const { cur.sos2a2 = leg.sos2a2; cur.sos2b1 = leg.sos2b1; cur.sos2b2 = leg.sos2b2; - return cur; } -::cbPKT_ADAPTFILTINFO Adapter::fromLegacy(const cbPKT_ADAPTFILTINFO& leg) const { - ::cbPKT_ADAPTFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.nMode = leg.nMode; cur.dLearningRate = leg.dLearningRate; cur.nRefChan1 = leg.nRefChan1; cur.nRefChan2 = leg.nRefChan2; - return cur; } -::cbPKT_REFELECFILTINFO Adapter::fromLegacy(const cbPKT_REFELECFILTINFO& leg) const { - ::cbPKT_REFELECFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.nMode = leg.nMode; cur.nRefChan = leg.nRefChan; - return cur; } -::cbSCALING Adapter::fromLegacy(const cbSCALING& leg) const { - ::cbSCALING cur{}; +void Adapter::fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const { cur.digmin = leg.digmin; cur.digmax = leg.digmax; cur.anamin = leg.anamin; cur.anamax = leg.anamax; cur.anagain = leg.anagain; copyArr(cur.anaunit, leg.anaunit); - return cur; } -::cbFILTDESC Adapter::fromLegacy(const cbFILTDESC& leg) const { - ::cbFILTDESC cur{}; +void Adapter::fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const { cur.hpfreq = leg.hpfreq; cur.hporder = leg.hporder; cur.hptype = leg.hptype; cur.lpfreq = leg.lpfreq; cur.lporder = leg.lporder; cur.lptype = leg.lptype; - return cur; } -::cbMANUALUNITMAPPING Adapter::fromLegacy(const cbMANUALUNITMAPPING& leg) const { - ::cbMANUALUNITMAPPING cur{}; +void Adapter::fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const { cur.nOverride = leg.nOverride; copyArr(cur.afOrigin, leg.afOrigin); copyArr2D(cur.afShape, leg.afShape); cur.aPhi = leg.aPhi; cur.bValid = leg.bValid; - return cur; } -::cbHOOP Adapter::fromLegacy(const cbHOOP& leg) const { - ::cbHOOP cur{}; +void Adapter::fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const { cur.valid = leg.valid; cur.time = leg.time; cur.min = leg.min; cur.max = leg.max; - return cur; } -::cbPKT_CHANINFO Adapter::fromLegacy(const cbPKT_CHANINFO& leg) const { - ::cbPKT_CHANINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.proc = leg.proc; cur.bank = leg.bank; @@ -208,15 +183,15 @@ ::cbPKT_CHANINFO Adapter::fromLegacy(const cbPKT_CHANINFO& leg) const { cur.aoutcaps = leg.aoutcaps; cur.ainpcaps = leg.ainpcaps; cur.spkcaps = leg.spkcaps; - cur.physcalin = fromLegacy(leg.physcalin); - cur.phyfiltin = fromLegacy(leg.phyfiltin); - cur.physcalout = fromLegacy(leg.physcalout); - cur.phyfiltout = fromLegacy(leg.phyfiltout); + fromLegacy(cur.physcalin, leg.physcalin); + fromLegacy(cur.phyfiltin, leg.phyfiltin); + fromLegacy(cur.physcalout, leg.physcalout); + fromLegacy(cur.phyfiltout, leg.phyfiltout); copyArr(cur.label, leg.label); cur.userflags = leg.userflags; copyArr(cur.position, leg.position); - cur.scalin = fromLegacy(leg.scalin); - cur.scalout = fromLegacy(leg.scalout); + fromLegacy(cur.scalin, leg.scalin); + fromLegacy(cur.scalout, leg.scalout); cur.doutopts = leg.doutopts; cur.dinpopts = leg.dinpopts; cur.aoutopts = leg.aoutopts; @@ -247,22 +222,18 @@ ::cbPKT_CHANINFO Adapter::fromLegacy(const cbPKT_CHANINFO& leg) const { cur.refelecchan = leg.refelecchan; copyArr(cur.unitmapping, leg.unitmapping, this, &Adapter::fromLegacy); copyArr2D(cur.spkhoops, leg.spkhoops, this, &Adapter::fromLegacy); - return cur; } -::cbPKT_FS_BASIS Adapter::fromLegacy(const cbPKT_FS_BASIS& leg) const { - ::cbPKT_FS_BASIS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.mode = leg.mode; cur.fs = leg.fs; copyArr2D(cur.basis, leg.basis); - return cur; } -::cbPKT_SS_MODELSET Adapter::fromLegacy(const cbPKT_SS_MODELSET& leg) const { - ::cbPKT_SS_MODELSET cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.unit_number = leg.unit_number; cur.valid = leg.valid; @@ -277,37 +248,29 @@ ::cbPKT_SS_MODELSET Adapter::fromLegacy(const cbPKT_SS_MODELSET& leg) const { cur.subcluster_spread_factor_denominator = leg.subcluster_spread_factor_denominator; cur.mu_e = leg.mu_e; cur.sigma_e_squared = leg.sigma_e_squared; - return cur; } -::cbPKT_SS_DETECT Adapter::fromLegacy(const cbPKT_SS_DETECT& leg) const { - ::cbPKT_SS_DETECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.fThreshold = leg.fThreshold; cur.fMultiplier = leg.fMultiplier; - return cur; } -::cbPKT_SS_ARTIF_REJECT Adapter::fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) const { - ::cbPKT_SS_ARTIF_REJECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.nMaxSimulChans = leg.nMaxSimulChans; cur.nRefractoryCount = leg.nRefractoryCount; - return cur; } -::cbPKT_SS_NOISE_BOUNDARY Adapter::fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) const { - ::cbPKT_SS_NOISE_BOUNDARY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; copyArr(cur.afc, leg.afc); copyArr2D(cur.afS, leg.afS); - return cur; } -::cbPKT_SS_STATISTICS Adapter::fromLegacy(const cbPKT_SS_STATISTICS& leg) const { - ::cbPKT_SS_STATISTICS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.nUpdateSpikes = leg.nUpdateSpikes; cur.nAutoalg = leg.nAutoalg; cur.nMode = leg.nMode; @@ -320,63 +283,51 @@ ::cbPKT_SS_STATISTICS Adapter::fromLegacy(const cbPKT_SS_STATISTICS& leg) const cur.fClusterHistMinPeakPercentage = leg.fClusterHistMinPeakPercentage; cur.nWaveBasisSize = leg.nWaveBasisSize; cur.nWaveSampleSize = leg.nWaveSampleSize; - return cur; } -::cbAdaptControl Adapter::fromLegacy(const cbAdaptControl& leg) const { - ::cbAdaptControl cur{}; +void Adapter::fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const { cur.nMode = leg.nMode; cur.fTimeOutMinutes = leg.fTimeOutMinutes; cur.fElapsedMinutes = leg.fElapsedMinutes; - return cur; } -::cbPKT_SS_STATUS Adapter::fromLegacy(const cbPKT_SS_STATUS& leg) const { - ::cbPKT_SS_STATUS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); - cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats); - cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits); - return cur; +void Adapter::fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + fromLegacy(cur.cntlUnitStats, leg.cntlUnitStats); + fromLegacy(cur.cntlNumUnits, leg.cntlNumUnits); } -::cbproto::SpikeSorting Adapter::fromLegacy(const cbSPIKE_SORTING& leg) const { - ::cbproto::SpikeSorting cur{}; +void Adapter::fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const { copyArr(cur.basis, leg.asBasis, this, &Adapter::fromLegacy); copyArr2D(cur.models, leg.asSortModel, this, &Adapter::fromLegacy); - cur.detect = fromLegacy(leg.pktDetect); - cur.artifact_reject = fromLegacy(leg.pktArtifReject); + fromLegacy(cur.detect, leg.pktDetect); + fromLegacy(cur.artifact_reject, leg.pktArtifReject); copyArr(cur.noise_boundary, leg.pktNoiseBoundary, this, &Adapter::fromLegacy); - cur.statistics = fromLegacy(leg.pktStatistics); - cur.status = fromLegacy(leg.pktStatus); - return cur; + fromLegacy(cur.statistics, leg.pktStatistics); + fromLegacy(cur.status, leg.pktStatus); } -::cbPKT_NTRODEINFO Adapter::fromLegacy(const cbPKT_NTRODEINFO& leg) const { - ::cbPKT_NTRODEINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.ntrode = leg.ntrode; copyArr(cur.label, leg.label); copyArr2D(cur.ellipses, leg.ellipses, this, &Adapter::fromLegacy); cur.nSite = leg.nSite; cur.fs = leg.fs; copyArr(cur.nChan, leg.nChan); - return cur; } -::cbWaveformData Adapter::fromLegacy(const cbWaveformData& leg) const { - ::cbWaveformData cur{}; +void Adapter::fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const { cur.offset = leg.offset; // aka sineFrequency cur.seq = leg.seq; // aka sineAmplitude cur.seqTotal = leg.seqTotal; cur.phases = leg.phases; copyArr(cur.duration, leg.duration); copyArr(cur.amplitude, leg.amplitude); - return cur; } -::cbPKT_AOUT_WAVEFORM Adapter::fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const { - ::cbPKT_AOUT_WAVEFORM cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.mode = leg.mode; cur.repeats = leg.repeats; @@ -386,22 +337,18 @@ ::cbPKT_AOUT_WAVEFORM Adapter::fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const cur.trigValue = leg.trigValue; cur.trigNum = leg.trigNum; cur.active = leg.active; - cur.wave = fromLegacy(leg.wave); - return cur; + fromLegacy(cur.wave, leg.wave); } -::cbPKT_LNC Adapter::fromLegacy(const cbPKT_LNC& leg) const { - ::cbPKT_LNC cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.lncFreq = leg.lncFreq; cur.lncRefChan = leg.lncRefChan; cur.lncGlobalMode = leg.lncGlobalMode; - return cur; } -::cbPKT_NPLAY Adapter::fromLegacy(const cbPKT_NPLAY& leg) const { - ::cbPKT_NPLAY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.ftime = leg.ftime; // aka opt cur.stime = leg.stime; cur.etime = leg.etime; @@ -410,27 +357,21 @@ ::cbPKT_NPLAY Adapter::fromLegacy(const cbPKT_NPLAY& leg) const { cur.flags = leg.flags; cur.speed = leg.speed; copyArr(cur.fname, leg.fname); - return cur; } -::cbVIDEOSOURCE Adapter::fromLegacy(const cbVIDEOSOURCE& leg) const { - ::cbVIDEOSOURCE cur{}; +void Adapter::fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const { copyArr(cur.name, leg.name); cur.fps = leg.fps; - return cur; } -::cbTRACKOBJ Adapter::fromLegacy(const cbTRACKOBJ& leg) const { - ::cbTRACKOBJ cur{}; +void Adapter::fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const { copyArr(cur.name, leg.name); cur.type = leg.type; cur.pointCount = leg.pointCount; - return cur; } -::cbPKT_FILECFG Adapter::fromLegacy(const cbPKT_FILECFG& leg) const { - ::cbPKT_FILECFG cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.options = leg.options; cur.duration = leg.duration; cur.recording = leg.recording; @@ -438,69 +379,69 @@ ::cbPKT_FILECFG Adapter::fromLegacy(const cbPKT_FILECFG& leg) const { copyArr(cur.username, leg.username); copyArr(cur.filename, leg.filename); // aka datetime copyArr(cur.comment, leg.comment); - return cur; } -NativeConfigBuffer Adapter::fromLegacy(const cbCFGBUFF& leg) const { +void Adapter::fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const { // TODO: VERIFY that each list that's assumed to be instrument-independent is in fact independent from any particular instrument. - NativeConfigBuffer cur{}; - cur.version = leg.version; + cur.version = cbVERSION_MAJOR * 100 + cbVERSION_MINOR; // Central's version field contains garbage data, so replace it with the protocol version cur.sysflags = leg.sysflags; - cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); - cur.sysinfo = fromLegacy(leg.sysinfo); - cur.procinfo = fromLegacy(leg.procinfo[instrument_idx]); + cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); + fromLegacy(cur.sysinfo, leg.sysinfo); + fromLegacy(cur.procinfo, leg.procinfo[instrument_idx]); copyArr(cur.bankinfo, leg.bankinfo[instrument_idx], this, &Adapter::fromLegacy); copyArr(cur.groupinfo, leg.groupinfo[instrument_idx], this, &Adapter::fromLegacy); copyArr(cur.filtinfo, leg.filtinfo[instrument_idx], this, &Adapter::fromLegacy); - cur.adaptinfo = fromLegacy(leg.adaptinfo[instrument_idx]); - cur.refelecinfo = fromLegacy(leg.refelecinfo[instrument_idx]); + fromLegacy(cur.adaptinfo, leg.adaptinfo[instrument_idx]); + fromLegacy(cur.refelecinfo, leg.refelecinfo[instrument_idx]); copyArr(cur.chaninfo, leg.chaninfo, this, &Adapter::fromLegacy); copyArr(cur.asBasis, leg.isSortingOptions.asBasis, this, &Adapter::fromLegacy); - copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); + // copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); // TODO: For some reason, this contains memory that's innaccessible // TODO: Move native isSortingOptions fields into a struct - cur.pktDetect = fromLegacy(leg.isSortingOptions.pktDetect); - cur.pktArtifReject = fromLegacy(leg.isSortingOptions.pktArtifReject); + fromLegacy(cur.pktDetect, leg.isSortingOptions.pktDetect); + fromLegacy(cur.pktArtifReject, leg.isSortingOptions.pktArtifReject); copyArr(cur.pktNoiseBoundary, leg.isSortingOptions.pktNoiseBoundary, this, &Adapter::fromLegacy); - cur.pktStatistics = fromLegacy(leg.isSortingOptions.pktStatistics); - cur.pktStatus = fromLegacy(leg.isSortingOptions.pktStatus); + fromLegacy(cur.pktStatistics, leg.isSortingOptions.pktStatistics); + fromLegacy(cur.pktStatus, leg.isSortingOptions.pktStatus); copyArr(cur.isNTrodeInfo, leg.isNTrodeInfo, this, &Adapter::fromLegacy); copyArr2D(cur.isWaveform, leg.isWaveform, this, &Adapter::fromLegacy); - cur.isLnc = fromLegacy(leg.isLnc[instrument_idx]); - cur.isNPlay = fromLegacy(leg.isNPlay); + fromLegacy(cur.isLnc, leg.isLnc[instrument_idx]); + fromLegacy(cur.isNPlay, leg.isNPlay); copyArr(cur.isVideoSource, leg.isVideoSource, this, &Adapter::fromLegacy); copyArr(cur.isTrackObj, leg.isTrackObj, this, &Adapter::fromLegacy); - cur.fileinfo = fromLegacy(leg.fileinfo); + fromLegacy(cur.fileinfo, leg.fileinfo); - return cur; } -NativeNSPStatus Adapter::fromLegacy(const NSPStatus& leg) const { +void Adapter::fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const { switch(leg) { case NSPStatus::NSP_INIT: - return NativeNSPStatus::NSP_INIT; + cur = NativeNSPStatus::NSP_INIT; + break; case NSPStatus::NSP_NOIPADDR: - return NativeNSPStatus::NSP_NOIPADDR; + cur = NativeNSPStatus::NSP_NOIPADDR; + break; case NSPStatus::NSP_NOREPLY: - return NativeNSPStatus::NSP_NOREPLY; + cur = NativeNSPStatus::NSP_NOREPLY; + break; case NSPStatus::NSP_FOUND: - return NativeNSPStatus::NSP_FOUND; + cur = NativeNSPStatus::NSP_FOUND; + break; case NSPStatus::NSP_INVALID: + /* fallthrough */ default: - return NativeNSPStatus::NSP_INVALID; + cur = NativeNSPStatus::NSP_INVALID; + break; } } -::cbPKT_UNIT_SELECTION Adapter::fromLegacy(const cbPKT_UNIT_SELECTION& leg) const { - ::cbPKT_UNIT_SELECTION cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.lastchan = leg.lastchan; copyArr(cur.abyUnitSelections, leg.abyUnitSelections); - return cur; } -NativePCStatus Adapter::fromLegacy(const cbPcStatus& leg) const { - NativePCStatus cur{}; - cur.isSelection = fromLegacy(leg.isSelection[instrument_idx]); +void Adapter::fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const { + fromLegacy(cur.isSelection, leg.isSelection[instrument_idx]); cur.m_iBlockRecording = leg.m_iBlockRecording; cur.m_nPCStatusFlags = leg.m_nPCStatusFlags; cur.m_nNumFEChans = leg.m_nNumFEChans; @@ -516,96 +457,78 @@ NativePCStatus Adapter::fromLegacy(const cbPcStatus& leg) const { cur.m_nNspStatus = NativeNSPStatus::NSP_FOUND; // TODO: VERIFY cur.m_nNumNTrodesPerInstrument = cbMAXNTRODES; // TODO: VERIFY cur.m_nGeminiSystem = 1; // TODO: VERIFY - return cur; } -NativeReceiveBuffer Adapter::fromLegacy(const cbRECBUFF& leg) const { - NativeReceiveBuffer cur{}; +void Adapter::fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const { cur.received = leg.received; cur.lasttime = leg.lasttime; cur.headwrap = leg.headwrap; cur.headindex = leg.headindex; copyArr(cur.buffer, leg.buffer); - return cur; } -NativeTransmitBuffer Adapter::fromLegacy(const cbXMTBUFF& leg) const { - NativeTransmitBuffer cur{}; +void Adapter::fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const { cur.transmitted = leg.transmitted; cur.headindex = leg.headindex; cur.tailindex = leg.tailindex; cur.last_valid_index = leg.last_valid_index; cur.bufferlen = leg.bufferlen; copyArr(cur.buffer, leg.buffer); - return cur; } -NativeTransmitBufferLocal Adapter::fromLegacy(const cbXMTBUFFLOCAL& leg) const { - NativeTransmitBufferLocal cur{}; +void Adapter::fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const { cur.transmitted = leg.transmitted; cur.headindex = leg.headindex; cur.tailindex = leg.tailindex; cur.last_valid_index = leg.last_valid_index; cur.bufferlen = leg.bufferlen; copyArr(cur.buffer, leg.buffer); - return cur; } -::cbPKT_SPK Adapter::fromLegacy(const cbPKT_SPK& leg) const { - ::cbPKT_SPK cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); copyArr(cur.fPattern, leg.fPattern); cur.nPeak = leg.nPeak; cur.nValley = leg.nValley; copyArr(cur.wave, leg.wave); - return cur; } -NativeSpikeCache Adapter::fromLegacy(const cbSPKCACHE& leg) const { - NativeSpikeCache cur{}; +void Adapter::fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const { cur.chid = leg.chid; cur.pktcnt = leg.pktcnt; cur.pktsize = leg.pktsize; cur.head = leg.head; cur.valid = leg.valid; copyArr(cur.spkpkt, leg.spkpkt, this, &Adapter::fromLegacy); - return cur; } -NativeSpikeBuffer Adapter::fromLegacy(const cbSPKBUFF& leg) const { - NativeSpikeBuffer cur{}; +void Adapter::fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const { cur.flags = leg.flags; cur.chidmax = leg.chidmax; cur.linesize = leg.linesize; cur.spkcount = leg.spkcount; copyArr(cur.cache, leg.cache, this, &Adapter::fromLegacy); - return cur; } -cbPKT_HEADER Adapter::toLegacy(const ::cbPKT_HEADER& cur) const { - cbPKT_HEADER leg{}; +void Adapter::toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const { leg.time = cur.time; leg.chid = cur.chid; leg.type = static_cast(cur.type); leg.dlen = static_cast(cur.dlen); - return leg; } -cbPKT_SYSINFO Adapter::toLegacy(const ::cbPKT_SYSINFO& cur) const { - cbPKT_SYSINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.sysfreq = cur.sysfreq; leg.spikelen = cur.spikelen; leg.spikepre = cur.spikepre; leg.resetque = cur.resetque; leg.runlevel = cur.runlevel; leg.runflags = cur.runflags; - return leg; } -cbPKT_PROCINFO Adapter::toLegacy(const ::cbPKT_PROCINFO& cur) const { - cbPKT_PROCINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.idcode = cur.idcode; leg.idcode = cur.idcode; @@ -620,12 +543,10 @@ cbPKT_PROCINFO Adapter::toLegacy(const ::cbPKT_PROCINFO& cur) const { leg.hoopcount = cur.hoopcount; leg.sortmethod = cur.reserved; leg.version = cur.version; - return leg; } -cbPKT_BANKINFO Adapter::toLegacy(const ::cbPKT_BANKINFO& cur) const { - cbPKT_BANKINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.bank = cur.bank; leg.idcode = cur.idcode; @@ -633,24 +554,20 @@ cbPKT_BANKINFO Adapter::toLegacy(const ::cbPKT_BANKINFO& cur) const { copyArr(leg.label, cur.label); leg.chanbase = cur.chanbase; leg.chancount = cur.chancount; - return leg; } -cbPKT_GROUPINFO Adapter::toLegacy(const ::cbPKT_GROUPINFO& cur) const { - cbPKT_GROUPINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.group = cur.group; copyArr(leg.label, cur.label); leg.period = cur.period; leg.length = cur.length; copyArr(leg.list, cur.list); - return leg; } -cbPKT_FILTINFO Adapter::toLegacy(const ::cbPKT_FILTINFO& cur) const { - cbPKT_FILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.filt = cur.filt; copyArr(leg.label, cur.label); @@ -669,73 +586,59 @@ cbPKT_FILTINFO Adapter::toLegacy(const ::cbPKT_FILTINFO& cur) const { leg.sos2a2 = cur.sos2a2; leg.sos2b1 = cur.sos2b1; leg.sos2b2 = cur.sos2b2; - return leg; } -cbPKT_ADAPTFILTINFO Adapter::toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) const { - cbPKT_ADAPTFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.nMode = cur.nMode; leg.dLearningRate = cur.dLearningRate; leg.nRefChan1 = cur.nRefChan1; leg.nRefChan2 = cur.nRefChan2; - return leg; } -cbPKT_REFELECFILTINFO Adapter::toLegacy(const ::cbPKT_REFELECFILTINFO& cur) const { - cbPKT_REFELECFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.nMode = cur.nMode; leg.nRefChan = cur.nRefChan; - return leg; } -cbSCALING Adapter::toLegacy(const ::cbSCALING& cur) const { - cbSCALING leg{}; +void Adapter::toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const { leg.digmin = cur.digmin; leg.digmax = cur.digmax; leg.anamin = cur.anamin; leg.anamax = cur.anamax; leg.anagain = cur.anagain; copyArr(leg.anaunit, cur.anaunit); - return leg; } -cbFILTDESC Adapter::toLegacy(const ::cbFILTDESC& cur) const { - cbFILTDESC leg{}; +void Adapter::toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const { leg.hpfreq = cur.hpfreq; leg.hporder = cur.hporder; leg.hptype = cur.hptype; leg.lpfreq = cur.lpfreq; leg.lporder = cur.lporder; leg.lptype = cur.lptype; - return leg; } -cbMANUALUNITMAPPING Adapter::toLegacy(const ::cbMANUALUNITMAPPING& cur) const { - cbMANUALUNITMAPPING leg{}; +void Adapter::toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const { leg.nOverride = cur.nOverride; copyArr(leg.afOrigin, cur.afOrigin); copyArr2D(leg.afShape, cur.afShape); leg.aPhi = cur.aPhi; leg.bValid = cur.bValid; - return leg; } -cbHOOP Adapter::toLegacy(const ::cbHOOP& cur) const { - cbHOOP leg{}; +void Adapter::toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const { leg.valid = cur.valid; leg.time = cur.time; leg.min = cur.min; leg.max = cur.max; - return leg; } -cbPKT_CHANINFO Adapter::toLegacy(const ::cbPKT_CHANINFO& cur) const { - cbPKT_CHANINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.proc = cur.proc; leg.bank = cur.bank; @@ -746,15 +649,15 @@ cbPKT_CHANINFO Adapter::toLegacy(const ::cbPKT_CHANINFO& cur) const { leg.aoutcaps = cur.aoutcaps; leg.ainpcaps = cur.ainpcaps; leg.spkcaps = cur.spkcaps; - leg.physcalin = toLegacy(cur.physcalin); - leg.phyfiltin = toLegacy(cur.phyfiltin); - leg.physcalout = toLegacy(cur.physcalout); - leg.phyfiltout = toLegacy(cur.phyfiltout); + toLegacy(leg.physcalin, cur.physcalin); + toLegacy(leg.phyfiltin, cur.phyfiltin); + toLegacy(leg.physcalout, cur.physcalout); + toLegacy(leg.phyfiltout, cur.phyfiltout); copyArr(leg.label, cur.label); leg.userflags = cur.userflags; copyArr(leg.position, cur.position); - leg.scalin = toLegacy(cur.scalin); - leg.scalout = toLegacy(cur.scalout); + toLegacy(leg.scalin, cur.scalin); + toLegacy(leg.scalout, cur.scalout); leg.doutopts = cur.doutopts; leg.dinpopts = cur.dinpopts; leg.aoutopts = cur.aoutopts; @@ -782,22 +685,18 @@ cbPKT_CHANINFO Adapter::toLegacy(const ::cbPKT_CHANINFO& cur) const { leg.refelecchan = cur.refelecchan; copyArr(leg.unitmapping, cur.unitmapping, this, &Adapter::toLegacy); copyArr2D(leg.spkhoops, cur.spkhoops, this, &Adapter::toLegacy); - return leg; } -cbPKT_FS_BASIS Adapter::toLegacy(const ::cbPKT_FS_BASIS& cur) const { - cbPKT_FS_BASIS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.mode = cur.mode; leg.fs = cur.fs; copyArr2D(leg.basis, cur.basis); - return leg; } -cbPKT_SS_MODELSET Adapter::toLegacy(const ::cbPKT_SS_MODELSET& cur) const { - cbPKT_SS_MODELSET leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.unit_number = cur.unit_number; leg.valid = cur.valid; @@ -812,37 +711,29 @@ cbPKT_SS_MODELSET Adapter::toLegacy(const ::cbPKT_SS_MODELSET& cur) const { leg.subcluster_spread_factor_denominator = cur.subcluster_spread_factor_denominator; leg.mu_e = cur.mu_e; leg.sigma_e_squared = cur.sigma_e_squared; - return leg; } -cbPKT_SS_DETECT Adapter::toLegacy(const ::cbPKT_SS_DETECT& cur) const { - cbPKT_SS_DETECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.fThreshold = cur.fThreshold; leg.fMultiplier = cur.fMultiplier; - return leg; } -cbPKT_SS_ARTIF_REJECT Adapter::toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) const { - cbPKT_SS_ARTIF_REJECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.nMaxSimulChans = cur.nMaxSimulChans; leg.nRefractoryCount = cur.nRefractoryCount; - return leg; } -cbPKT_SS_NOISE_BOUNDARY Adapter::toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) const { - cbPKT_SS_NOISE_BOUNDARY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; copyArr(leg.afc, cur.afc); copyArr2D(leg.afS, cur.afS); - return leg; } -cbPKT_SS_STATISTICS Adapter::toLegacy(const ::cbPKT_SS_STATISTICS& cur) const { - cbPKT_SS_STATISTICS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.nUpdateSpikes = cur.nUpdateSpikes; leg.nAutoalg = cur.nAutoalg; leg.nMode = cur.nMode; @@ -855,63 +746,51 @@ cbPKT_SS_STATISTICS Adapter::toLegacy(const ::cbPKT_SS_STATISTICS& cur) const { leg.fClusterHistMinPeakPercentage = cur.fClusterHistMinPeakPercentage; leg.nWaveBasisSize = cur.nWaveBasisSize; leg.nWaveSampleSize = cur.nWaveSampleSize; - return leg; } -cbAdaptControl Adapter::toLegacy(const ::cbAdaptControl& cur) const { - cbAdaptControl leg{}; +void Adapter::toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const { leg.nMode = cur.nMode; leg.fTimeOutMinutes = cur.fTimeOutMinutes; leg.fElapsedMinutes = cur.fElapsedMinutes; - return leg; } -cbPKT_SS_STATUS Adapter::toLegacy(const ::cbPKT_SS_STATUS& cur) const { - cbPKT_SS_STATUS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); - leg.cntlUnitStats = toLegacy(cur.cntlUnitStats); - leg.cntlNumUnits = toLegacy(cur.cntlNumUnits); - return leg; +void Adapter::toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + toLegacy(leg.cntlUnitStats, cur.cntlUnitStats); + toLegacy(leg.cntlNumUnits, cur.cntlNumUnits); } -cbSPIKE_SORTING Adapter::toLegacy(const ::cbproto::SpikeSorting& cur) const { - cbSPIKE_SORTING leg{}; +void Adapter::toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const { copyArr(leg.asBasis, cur.basis, this, &Adapter::toLegacy); copyArr2D(leg.asSortModel, cur.models, this, &Adapter::toLegacy); - leg.pktDetect = toLegacy(cur.detect); - leg.pktArtifReject = toLegacy(cur.artifact_reject); + toLegacy(leg.pktDetect, cur.detect); + toLegacy(leg.pktArtifReject, cur.artifact_reject); copyArr(leg.pktNoiseBoundary, cur.noise_boundary, this, &Adapter::toLegacy); - leg.pktStatistics = toLegacy(cur.statistics); - leg.pktStatus = toLegacy(cur.status); - return leg; + toLegacy(leg.pktStatistics, cur.statistics); + toLegacy(leg.pktStatus, cur.status); } -cbPKT_NTRODEINFO Adapter::toLegacy(const ::cbPKT_NTRODEINFO& cur) const { - cbPKT_NTRODEINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.ntrode = cur.ntrode; copyArr(leg.label, cur.label); copyArr2D(leg.ellipses, cur.ellipses, this, &Adapter::toLegacy); leg.nSite = cur.nSite; leg.fs = cur.fs; copyArr(leg.nChan, cur.nChan); - return leg; } -cbWaveformData Adapter::toLegacy(const ::cbWaveformData& cur) const { - cbWaveformData leg{}; +void Adapter::toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const { leg.offset = cur.offset; // aka sineFrequency leg.seq = cur.seq; // aka sineAmplitude leg.seqTotal = cur.seqTotal; leg.phases = cur.phases; copyArr(leg.duration, cur.duration); copyArr(leg.amplitude, cur.amplitude); - return leg; } -cbPKT_AOUT_WAVEFORM Adapter::toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const { - cbPKT_AOUT_WAVEFORM leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.mode = cur.mode; leg.repeats = cur.repeats; @@ -920,22 +799,18 @@ cbPKT_AOUT_WAVEFORM Adapter::toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const { leg.trigValue = cur.trigValue; leg.trigNum = cur.trigNum; leg.active = cur.active; - leg.wave = toLegacy(cur.wave); - return leg; + toLegacy(leg.wave, cur.wave); } -cbPKT_LNC Adapter::toLegacy(const ::cbPKT_LNC& cur) const { - cbPKT_LNC leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.lncFreq = cur.lncFreq; leg.lncRefChan = cur.lncRefChan; leg.lncGlobalMode = cur.lncGlobalMode; - return leg; } -cbPKT_NPLAY Adapter::toLegacy(const ::cbPKT_NPLAY& cur) const { - cbPKT_NPLAY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.ftime = cur.ftime; // aka opt leg.stime = cur.stime; leg.etime = cur.etime; @@ -944,27 +819,21 @@ cbPKT_NPLAY Adapter::toLegacy(const ::cbPKT_NPLAY& cur) const { leg.flags = cur.flags; leg.speed = cur.speed; copyArr(leg.fname, cur.fname); - return leg; } -cbVIDEOSOURCE Adapter::toLegacy(const ::cbVIDEOSOURCE& cur) const { - cbVIDEOSOURCE leg{}; +void Adapter::toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const { copyArr(leg.name, cur.name); leg.fps = cur.fps; - return leg; } -cbTRACKOBJ Adapter::toLegacy(const ::cbTRACKOBJ& cur) const { - cbTRACKOBJ leg{}; +void Adapter::toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const { copyArr(leg.name, cur.name); leg.type = cur.type; leg.pointCount = cur.pointCount; - return leg; } -cbPKT_FILECFG Adapter::toLegacy(const ::cbPKT_FILECFG& cur) const { - cbPKT_FILECFG leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.options = cur.options; leg.duration = cur.duration; leg.recording = cur.recording; @@ -972,73 +841,68 @@ cbPKT_FILECFG Adapter::toLegacy(const ::cbPKT_FILECFG& cur) const { copyArr(leg.username, cur.username); copyArr(leg.filename, cur.filename); // aka datetime copyArr(leg.comment, cur.comment); - return leg; } -NSPStatus Adapter::toLegacy(const NativeNSPStatus& cur) const { +void Adapter::toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const { switch(cur) { case NativeNSPStatus::NSP_INIT: - return NSPStatus::NSP_INIT; + leg = NSPStatus::NSP_INIT; + break; case NativeNSPStatus::NSP_NOIPADDR: - return NSPStatus::NSP_NOIPADDR; + leg = NSPStatus::NSP_NOIPADDR; + break; case NativeNSPStatus::NSP_NOREPLY: - return NSPStatus::NSP_NOREPLY; + leg = NSPStatus::NSP_NOREPLY; + break; case NativeNSPStatus::NSP_FOUND: - return NSPStatus::NSP_FOUND; + leg = NSPStatus::NSP_FOUND; + break; case NativeNSPStatus::NSP_INVALID: + /* fallthrough */ default: - return NSPStatus::NSP_INVALID; + leg = NSPStatus::NSP_INVALID; + break; } } -cbPKT_UNIT_SELECTION Adapter::toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const { - cbPKT_UNIT_SELECTION leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.lastchan = cur.lastchan; copyArr(leg.abyUnitSelections, cur.abyUnitSelections); - return leg; } -cbRECBUFF Adapter::toLegacy(const NativeReceiveBuffer& cur) const { - cbRECBUFF leg{}; +void Adapter::toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const { leg.received = cur.received; leg.lasttime = cur.lasttime; leg.headwrap = cur.headwrap; leg.headindex = cur.headindex; copyArr(leg.buffer, cur.buffer); - return leg; } -cbXMTBUFF Adapter::toLegacy(const NativeTransmitBuffer& cur) const { - cbXMTBUFF leg{}; +void Adapter::toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const { leg.transmitted = cur.transmitted; leg.headindex = cur.headindex; leg.tailindex = cur.tailindex; leg.last_valid_index = cur.last_valid_index; leg.bufferlen = cur.bufferlen; copyArr(leg.buffer, cur.buffer); - return leg; } -cbXMTBUFFLOCAL Adapter::toLegacy(const NativeTransmitBufferLocal& cur) const { - cbXMTBUFFLOCAL leg{}; +void Adapter::toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const { leg.transmitted = cur.transmitted; leg.headindex = cur.headindex; leg.tailindex = cur.tailindex; leg.last_valid_index = cur.last_valid_index; leg.bufferlen = cur.bufferlen; copyArr(leg.buffer, cur.buffer); - return leg; } -cbPKT_SPK Adapter::toLegacy(const ::cbPKT_SPK& cur) const { - cbPKT_SPK leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); copyArr(leg.fPattern, leg.fPattern); leg.nPeak = cur.nPeak; leg.nValley = cur.nValley; copyArr(leg.wave, cur.wave); - return leg; } Adapter::Adapter(uint8_t instrument_idx, void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) @@ -1127,106 +991,88 @@ uint32_t* Adapter::getLocalXmtBufferPtr() { return xmt->buffer; } -Result<::cbPKT_PROCINFO> Adapter::getProcInfo() const { - if (instrument_idx >= std::size(cfg->procinfo)) { - return Result<::cbPKT_PROCINFO>::error("Instrument index out of range"); - } - return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx])); +Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { + fromLegacy(buf, cfg->procinfo[instrument_idx]); + return Result::ok(); } -Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint32_t bank_num) const { - if (instrument_idx >= std::size(cfg->bankinfo)) { - return Result<::cbPKT_BANKINFO>::error("Instrument index out of range"); - } +Result Adapter::getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const { uint32_t bank_idx = bank_num - 1; if (bank_idx >= std::size(cfg->bankinfo[0])) { - return Result<::cbPKT_BANKINFO>::error("Bank number out of range"); + return Result::error("Bank number out of range"); } - return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx])); + fromLegacy(buf, cfg->bankinfo[instrument_idx][bank_idx]); + return Result::ok(); } -Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint32_t filter_num) const { - if (instrument_idx >= std::size(cfg->filtinfo)) { - return Result<::cbPKT_FILTINFO>::error("Instrument index out of range"); - } +Result Adapter::getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const { uint32_t filter_idx = filter_num - 1; if (filter_idx >= std::size(cfg->filtinfo[0])) { - return Result<::cbPKT_FILTINFO>::error("Filter number out of range"); + return Result::error("Filter number out of range"); } - return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx])); + fromLegacy(buf, cfg->filtinfo[instrument_idx][filter_idx]); + return Result::ok(); } -Result<::cbPKT_CHANINFO> Adapter::getChanInfo(uint32_t channel_idx) const { +Result Adapter::getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const { if (channel_idx >= std::size(cfg->chaninfo)) { - return Result<::cbPKT_CHANINFO>::error("Channel number out of range"); + return Result::error("Channel number out of range"); } - return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx])); + fromLegacy(buf, cfg->chaninfo[channel_idx]); + return Result::ok(); } -Result<::cbPKT_SYSINFO> Adapter::getSysInfo() const { - return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo)); +Result Adapter::getSysInfo(::cbPKT_SYSINFO& buf) const { + fromLegacy(buf, cfg->sysinfo); + return Result::ok(); } -Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint32_t group_idx) const { - if (instrument_idx >= std::size(cfg->groupinfo)) { - return Result<::cbPKT_GROUPINFO>::error("Instrument index out of range"); - } +Result Adapter::getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const { if (group_idx >= std::size(cfg->groupinfo[0])) { - return Result<::cbPKT_GROUPINFO>::error("Group index out of range"); + return Result::error("Group index out of range"); } - return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx])); + fromLegacy(buf, cfg->groupinfo[instrument_idx][group_idx]); + return Result::ok(); } -Result Adapter::getConfigBuffer() const { - if (instrument_idx >= std::size(cfg->procinfo)) { - return Result::error("Instrument index out of range"); - } - return Result::ok(fromLegacy(*cfg)); +Result Adapter::getConfigBuffer(NativeConfigBuffer& buf) const { + fromLegacy(buf, *cfg); + return Result::ok(); } -Result Adapter::getPcStatus() const { - if (instrument_idx >= std::size(status->isSelection)) { - return Result::error("Instrument index out of range"); - } - return Result::ok(fromLegacy(*status)); +Result Adapter::getPcStatus(NativePCStatus& buf) const { + fromLegacy(buf, *status); + return Result::ok(); } -Result Adapter::getSpikeCache(uint32_t channel_idx) const { +Result Adapter::getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const { if (channel_idx >= std::size(spike->cache)) { - return Result::error("Channel index out of range"); + return Result::error("Channel index out of range"); } - return Result::ok(fromLegacy(spike->cache[channel_idx])); + fromLegacy(buf, spike->cache[channel_idx]); + return Result::ok(); } Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { - if (instrument_idx >= std::size(cfg->procinfo)) { - return Result::error("Instrument index out of range"); - } - cfg->procinfo[instrument_idx] = toLegacy(info); + toLegacy(cfg->procinfo[instrument_idx], info); return Result::ok(); } Result Adapter::setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) { - if (instrument_idx >= std::size(cfg->bankinfo)) { - return Result::error("Instrument index out of range"); - } uint32_t bank_idx = bank_num - 1; if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result::error("Bank number out of range"); } - cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info); + toLegacy(cfg->bankinfo[instrument_idx][bank_idx], info); return Result::ok(); } Result Adapter::setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) { - if (instrument_idx >= std::size(cfg->filtinfo)) { - return Result::error("Instrument index out of range"); - } uint32_t filter_idx = filter_num - 1; if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result::error("Filter number out of range"); } - cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info); + toLegacy(cfg->filtinfo[instrument_idx][filter_idx], info); return Result::ok(); } @@ -1234,23 +1080,20 @@ Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& if (channel_idx >= std::size(cfg->chaninfo)) { return Result::error("Channel number out of range"); } - cfg->chaninfo[channel_idx] = toLegacy(info); + toLegacy(cfg->chaninfo[channel_idx], info); return Result::ok(); } Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { - cfg->sysinfo = toLegacy(info); + toLegacy(cfg->sysinfo, info); return Result::ok(); } Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { - if (instrument_idx >= std::size(cfg->groupinfo)) { - return Result::error("Instrument index out of range"); - } if (group_idx >= std::size(cfg->groupinfo[0])) { return Result::error("Group index out of range"); } - cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info); + toLegacy(cfg->groupinfo[instrument_idx][group_idx], info); return Result::ok(); } diff --git a/src/cbshm/src/central_adapters/v4_0.cpp b/src/cbshm/src/central_adapters/v4_0.cpp index 83502786..67605a1e 100644 --- a/src/cbshm/src/central_adapters/v4_0.cpp +++ b/src/cbshm/src/central_adapters/v4_0.cpp @@ -42,32 +42,27 @@ size_t BootstrapAdapter::getReceiveBufferLen() const { return sizeof(cbRECBUFFLEN); } -::cbPKT_HEADER Adapter::fromLegacy(const cbPKT_HEADER& leg) const { - ::cbPKT_HEADER cur{}; +void Adapter::fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const { cur.time = leg.time; cur.chid = leg.chid; cur.type = static_cast(leg.type); cur.dlen = leg.dlen; cur.instrument = leg.instrument; cur.reserved = leg.reserved; - return cur; } -::cbPKT_SYSINFO Adapter::fromLegacy(const cbPKT_SYSINFO& leg) const { - ::cbPKT_SYSINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.sysfreq = leg.sysfreq; cur.spikelen = leg.spikelen; cur.spikepre = leg.spikepre; cur.resetque = leg.resetque; cur.runlevel = leg.runlevel; cur.runflags = leg.runflags; - return cur; } -::cbPKT_PROCINFO Adapter::fromLegacy(const cbPKT_PROCINFO& leg) const { - ::cbPKT_PROCINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.idcode = leg.idcode; cur.idcode = leg.idcode; @@ -82,12 +77,10 @@ ::cbPKT_PROCINFO Adapter::fromLegacy(const cbPKT_PROCINFO& leg) const { cur.hoopcount = leg.hoopcount; cur.reserved = leg.reserved; cur.version = leg.version; - return cur; } -::cbPKT_BANKINFO Adapter::fromLegacy(const cbPKT_BANKINFO& leg) const { - ::cbPKT_BANKINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.bank = leg.bank; cur.idcode = leg.idcode; @@ -95,24 +88,20 @@ ::cbPKT_BANKINFO Adapter::fromLegacy(const cbPKT_BANKINFO& leg) const { copyArr(cur.label, leg.label); cur.chanbase = leg.chanbase; cur.chancount = leg.chancount; - return cur; } -::cbPKT_GROUPINFO Adapter::fromLegacy(const cbPKT_GROUPINFO& leg) const { - ::cbPKT_GROUPINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.group = leg.group; copyArr(cur.label, leg.label); cur.period = leg.period; cur.length = leg.length; copyArr(cur.list, leg.list); - return cur; } -::cbPKT_FILTINFO Adapter::fromLegacy(const cbPKT_FILTINFO& leg) const { - ::cbPKT_FILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.filt = leg.filt; copyArr(cur.label, leg.label); @@ -131,73 +120,59 @@ ::cbPKT_FILTINFO Adapter::fromLegacy(const cbPKT_FILTINFO& leg) const { cur.sos2a2 = leg.sos2a2; cur.sos2b1 = leg.sos2b1; cur.sos2b2 = leg.sos2b2; - return cur; } -::cbPKT_ADAPTFILTINFO Adapter::fromLegacy(const cbPKT_ADAPTFILTINFO& leg) const { - ::cbPKT_ADAPTFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.nMode = leg.nMode; cur.dLearningRate = leg.dLearningRate; cur.nRefChan1 = leg.nRefChan1; cur.nRefChan2 = leg.nRefChan2; - return cur; } -::cbPKT_REFELECFILTINFO Adapter::fromLegacy(const cbPKT_REFELECFILTINFO& leg) const { - ::cbPKT_REFELECFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.nMode = leg.nMode; cur.nRefChan = leg.nRefChan; - return cur; } -::cbSCALING Adapter::fromLegacy(const cbSCALING& leg) const { - ::cbSCALING cur{}; +void Adapter::fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const { cur.digmin = leg.digmin; cur.digmax = leg.digmax; cur.anamin = leg.anamin; cur.anamax = leg.anamax; cur.anagain = leg.anagain; copyArr(cur.anaunit, leg.anaunit); - return cur; } -::cbFILTDESC Adapter::fromLegacy(const cbFILTDESC& leg) const { - ::cbFILTDESC cur{}; +void Adapter::fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const { cur.hpfreq = leg.hpfreq; cur.hporder = leg.hporder; cur.hptype = leg.hptype; cur.lpfreq = leg.lpfreq; cur.lporder = leg.lporder; cur.lptype = leg.lptype; - return cur; } -::cbMANUALUNITMAPPING Adapter::fromLegacy(const cbMANUALUNITMAPPING& leg) const { - ::cbMANUALUNITMAPPING cur{}; +void Adapter::fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const { cur.nOverride = leg.nOverride; copyArr(cur.afOrigin, leg.afOrigin); copyArr2D(cur.afShape, leg.afShape); cur.aPhi = leg.aPhi; cur.bValid = leg.bValid; - return cur; } -::cbHOOP Adapter::fromLegacy(const cbHOOP& leg) const { - ::cbHOOP cur{}; +void Adapter::fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const { cur.valid = leg.valid; cur.time = leg.time; cur.min = leg.min; cur.max = leg.max; - return cur; } -::cbPKT_CHANINFO Adapter::fromLegacy(const cbPKT_CHANINFO& leg) const { - ::cbPKT_CHANINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.proc = leg.proc; cur.bank = leg.bank; @@ -208,15 +183,15 @@ ::cbPKT_CHANINFO Adapter::fromLegacy(const cbPKT_CHANINFO& leg) const { cur.aoutcaps = leg.aoutcaps; cur.ainpcaps = leg.ainpcaps; cur.spkcaps = leg.spkcaps; - cur.physcalin = fromLegacy(leg.physcalin); - cur.phyfiltin = fromLegacy(leg.phyfiltin); - cur.physcalout = fromLegacy(leg.physcalout); - cur.phyfiltout = fromLegacy(leg.phyfiltout); + fromLegacy(cur.physcalin, leg.physcalin); + fromLegacy(cur.phyfiltin, leg.phyfiltin); + fromLegacy(cur.physcalout, leg.physcalout); + fromLegacy(cur.phyfiltout, leg.phyfiltout); copyArr(cur.label, leg.label); cur.userflags = leg.userflags; copyArr(cur.position, leg.position); - cur.scalin = fromLegacy(leg.scalin); - cur.scalout = fromLegacy(leg.scalout); + fromLegacy(cur.scalin, leg.scalin); + fromLegacy(cur.scalout, leg.scalout); cur.doutopts = leg.doutopts; cur.dinpopts = leg.dinpopts; cur.aoutopts = leg.aoutopts; @@ -247,22 +222,18 @@ ::cbPKT_CHANINFO Adapter::fromLegacy(const cbPKT_CHANINFO& leg) const { cur.refelecchan = leg.refelecchan; copyArr(cur.unitmapping, leg.unitmapping, this, &Adapter::fromLegacy); copyArr2D(cur.spkhoops, leg.spkhoops, this, &Adapter::fromLegacy); - return cur; } -::cbPKT_FS_BASIS Adapter::fromLegacy(const cbPKT_FS_BASIS& leg) const { - ::cbPKT_FS_BASIS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.mode = leg.mode; cur.fs = leg.fs; copyArr2D(cur.basis, leg.basis); - return cur; } -::cbPKT_SS_MODELSET Adapter::fromLegacy(const cbPKT_SS_MODELSET& leg) const { - ::cbPKT_SS_MODELSET cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.unit_number = leg.unit_number; cur.valid = leg.valid; @@ -277,37 +248,29 @@ ::cbPKT_SS_MODELSET Adapter::fromLegacy(const cbPKT_SS_MODELSET& leg) const { cur.subcluster_spread_factor_denominator = leg.subcluster_spread_factor_denominator; cur.mu_e = leg.mu_e; cur.sigma_e_squared = leg.sigma_e_squared; - return cur; } -::cbPKT_SS_DETECT Adapter::fromLegacy(const cbPKT_SS_DETECT& leg) const { - ::cbPKT_SS_DETECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.fThreshold = leg.fThreshold; cur.fMultiplier = leg.fMultiplier; - return cur; } -::cbPKT_SS_ARTIF_REJECT Adapter::fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) const { - ::cbPKT_SS_ARTIF_REJECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.nMaxSimulChans = leg.nMaxSimulChans; cur.nRefractoryCount = leg.nRefractoryCount; - return cur; } -::cbPKT_SS_NOISE_BOUNDARY Adapter::fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) const { - ::cbPKT_SS_NOISE_BOUNDARY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; copyArr(cur.afc, leg.afc); copyArr2D(cur.afS, leg.afS); - return cur; } -::cbPKT_SS_STATISTICS Adapter::fromLegacy(const cbPKT_SS_STATISTICS& leg) const { - ::cbPKT_SS_STATISTICS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.nUpdateSpikes = leg.nUpdateSpikes; cur.nAutoalg = leg.nAutoalg; cur.nMode = leg.nMode; @@ -320,63 +283,51 @@ ::cbPKT_SS_STATISTICS Adapter::fromLegacy(const cbPKT_SS_STATISTICS& leg) const cur.fClusterHistMinPeakPercentage = leg.fClusterHistMinPeakPercentage; cur.nWaveBasisSize = leg.nWaveBasisSize; cur.nWaveSampleSize = leg.nWaveSampleSize; - return cur; } -::cbAdaptControl Adapter::fromLegacy(const cbAdaptControl& leg) const { - ::cbAdaptControl cur{}; +void Adapter::fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const { cur.nMode = leg.nMode; cur.fTimeOutMinutes = leg.fTimeOutMinutes; cur.fElapsedMinutes = leg.fElapsedMinutes; - return cur; } -::cbPKT_SS_STATUS Adapter::fromLegacy(const cbPKT_SS_STATUS& leg) const { - ::cbPKT_SS_STATUS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); - cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats); - cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits); - return cur; +void Adapter::fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + fromLegacy(cur.cntlUnitStats, leg.cntlUnitStats); + fromLegacy(cur.cntlNumUnits, leg.cntlNumUnits); } -::cbproto::SpikeSorting Adapter::fromLegacy(const cbSPIKE_SORTING& leg) const { - ::cbproto::SpikeSorting cur{}; +void Adapter::fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const { copyArr(cur.basis, leg.asBasis, this, &Adapter::fromLegacy); copyArr2D(cur.models, leg.asSortModel, this, &Adapter::fromLegacy); - cur.detect = fromLegacy(leg.pktDetect); - cur.artifact_reject = fromLegacy(leg.pktArtifReject); + fromLegacy(cur.detect, leg.pktDetect); + fromLegacy(cur.artifact_reject, leg.pktArtifReject); copyArr(cur.noise_boundary, leg.pktNoiseBoundary, this, &Adapter::fromLegacy); - cur.statistics = fromLegacy(leg.pktStatistics); - cur.status = fromLegacy(leg.pktStatus); - return cur; + fromLegacy(cur.statistics, leg.pktStatistics); + fromLegacy(cur.status, leg.pktStatus); } -::cbPKT_NTRODEINFO Adapter::fromLegacy(const cbPKT_NTRODEINFO& leg) const { - ::cbPKT_NTRODEINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.ntrode = leg.ntrode; copyArr(cur.label, leg.label); copyArr2D(cur.ellipses, leg.ellipses, this, &Adapter::fromLegacy); cur.nSite = leg.nSite; cur.fs = leg.fs; copyArr(cur.nChan, leg.nChan); - return cur; } -::cbWaveformData Adapter::fromLegacy(const cbWaveformData& leg) const { - ::cbWaveformData cur{}; +void Adapter::fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const { cur.offset = leg.offset; // aka sineFrequency cur.seq = leg.seq; // aka sineAmplitude cur.seqTotal = leg.seqTotal; cur.phases = leg.phases; copyArr(cur.duration, leg.duration); copyArr(cur.amplitude, leg.amplitude); - return cur; } -::cbPKT_AOUT_WAVEFORM Adapter::fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const { - ::cbPKT_AOUT_WAVEFORM cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.mode = leg.mode; cur.repeats = leg.repeats; @@ -386,22 +337,18 @@ ::cbPKT_AOUT_WAVEFORM Adapter::fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const cur.trigValue = leg.trigValue; cur.trigNum = leg.trigNum; cur.active = leg.active; - cur.wave = fromLegacy(leg.wave); - return cur; + fromLegacy(cur.wave, leg.wave); } -::cbPKT_LNC Adapter::fromLegacy(const cbPKT_LNC& leg) const { - ::cbPKT_LNC cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.lncFreq = leg.lncFreq; cur.lncRefChan = leg.lncRefChan; cur.lncGlobalMode = leg.lncGlobalMode; - return cur; } -::cbPKT_NPLAY Adapter::fromLegacy(const cbPKT_NPLAY& leg) const { - ::cbPKT_NPLAY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.ftime = leg.ftime; // aka opt cur.stime = leg.stime; cur.etime = leg.etime; @@ -410,27 +357,21 @@ ::cbPKT_NPLAY Adapter::fromLegacy(const cbPKT_NPLAY& leg) const { cur.flags = leg.flags; cur.speed = leg.speed; copyArr(cur.fname, leg.fname); - return cur; } -::cbVIDEOSOURCE Adapter::fromLegacy(const cbVIDEOSOURCE& leg) const { - ::cbVIDEOSOURCE cur{}; +void Adapter::fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const { copyArr(cur.name, leg.name); cur.fps = leg.fps; - return cur; } -::cbTRACKOBJ Adapter::fromLegacy(const cbTRACKOBJ& leg) const { - ::cbTRACKOBJ cur{}; +void Adapter::fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const { copyArr(cur.name, leg.name); cur.type = leg.type; cur.pointCount = leg.pointCount; - return cur; } -::cbPKT_FILECFG Adapter::fromLegacy(const cbPKT_FILECFG& leg) const { - ::cbPKT_FILECFG cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.options = leg.options; cur.duration = leg.duration; cur.recording = leg.recording; @@ -438,69 +379,68 @@ ::cbPKT_FILECFG Adapter::fromLegacy(const cbPKT_FILECFG& leg) const { copyArr(cur.username, leg.username); copyArr(cur.filename, leg.filename); // aka datetime copyArr(cur.comment, leg.comment); - return cur; } -NativeConfigBuffer Adapter::fromLegacy(const cbCFGBUFF& leg) const { +void Adapter::fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const { // TODO: VERIFY that each list that's assumed to be instrument-independent is in fact independent from any particular instrument. - NativeConfigBuffer cur{}; - cur.version = leg.version; + cur.version = cbVERSION_MAJOR * 100 + cbVERSION_MINOR; // Central's version field contains garbage data, so replace it with the protocol version cur.sysflags = leg.sysflags; - cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); - cur.sysinfo = fromLegacy(leg.sysinfo); - cur.procinfo = fromLegacy(leg.procinfo[instrument_idx]); + cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); + fromLegacy(cur.sysinfo, leg.sysinfo); + fromLegacy(cur.procinfo, leg.procinfo[instrument_idx]); copyArr(cur.bankinfo, leg.bankinfo[instrument_idx], this, &Adapter::fromLegacy); copyArr(cur.groupinfo, leg.groupinfo[instrument_idx], this, &Adapter::fromLegacy); copyArr(cur.filtinfo, leg.filtinfo[instrument_idx], this, &Adapter::fromLegacy); - cur.adaptinfo = fromLegacy(leg.adaptinfo[instrument_idx]); - cur.refelecinfo = fromLegacy(leg.refelecinfo[instrument_idx]); + fromLegacy(cur.adaptinfo, leg.adaptinfo[instrument_idx]); + fromLegacy(cur.refelecinfo, leg.refelecinfo[instrument_idx]); copyArr(cur.chaninfo, leg.chaninfo, this, &Adapter::fromLegacy); copyArr(cur.asBasis, leg.isSortingOptions.asBasis, this, &Adapter::fromLegacy); - copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); + // copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); // TODO: For some reason, this contains memory that's innaccessible // TODO: Move native isSortingOptions fields into a struct - cur.pktDetect = fromLegacy(leg.isSortingOptions.pktDetect); - cur.pktArtifReject = fromLegacy(leg.isSortingOptions.pktArtifReject); + fromLegacy(cur.pktDetect, leg.isSortingOptions.pktDetect); + fromLegacy(cur.pktArtifReject, leg.isSortingOptions.pktArtifReject); copyArr(cur.pktNoiseBoundary, leg.isSortingOptions.pktNoiseBoundary, this, &Adapter::fromLegacy); - cur.pktStatistics = fromLegacy(leg.isSortingOptions.pktStatistics); - cur.pktStatus = fromLegacy(leg.isSortingOptions.pktStatus); + fromLegacy(cur.pktStatistics, leg.isSortingOptions.pktStatistics); + fromLegacy(cur.pktStatus, leg.isSortingOptions.pktStatus); copyArr(cur.isNTrodeInfo, leg.isNTrodeInfo, this, &Adapter::fromLegacy); copyArr2D(cur.isWaveform, leg.isWaveform, this, &Adapter::fromLegacy); - cur.isLnc = fromLegacy(leg.isLnc[instrument_idx]); - cur.isNPlay = fromLegacy(leg.isNPlay); + fromLegacy(cur.isLnc, leg.isLnc[instrument_idx]); + fromLegacy(cur.isNPlay, leg.isNPlay); copyArr(cur.isVideoSource, leg.isVideoSource, this, &Adapter::fromLegacy); copyArr(cur.isTrackObj, leg.isTrackObj, this, &Adapter::fromLegacy); - cur.fileinfo = fromLegacy(leg.fileinfo); - - return cur; + fromLegacy(cur.fileinfo, leg.fileinfo); } -NativeNSPStatus Adapter::fromLegacy(const NSPStatus& leg) const { +void Adapter::fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const { switch(leg) { case NSPStatus::NSP_INIT: - return NativeNSPStatus::NSP_INIT; + cur = NativeNSPStatus::NSP_INIT; + break; case NSPStatus::NSP_NOIPADDR: - return NativeNSPStatus::NSP_NOIPADDR; + cur = NativeNSPStatus::NSP_NOIPADDR; + break; case NSPStatus::NSP_NOREPLY: - return NativeNSPStatus::NSP_NOREPLY; + cur = NativeNSPStatus::NSP_NOREPLY; + break; case NSPStatus::NSP_FOUND: - return NativeNSPStatus::NSP_FOUND; + cur = NativeNSPStatus::NSP_FOUND; + break; case NSPStatus::NSP_INVALID: + /* fallthrough */ default: - return NativeNSPStatus::NSP_INVALID; + cur = NativeNSPStatus::NSP_INVALID; + break; } } -::cbPKT_UNIT_SELECTION Adapter::fromLegacy(const cbPKT_UNIT_SELECTION& leg) const { - ::cbPKT_UNIT_SELECTION cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.lastchan = leg.lastchan; copyArr(cur.abyUnitSelections, leg.abyUnitSelections); - return cur; } -NativePCStatus Adapter::fromLegacy(const cbPcStatus& leg) const { - NativePCStatus cur{}; - cur.isSelection = fromLegacy(leg.isSelection[instrument_idx]); +void Adapter::fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const { + fromLegacy(cur.isSelection, leg.isSelection[instrument_idx]); cur.m_iBlockRecording = leg.m_iBlockRecording; cur.m_nPCStatusFlags = leg.m_nPCStatusFlags; cur.m_nNumFEChans = leg.m_nNumFEChans; @@ -513,101 +453,83 @@ NativePCStatus Adapter::fromLegacy(const cbPcStatus& leg) const { cur.m_nNumSerialChans = leg.m_nNumSerialChans; cur.m_nNumDigoutChans = leg.m_nNumDigoutChans; cur.m_nNumTotalChans = leg.m_nNumTotalChans; - cur.m_nNspStatus = fromLegacy(leg.m_nNspStatus[instrument_idx]); + fromLegacy(cur.m_nNspStatus, leg.m_nNspStatus[instrument_idx]); cur.m_nNumNTrodesPerInstrument = leg.m_nNumNTrodesPerInstrument[instrument_idx]; cur.m_nGeminiSystem = leg.m_nGeminiSystem; - return cur; } -NativeReceiveBuffer Adapter::fromLegacy(const cbRECBUFF& leg) const { - NativeReceiveBuffer cur{}; +void Adapter::fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const { cur.received = leg.received; cur.lasttime = leg.lasttime; cur.headwrap = leg.headwrap; cur.headindex = leg.headindex; copyArr(cur.buffer, leg.buffer); - return cur; } -NativeTransmitBuffer Adapter::fromLegacy(const cbXMTBUFF& leg) const { - NativeTransmitBuffer cur{}; +void Adapter::fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const { cur.transmitted = leg.transmitted; cur.headindex = leg.headindex; cur.tailindex = leg.tailindex; cur.last_valid_index = leg.last_valid_index; cur.bufferlen = leg.bufferlen; copyArr(cur.buffer, leg.buffer); - return cur; } -NativeTransmitBufferLocal Adapter::fromLegacy(const cbXMTBUFFLOCAL& leg) const { - NativeTransmitBufferLocal cur{}; +void Adapter::fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const { cur.transmitted = leg.transmitted; cur.headindex = leg.headindex; cur.tailindex = leg.tailindex; cur.last_valid_index = leg.last_valid_index; cur.bufferlen = leg.bufferlen; copyArr(cur.buffer, leg.buffer); - return cur; } -::cbPKT_SPK Adapter::fromLegacy(const cbPKT_SPK& leg) const { - ::cbPKT_SPK cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); copyArr(cur.fPattern, leg.fPattern); cur.nPeak = leg.nPeak; cur.nValley = leg.nValley; copyArr(cur.wave, leg.wave); - return cur; } -NativeSpikeCache Adapter::fromLegacy(const cbSPKCACHE& leg) const { - NativeSpikeCache cur{}; +void Adapter::fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const { cur.chid = leg.chid; cur.pktcnt = leg.pktcnt; cur.pktsize = leg.pktsize; cur.head = leg.head; cur.valid = leg.valid; copyArr(cur.spkpkt, leg.spkpkt, this, &Adapter::fromLegacy); - return cur; } -NativeSpikeBuffer Adapter::fromLegacy(const cbSPKBUFF& leg) const { - NativeSpikeBuffer cur{}; +void Adapter::fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const { cur.flags = leg.flags; cur.chidmax = leg.chidmax; cur.linesize = leg.linesize; cur.spkcount = leg.spkcount; copyArr(cur.cache, leg.cache, this, &Adapter::fromLegacy); - return cur; } -cbPKT_HEADER Adapter::toLegacy(const ::cbPKT_HEADER& cur) const { - cbPKT_HEADER leg{}; +void Adapter::toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const { leg.time = cur.time; leg.chid = cur.chid; leg.type = static_cast(cur.type); leg.dlen = cur.dlen; leg.instrument = cur.instrument; leg.reserved = cur.reserved; - return leg; } -cbPKT_SYSINFO Adapter::toLegacy(const ::cbPKT_SYSINFO& cur) const { - cbPKT_SYSINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.sysfreq = cur.sysfreq; leg.spikelen = cur.spikelen; leg.spikepre = cur.spikepre; leg.resetque = cur.resetque; leg.runlevel = cur.runlevel; leg.runflags = cur.runflags; - return leg; } -cbPKT_PROCINFO Adapter::toLegacy(const ::cbPKT_PROCINFO& cur) const { - cbPKT_PROCINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.idcode = cur.idcode; leg.idcode = cur.idcode; @@ -622,12 +544,10 @@ cbPKT_PROCINFO Adapter::toLegacy(const ::cbPKT_PROCINFO& cur) const { leg.hoopcount = cur.hoopcount; leg.reserved = cur.reserved; leg.version = cur.version; - return leg; } -cbPKT_BANKINFO Adapter::toLegacy(const ::cbPKT_BANKINFO& cur) const { - cbPKT_BANKINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.bank = cur.bank; leg.idcode = cur.idcode; @@ -635,24 +555,20 @@ cbPKT_BANKINFO Adapter::toLegacy(const ::cbPKT_BANKINFO& cur) const { copyArr(leg.label, cur.label); leg.chanbase = cur.chanbase; leg.chancount = cur.chancount; - return leg; } -cbPKT_GROUPINFO Adapter::toLegacy(const ::cbPKT_GROUPINFO& cur) const { - cbPKT_GROUPINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.group = cur.group; copyArr(leg.label, cur.label); leg.period = cur.period; leg.length = cur.length; copyArr(leg.list, cur.list); - return leg; } -cbPKT_FILTINFO Adapter::toLegacy(const ::cbPKT_FILTINFO& cur) const { - cbPKT_FILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.filt = cur.filt; copyArr(leg.label, cur.label); @@ -671,73 +587,59 @@ cbPKT_FILTINFO Adapter::toLegacy(const ::cbPKT_FILTINFO& cur) const { leg.sos2a2 = cur.sos2a2; leg.sos2b1 = cur.sos2b1; leg.sos2b2 = cur.sos2b2; - return leg; } -cbPKT_ADAPTFILTINFO Adapter::toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) const { - cbPKT_ADAPTFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.nMode = cur.nMode; leg.dLearningRate = cur.dLearningRate; leg.nRefChan1 = cur.nRefChan1; leg.nRefChan2 = cur.nRefChan2; - return leg; } -cbPKT_REFELECFILTINFO Adapter::toLegacy(const ::cbPKT_REFELECFILTINFO& cur) const { - cbPKT_REFELECFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.nMode = cur.nMode; leg.nRefChan = cur.nRefChan; - return leg; } -cbSCALING Adapter::toLegacy(const ::cbSCALING& cur) const { - cbSCALING leg{}; +void Adapter::toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const { leg.digmin = cur.digmin; leg.digmax = cur.digmax; leg.anamin = cur.anamin; leg.anamax = cur.anamax; leg.anagain = cur.anagain; copyArr(leg.anaunit, cur.anaunit); - return leg; } -cbFILTDESC Adapter::toLegacy(const ::cbFILTDESC& cur) const { - cbFILTDESC leg{}; +void Adapter::toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const { leg.hpfreq = cur.hpfreq; leg.hporder = cur.hporder; leg.hptype = cur.hptype; leg.lpfreq = cur.lpfreq; leg.lporder = cur.lporder; leg.lptype = cur.lptype; - return leg; } -cbMANUALUNITMAPPING Adapter::toLegacy(const ::cbMANUALUNITMAPPING& cur) const { - cbMANUALUNITMAPPING leg{}; +void Adapter::toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const { leg.nOverride = cur.nOverride; copyArr(leg.afOrigin, cur.afOrigin); copyArr2D(leg.afShape, cur.afShape); leg.aPhi = cur.aPhi; leg.bValid = cur.bValid; - return leg; } -cbHOOP Adapter::toLegacy(const ::cbHOOP& cur) const { - cbHOOP leg{}; +void Adapter::toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const { leg.valid = cur.valid; leg.time = cur.time; leg.min = cur.min; leg.max = cur.max; - return leg; } -cbPKT_CHANINFO Adapter::toLegacy(const ::cbPKT_CHANINFO& cur) const { - cbPKT_CHANINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.proc = cur.proc; leg.bank = cur.bank; @@ -748,15 +650,15 @@ cbPKT_CHANINFO Adapter::toLegacy(const ::cbPKT_CHANINFO& cur) const { leg.aoutcaps = cur.aoutcaps; leg.ainpcaps = cur.ainpcaps; leg.spkcaps = cur.spkcaps; - leg.physcalin = toLegacy(cur.physcalin); - leg.phyfiltin = toLegacy(cur.phyfiltin); - leg.physcalout = toLegacy(cur.physcalout); - leg.phyfiltout = toLegacy(cur.phyfiltout); + toLegacy(leg.physcalin, cur.physcalin); + toLegacy(leg.phyfiltin, cur.phyfiltin); + toLegacy(leg.physcalout, cur.physcalout); + toLegacy(leg.phyfiltout, cur.phyfiltout); copyArr(leg.label, cur.label); leg.userflags = cur.userflags; copyArr(leg.position, cur.position); - leg.scalin = toLegacy(cur.scalin); - leg.scalout = toLegacy(cur.scalout); + toLegacy(leg.scalin, cur.scalin); + toLegacy(leg.scalout, cur.scalout); leg.doutopts = cur.doutopts; leg.dinpopts = cur.dinpopts; leg.aoutopts = cur.aoutopts; @@ -784,22 +686,18 @@ cbPKT_CHANINFO Adapter::toLegacy(const ::cbPKT_CHANINFO& cur) const { leg.refelecchan = cur.refelecchan; copyArr(leg.unitmapping, cur.unitmapping, this, &Adapter::toLegacy); copyArr2D(leg.spkhoops, cur.spkhoops, this, &Adapter::toLegacy); - return leg; } -cbPKT_FS_BASIS Adapter::toLegacy(const ::cbPKT_FS_BASIS& cur) const { - cbPKT_FS_BASIS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.mode = cur.mode; leg.fs = cur.fs; copyArr2D(leg.basis, cur.basis); - return leg; } -cbPKT_SS_MODELSET Adapter::toLegacy(const ::cbPKT_SS_MODELSET& cur) const { - cbPKT_SS_MODELSET leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.unit_number = cur.unit_number; leg.valid = cur.valid; @@ -814,37 +712,29 @@ cbPKT_SS_MODELSET Adapter::toLegacy(const ::cbPKT_SS_MODELSET& cur) const { leg.subcluster_spread_factor_denominator = cur.subcluster_spread_factor_denominator; leg.mu_e = cur.mu_e; leg.sigma_e_squared = cur.sigma_e_squared; - return leg; } -cbPKT_SS_DETECT Adapter::toLegacy(const ::cbPKT_SS_DETECT& cur) const { - cbPKT_SS_DETECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.fThreshold = cur.fThreshold; leg.fMultiplier = cur.fMultiplier; - return leg; } -cbPKT_SS_ARTIF_REJECT Adapter::toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) const { - cbPKT_SS_ARTIF_REJECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.nMaxSimulChans = cur.nMaxSimulChans; leg.nRefractoryCount = cur.nRefractoryCount; - return leg; } -cbPKT_SS_NOISE_BOUNDARY Adapter::toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) const { - cbPKT_SS_NOISE_BOUNDARY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; copyArr(leg.afc, cur.afc); copyArr2D(leg.afS, cur.afS); - return leg; } -cbPKT_SS_STATISTICS Adapter::toLegacy(const ::cbPKT_SS_STATISTICS& cur) const { - cbPKT_SS_STATISTICS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.nUpdateSpikes = cur.nUpdateSpikes; leg.nAutoalg = cur.nAutoalg; leg.nMode = cur.nMode; @@ -857,63 +747,51 @@ cbPKT_SS_STATISTICS Adapter::toLegacy(const ::cbPKT_SS_STATISTICS& cur) const { leg.fClusterHistMinPeakPercentage = cur.fClusterHistMinPeakPercentage; leg.nWaveBasisSize = cur.nWaveBasisSize; leg.nWaveSampleSize = cur.nWaveSampleSize; - return leg; } -cbAdaptControl Adapter::toLegacy(const ::cbAdaptControl& cur) const { - cbAdaptControl leg{}; +void Adapter::toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const { leg.nMode = cur.nMode; leg.fTimeOutMinutes = cur.fTimeOutMinutes; leg.fElapsedMinutes = cur.fElapsedMinutes; - return leg; } -cbPKT_SS_STATUS Adapter::toLegacy(const ::cbPKT_SS_STATUS& cur) const { - cbPKT_SS_STATUS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); - leg.cntlUnitStats = toLegacy(cur.cntlUnitStats); - leg.cntlNumUnits = toLegacy(cur.cntlNumUnits); - return leg; +void Adapter::toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + toLegacy(leg.cntlUnitStats, cur.cntlUnitStats); + toLegacy(leg.cntlNumUnits, cur.cntlNumUnits); } -cbSPIKE_SORTING Adapter::toLegacy(const ::cbproto::SpikeSorting& cur) const { - cbSPIKE_SORTING leg{}; +void Adapter::toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const { copyArr(leg.asBasis, cur.basis, this, &Adapter::toLegacy); copyArr2D(leg.asSortModel, cur.models, this, &Adapter::toLegacy); - leg.pktDetect = toLegacy(cur.detect); - leg.pktArtifReject = toLegacy(cur.artifact_reject); + toLegacy(leg.pktDetect, cur.detect); + toLegacy(leg.pktArtifReject, cur.artifact_reject); copyArr(leg.pktNoiseBoundary, cur.noise_boundary, this, &Adapter::toLegacy); - leg.pktStatistics = toLegacy(cur.statistics); - leg.pktStatus = toLegacy(cur.status); - return leg; + toLegacy(leg.pktStatistics, cur.statistics); + toLegacy(leg.pktStatus, cur.status); } -cbPKT_NTRODEINFO Adapter::toLegacy(const ::cbPKT_NTRODEINFO& cur) const { - cbPKT_NTRODEINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.ntrode = cur.ntrode; copyArr(leg.label, cur.label); copyArr2D(leg.ellipses, cur.ellipses, this, &Adapter::toLegacy); leg.nSite = cur.nSite; leg.fs = cur.fs; copyArr(leg.nChan, cur.nChan); - return leg; } -cbWaveformData Adapter::toLegacy(const ::cbWaveformData& cur) const { - cbWaveformData leg{}; +void Adapter::toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const { leg.offset = cur.offset; // aka sineFrequency leg.seq = cur.seq; // aka sineAmplitude leg.seqTotal = cur.seqTotal; leg.phases = cur.phases; copyArr(leg.duration, cur.duration); copyArr(leg.amplitude, cur.amplitude); - return leg; } -cbPKT_AOUT_WAVEFORM Adapter::toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const { - cbPKT_AOUT_WAVEFORM leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.mode = cur.mode; leg.repeats = cur.repeats; @@ -922,22 +800,18 @@ cbPKT_AOUT_WAVEFORM Adapter::toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const { leg.trigValue = cur.trigValue; leg.trigNum = cur.trigNum; leg.active = cur.active; - leg.wave = toLegacy(cur.wave); - return leg; + toLegacy(leg.wave, cur.wave); } -cbPKT_LNC Adapter::toLegacy(const ::cbPKT_LNC& cur) const { - cbPKT_LNC leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.lncFreq = cur.lncFreq; leg.lncRefChan = cur.lncRefChan; leg.lncGlobalMode = cur.lncGlobalMode; - return leg; } -cbPKT_NPLAY Adapter::toLegacy(const ::cbPKT_NPLAY& cur) const { - cbPKT_NPLAY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.ftime = cur.ftime; // aka opt leg.stime = cur.stime; leg.etime = cur.etime; @@ -946,27 +820,21 @@ cbPKT_NPLAY Adapter::toLegacy(const ::cbPKT_NPLAY& cur) const { leg.flags = cur.flags; leg.speed = cur.speed; copyArr(leg.fname, cur.fname); - return leg; } -cbVIDEOSOURCE Adapter::toLegacy(const ::cbVIDEOSOURCE& cur) const { - cbVIDEOSOURCE leg{}; +void Adapter::toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const { copyArr(leg.name, cur.name); leg.fps = cur.fps; - return leg; } -cbTRACKOBJ Adapter::toLegacy(const ::cbTRACKOBJ& cur) const { - cbTRACKOBJ leg{}; +void Adapter::toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const { copyArr(leg.name, cur.name); leg.type = cur.type; leg.pointCount = cur.pointCount; - return leg; } -cbPKT_FILECFG Adapter::toLegacy(const ::cbPKT_FILECFG& cur) const { - cbPKT_FILECFG leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.options = cur.options; leg.duration = cur.duration; leg.recording = cur.recording; @@ -974,73 +842,68 @@ cbPKT_FILECFG Adapter::toLegacy(const ::cbPKT_FILECFG& cur) const { copyArr(leg.username, cur.username); copyArr(leg.filename, cur.filename); // aka datetime copyArr(leg.comment, cur.comment); - return leg; } -NSPStatus Adapter::toLegacy(const NativeNSPStatus& cur) const { +void Adapter::toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const { switch(cur) { case NativeNSPStatus::NSP_INIT: - return NSPStatus::NSP_INIT; + leg = NSPStatus::NSP_INIT; + break; case NativeNSPStatus::NSP_NOIPADDR: - return NSPStatus::NSP_NOIPADDR; + leg = NSPStatus::NSP_NOIPADDR; + break; case NativeNSPStatus::NSP_NOREPLY: - return NSPStatus::NSP_NOREPLY; + leg = NSPStatus::NSP_NOREPLY; + break; case NativeNSPStatus::NSP_FOUND: - return NSPStatus::NSP_FOUND; + leg = NSPStatus::NSP_FOUND; + break; case NativeNSPStatus::NSP_INVALID: + /* fallthrough */ default: - return NSPStatus::NSP_INVALID; + leg = NSPStatus::NSP_INVALID; + break; } } -cbPKT_UNIT_SELECTION Adapter::toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const { - cbPKT_UNIT_SELECTION leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.lastchan = cur.lastchan; copyArr(leg.abyUnitSelections, cur.abyUnitSelections); - return leg; } -cbRECBUFF Adapter::toLegacy(const NativeReceiveBuffer& cur) const { - cbRECBUFF leg{}; +void Adapter::toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const { leg.received = cur.received; leg.lasttime = cur.lasttime; leg.headwrap = cur.headwrap; leg.headindex = cur.headindex; copyArr(leg.buffer, cur.buffer); - return leg; } -cbXMTBUFF Adapter::toLegacy(const NativeTransmitBuffer& cur) const { - cbXMTBUFF leg{}; +void Adapter::toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const { leg.transmitted = cur.transmitted; leg.headindex = cur.headindex; leg.tailindex = cur.tailindex; leg.last_valid_index = cur.last_valid_index; leg.bufferlen = cur.bufferlen; copyArr(leg.buffer, cur.buffer); - return leg; } -cbXMTBUFFLOCAL Adapter::toLegacy(const NativeTransmitBufferLocal& cur) const { - cbXMTBUFFLOCAL leg{}; +void Adapter::toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const { leg.transmitted = cur.transmitted; leg.headindex = cur.headindex; leg.tailindex = cur.tailindex; leg.last_valid_index = cur.last_valid_index; leg.bufferlen = cur.bufferlen; copyArr(leg.buffer, cur.buffer); - return leg; } -cbPKT_SPK Adapter::toLegacy(const ::cbPKT_SPK& cur) const { - cbPKT_SPK leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); copyArr(leg.fPattern, leg.fPattern); leg.nPeak = cur.nPeak; leg.nValley = cur.nValley; copyArr(leg.wave, cur.wave); - return leg; } Adapter::Adapter(uint8_t instrument_idx, void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) @@ -1129,106 +992,88 @@ uint32_t* Adapter::getLocalXmtBufferPtr() { return xmt->buffer; } -Result<::cbPKT_PROCINFO> Adapter::getProcInfo() const { - if (instrument_idx >= std::size(cfg->procinfo)) { - return Result<::cbPKT_PROCINFO>::error("Instrument index out of range"); - } - return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx])); +Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { + fromLegacy(buf, cfg->procinfo[instrument_idx]); + return Result::ok(); } -Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint32_t bank_num) const { - if (instrument_idx >= std::size(cfg->bankinfo)) { - return Result<::cbPKT_BANKINFO>::error("Instrument index out of range"); - } +Result Adapter::getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const { uint32_t bank_idx = bank_num - 1; if (bank_idx >= std::size(cfg->bankinfo[0])) { - return Result<::cbPKT_BANKINFO>::error("Bank number out of range"); + return Result::error("Bank number out of range"); } - return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx])); + fromLegacy(buf, cfg->bankinfo[instrument_idx][bank_idx]); + return Result::ok(); } -Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint32_t filter_num) const { - if (instrument_idx >= std::size(cfg->filtinfo)) { - return Result<::cbPKT_FILTINFO>::error("Instrument index out of range"); - } +Result Adapter::getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const { uint32_t filter_idx = filter_num - 1; if (filter_idx >= std::size(cfg->filtinfo[0])) { - return Result<::cbPKT_FILTINFO>::error("Filter number out of range"); + return Result::error("Filter number out of range"); } - return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx])); + fromLegacy(buf, cfg->filtinfo[instrument_idx][filter_idx]); + return Result::ok(); } -Result<::cbPKT_CHANINFO> Adapter::getChanInfo(uint32_t channel_idx) const { +Result Adapter::getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const { if (channel_idx >= std::size(cfg->chaninfo)) { - return Result<::cbPKT_CHANINFO>::error("Channel number out of range"); + return Result::error("Channel number out of range"); } - return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx])); + fromLegacy(buf, cfg->chaninfo[channel_idx]); + return Result::ok(); } -Result<::cbPKT_SYSINFO> Adapter::getSysInfo() const { - return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo)); +Result Adapter::getSysInfo(::cbPKT_SYSINFO& buf) const { + fromLegacy(buf, cfg->sysinfo); + return Result::ok(); } -Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint32_t group_idx) const { - if (instrument_idx >= std::size(cfg->groupinfo)) { - return Result<::cbPKT_GROUPINFO>::error("Instrument index out of range"); - } +Result Adapter::getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const { if (group_idx >= std::size(cfg->groupinfo[0])) { - return Result<::cbPKT_GROUPINFO>::error("Group index out of range"); + return Result::error("Group index out of range"); } - return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx])); + fromLegacy(buf, cfg->groupinfo[instrument_idx][group_idx]); + return Result::ok(); } -Result Adapter::getConfigBuffer() const { - if (instrument_idx >= std::size(cfg->procinfo)) { - return Result::error("Instrument index out of range"); - } - return Result::ok(fromLegacy(*cfg)); +Result Adapter::getConfigBuffer(NativeConfigBuffer& buf) const { + fromLegacy(buf, *cfg); + return Result::ok(); } -Result Adapter::getPcStatus() const { - if (instrument_idx >= std::size(status->isSelection)) { - return Result::error("Instrument index out of range"); - } - return Result::ok(fromLegacy(*status)); +Result Adapter::getPcStatus(NativePCStatus& buf) const { + fromLegacy(buf, *status); + return Result::ok(); } -Result Adapter::getSpikeCache(uint32_t channel_idx) const { +Result Adapter::getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const { if (channel_idx >= std::size(spike->cache)) { - return Result::error("Channel index out of range"); + return Result::error("Channel index out of range"); } - return Result::ok(fromLegacy(spike->cache[channel_idx])); + fromLegacy(buf, spike->cache[channel_idx]); + return Result::ok(); } Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { - if (instrument_idx >= std::size(cfg->procinfo)) { - return Result::error("Instrument index out of range"); - } - cfg->procinfo[instrument_idx] = toLegacy(info); + toLegacy(cfg->procinfo[instrument_idx], info); return Result::ok(); } Result Adapter::setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) { - if (instrument_idx >= std::size(cfg->bankinfo)) { - return Result::error("Instrument index out of range"); - } uint32_t bank_idx = bank_num - 1; if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result::error("Bank number out of range"); } - cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info); + toLegacy(cfg->bankinfo[instrument_idx][bank_idx], info); return Result::ok(); } Result Adapter::setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) { - if (instrument_idx >= std::size(cfg->filtinfo)) { - return Result::error("Instrument index out of range"); - } uint32_t filter_idx = filter_num - 1; if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result::error("Filter number out of range"); } - cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info); + toLegacy(cfg->filtinfo[instrument_idx][filter_idx], info); return Result::ok(); } @@ -1236,31 +1081,25 @@ Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& if (channel_idx >= std::size(cfg->chaninfo)) { return Result::error("Channel number out of range"); } - cfg->chaninfo[channel_idx] = toLegacy(info); + toLegacy(cfg->chaninfo[channel_idx], info); return Result::ok(); } Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { - cfg->sysinfo = toLegacy(info); + toLegacy(cfg->sysinfo, info); return Result::ok(); } Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { - if (instrument_idx >= std::size(cfg->groupinfo)) { - return Result::error("Instrument index out of range"); - } if (group_idx >= std::size(cfg->groupinfo[0])) { return Result::error("Group index out of range"); } - cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info); + toLegacy(cfg->groupinfo[instrument_idx][group_idx], info); return Result::ok(); } Result Adapter::setNspStatus(const NativeNSPStatus& status) const { - if (instrument_idx >= std::size(this->status->isSelection)) { - return Result::error("Instrument index out of range"); - } - this->status->m_nNspStatus[instrument_idx] = toLegacy(status); + toLegacy(this->status->m_nNspStatus[instrument_idx], status); return Result::ok(); } diff --git a/src/cbshm/src/central_adapters/v4_1.cpp b/src/cbshm/src/central_adapters/v4_1.cpp index dcc643d2..015934d8 100644 --- a/src/cbshm/src/central_adapters/v4_1.cpp +++ b/src/cbshm/src/central_adapters/v4_1.cpp @@ -42,32 +42,27 @@ size_t BootstrapAdapter::getReceiveBufferLen() const { return sizeof(cbRECBUFFLEN); } -::cbPKT_HEADER Adapter::fromLegacy(const cbPKT_HEADER& leg) const { - ::cbPKT_HEADER cur{}; +void Adapter::fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const { cur.time = leg.time; cur.chid = leg.chid; cur.type = leg.type; cur.dlen = leg.dlen; cur.instrument = leg.instrument; cur.reserved = leg.reserved; - return cur; } -::cbPKT_SYSINFO Adapter::fromLegacy(const cbPKT_SYSINFO& leg) const { - ::cbPKT_SYSINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.sysfreq = leg.sysfreq; cur.spikelen = leg.spikelen; cur.spikepre = leg.spikepre; cur.resetque = leg.resetque; cur.runlevel = leg.runlevel; cur.runflags = leg.runflags; - return cur; } -::cbPKT_PROCINFO Adapter::fromLegacy(const cbPKT_PROCINFO& leg) const { - ::cbPKT_PROCINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.idcode = leg.idcode; cur.idcode = leg.idcode; @@ -82,12 +77,10 @@ ::cbPKT_PROCINFO Adapter::fromLegacy(const cbPKT_PROCINFO& leg) const { cur.hoopcount = leg.hoopcount; cur.reserved = leg.reserved; cur.version = leg.version; - return cur; } -::cbPKT_BANKINFO Adapter::fromLegacy(const cbPKT_BANKINFO& leg) const { - ::cbPKT_BANKINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.bank = leg.bank; cur.idcode = leg.idcode; @@ -95,24 +88,20 @@ ::cbPKT_BANKINFO Adapter::fromLegacy(const cbPKT_BANKINFO& leg) const { copyArr(cur.label, leg.label); cur.chanbase = leg.chanbase; cur.chancount = leg.chancount; - return cur; } -::cbPKT_GROUPINFO Adapter::fromLegacy(const cbPKT_GROUPINFO& leg) const { - ::cbPKT_GROUPINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.group = leg.group; copyArr(cur.label, leg.label); cur.period = leg.period; cur.length = leg.length; copyArr(cur.list, leg.list); - return cur; } -::cbPKT_FILTINFO Adapter::fromLegacy(const cbPKT_FILTINFO& leg) const { - ::cbPKT_FILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.filt = leg.filt; copyArr(cur.label, leg.label); @@ -131,73 +120,59 @@ ::cbPKT_FILTINFO Adapter::fromLegacy(const cbPKT_FILTINFO& leg) const { cur.sos2a2 = leg.sos2a2; cur.sos2b1 = leg.sos2b1; cur.sos2b2 = leg.sos2b2; - return cur; } -::cbPKT_ADAPTFILTINFO Adapter::fromLegacy(const cbPKT_ADAPTFILTINFO& leg) const { - ::cbPKT_ADAPTFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.nMode = leg.nMode; cur.dLearningRate = leg.dLearningRate; cur.nRefChan1 = leg.nRefChan1; cur.nRefChan2 = leg.nRefChan2; - return cur; } -::cbPKT_REFELECFILTINFO Adapter::fromLegacy(const cbPKT_REFELECFILTINFO& leg) const { - ::cbPKT_REFELECFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.nMode = leg.nMode; cur.nRefChan = leg.nRefChan; - return cur; } -::cbSCALING Adapter::fromLegacy(const cbSCALING& leg) const { - ::cbSCALING cur{}; +void Adapter::fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const { cur.digmin = leg.digmin; cur.digmax = leg.digmax; cur.anamin = leg.anamin; cur.anamax = leg.anamax; cur.anagain = leg.anagain; copyArr(cur.anaunit, leg.anaunit); - return cur; } -::cbFILTDESC Adapter::fromLegacy(const cbFILTDESC& leg) const { - ::cbFILTDESC cur{}; +void Adapter::fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const { cur.hpfreq = leg.hpfreq; cur.hporder = leg.hporder; cur.hptype = leg.hptype; cur.lpfreq = leg.lpfreq; cur.lporder = leg.lporder; cur.lptype = leg.lptype; - return cur; } -::cbMANUALUNITMAPPING Adapter::fromLegacy(const cbMANUALUNITMAPPING& leg) const { - ::cbMANUALUNITMAPPING cur{}; +void Adapter::fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const { cur.nOverride = leg.nOverride; copyArr(cur.afOrigin, leg.afOrigin); copyArr2D(cur.afShape, leg.afShape); cur.aPhi = leg.aPhi; cur.bValid = leg.bValid; - return cur; } -::cbHOOP Adapter::fromLegacy(const cbHOOP& leg) const { - ::cbHOOP cur{}; +void Adapter::fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const { cur.valid = leg.valid; cur.time = leg.time; cur.min = leg.min; cur.max = leg.max; - return cur; } -::cbPKT_CHANINFO Adapter::fromLegacy(const cbPKT_CHANINFO& leg) const { - ::cbPKT_CHANINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.proc = leg.proc; cur.bank = leg.bank; @@ -208,15 +183,15 @@ ::cbPKT_CHANINFO Adapter::fromLegacy(const cbPKT_CHANINFO& leg) const { cur.aoutcaps = leg.aoutcaps; cur.ainpcaps = leg.ainpcaps; cur.spkcaps = leg.spkcaps; - cur.physcalin = fromLegacy(leg.physcalin); - cur.phyfiltin = fromLegacy(leg.phyfiltin); - cur.physcalout = fromLegacy(leg.physcalout); - cur.phyfiltout = fromLegacy(leg.phyfiltout); + fromLegacy(cur.physcalin, leg.physcalin); + fromLegacy(cur.phyfiltin, leg.phyfiltin); + fromLegacy(cur.physcalout, leg.physcalout); + fromLegacy(cur.phyfiltout, leg.phyfiltout); copyArr(cur.label, leg.label); cur.userflags = leg.userflags; copyArr(cur.position, leg.position); - cur.scalin = fromLegacy(leg.scalin); - cur.scalout = fromLegacy(leg.scalout); + fromLegacy(cur.scalin, leg.scalin); + fromLegacy(cur.scalout, leg.scalout); cur.doutopts = leg.doutopts; cur.dinpopts = leg.dinpopts; cur.aoutopts = leg.aoutopts; @@ -247,22 +222,18 @@ ::cbPKT_CHANINFO Adapter::fromLegacy(const cbPKT_CHANINFO& leg) const { cur.refelecchan = leg.refelecchan; copyArr(cur.unitmapping, leg.unitmapping, this, &Adapter::fromLegacy); copyArr2D(cur.spkhoops, leg.spkhoops, this, &Adapter::fromLegacy); - return cur; } -::cbPKT_FS_BASIS Adapter::fromLegacy(const cbPKT_FS_BASIS& leg) const { - ::cbPKT_FS_BASIS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.mode = leg.mode; cur.fs = leg.fs; copyArr2D(cur.basis, leg.basis); - return cur; } -::cbPKT_SS_MODELSET Adapter::fromLegacy(const cbPKT_SS_MODELSET& leg) const { - ::cbPKT_SS_MODELSET cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.unit_number = leg.unit_number; cur.valid = leg.valid; @@ -277,37 +248,29 @@ ::cbPKT_SS_MODELSET Adapter::fromLegacy(const cbPKT_SS_MODELSET& leg) const { cur.subcluster_spread_factor_denominator = leg.subcluster_spread_factor_denominator; cur.mu_e = leg.mu_e; cur.sigma_e_squared = leg.sigma_e_squared; - return cur; } -::cbPKT_SS_DETECT Adapter::fromLegacy(const cbPKT_SS_DETECT& leg) const { - ::cbPKT_SS_DETECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.fThreshold = leg.fThreshold; cur.fMultiplier = leg.fMultiplier; - return cur; } -::cbPKT_SS_ARTIF_REJECT Adapter::fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) const { - ::cbPKT_SS_ARTIF_REJECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.nMaxSimulChans = leg.nMaxSimulChans; cur.nRefractoryCount = leg.nRefractoryCount; - return cur; } -::cbPKT_SS_NOISE_BOUNDARY Adapter::fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) const { - ::cbPKT_SS_NOISE_BOUNDARY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; copyArr(cur.afc, leg.afc); copyArr2D(cur.afS, leg.afS); - return cur; } -::cbPKT_SS_STATISTICS Adapter::fromLegacy(const cbPKT_SS_STATISTICS& leg) const { - ::cbPKT_SS_STATISTICS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.nUpdateSpikes = leg.nUpdateSpikes; cur.nAutoalg = leg.nAutoalg; cur.nMode = leg.nMode; @@ -320,63 +283,51 @@ ::cbPKT_SS_STATISTICS Adapter::fromLegacy(const cbPKT_SS_STATISTICS& leg) const cur.fClusterHistMinPeakPercentage = leg.fClusterHistMinPeakPercentage; cur.nWaveBasisSize = leg.nWaveBasisSize; cur.nWaveSampleSize = leg.nWaveSampleSize; - return cur; } -::cbAdaptControl Adapter::fromLegacy(const cbAdaptControl& leg) const { - ::cbAdaptControl cur{}; +void Adapter::fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const { cur.nMode = leg.nMode; cur.fTimeOutMinutes = leg.fTimeOutMinutes; cur.fElapsedMinutes = leg.fElapsedMinutes; - return cur; } -::cbPKT_SS_STATUS Adapter::fromLegacy(const cbPKT_SS_STATUS& leg) const { - ::cbPKT_SS_STATUS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); - cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats); - cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits); - return cur; +void Adapter::fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + fromLegacy(cur.cntlUnitStats, leg.cntlUnitStats); + fromLegacy(cur.cntlNumUnits, leg.cntlNumUnits); } -::cbproto::SpikeSorting Adapter::fromLegacy(const cbSPIKE_SORTING& leg) const { - ::cbproto::SpikeSorting cur{}; +void Adapter::fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const { copyArr(cur.basis, leg.asBasis, this, &Adapter::fromLegacy); copyArr2D(cur.models, leg.asSortModel, this, &Adapter::fromLegacy); - cur.detect = fromLegacy(leg.pktDetect); - cur.artifact_reject = fromLegacy(leg.pktArtifReject); + fromLegacy(cur.detect, leg.pktDetect); + fromLegacy(cur.artifact_reject, leg.pktArtifReject); copyArr(cur.noise_boundary, leg.pktNoiseBoundary, this, &Adapter::fromLegacy); - cur.statistics = fromLegacy(leg.pktStatistics); - cur.status = fromLegacy(leg.pktStatus); - return cur; + fromLegacy(cur.statistics, leg.pktStatistics); + fromLegacy(cur.status, leg.pktStatus); } -::cbPKT_NTRODEINFO Adapter::fromLegacy(const cbPKT_NTRODEINFO& leg) const { - ::cbPKT_NTRODEINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.ntrode = leg.ntrode; copyArr(cur.label, leg.label); copyArr2D(cur.ellipses, leg.ellipses, this, &Adapter::fromLegacy); cur.nSite = leg.nSite; cur.fs = leg.fs; copyArr(cur.nChan, leg.nChan); - return cur; } -::cbWaveformData Adapter::fromLegacy(const cbWaveformData& leg) const { - ::cbWaveformData cur{}; +void Adapter::fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const { cur.offset = leg.offset; // aka sineFrequency cur.seq = leg.seq; // aka sineAmplitude cur.seqTotal = leg.seqTotal; cur.phases = leg.phases; copyArr(cur.duration, leg.duration); copyArr(cur.amplitude, leg.amplitude); - return cur; } -::cbPKT_AOUT_WAVEFORM Adapter::fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const { - ::cbPKT_AOUT_WAVEFORM cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.mode = leg.mode; cur.repeats = leg.repeats; @@ -386,22 +337,18 @@ ::cbPKT_AOUT_WAVEFORM Adapter::fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const cur.trigValue = leg.trigValue; cur.trigNum = leg.trigNum; cur.active = leg.active; - cur.wave = fromLegacy(leg.wave); - return cur; + fromLegacy(cur.wave, leg.wave); } -::cbPKT_LNC Adapter::fromLegacy(const cbPKT_LNC& leg) const { - ::cbPKT_LNC cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.lncFreq = leg.lncFreq; cur.lncRefChan = leg.lncRefChan; cur.lncGlobalMode = leg.lncGlobalMode; - return cur; } -::cbPKT_NPLAY Adapter::fromLegacy(const cbPKT_NPLAY& leg) const { - ::cbPKT_NPLAY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.ftime = leg.ftime; // aka opt cur.stime = leg.stime; cur.etime = leg.etime; @@ -410,27 +357,21 @@ ::cbPKT_NPLAY Adapter::fromLegacy(const cbPKT_NPLAY& leg) const { cur.flags = leg.flags; cur.speed = leg.speed; copyArr(cur.fname, leg.fname); - return cur; } -::cbVIDEOSOURCE Adapter::fromLegacy(const cbVIDEOSOURCE& leg) const { - ::cbVIDEOSOURCE cur{}; +void Adapter::fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const { copyArr(cur.name, leg.name); cur.fps = leg.fps; - return cur; } -::cbTRACKOBJ Adapter::fromLegacy(const cbTRACKOBJ& leg) const { - ::cbTRACKOBJ cur{}; +void Adapter::fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const { copyArr(cur.name, leg.name); cur.type = leg.type; cur.pointCount = leg.pointCount; - return cur; } -::cbPKT_FILECFG Adapter::fromLegacy(const cbPKT_FILECFG& leg) const { - ::cbPKT_FILECFG cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.options = leg.options; cur.duration = leg.duration; cur.recording = leg.recording; @@ -438,68 +379,68 @@ ::cbPKT_FILECFG Adapter::fromLegacy(const cbPKT_FILECFG& leg) const { copyArr(cur.username, leg.username); copyArr(cur.filename, leg.filename); // aka datetime copyArr(cur.comment, leg.comment); - return cur; } -NativeConfigBuffer Adapter::fromLegacy(const cbCFGBUFF& leg) const { +void Adapter::fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const { // TODO: VERIFY that each list that's assumed to be instrument-independent is in fact independent from any particular instrument. - NativeConfigBuffer cur{}; - cur.version = leg.version; + cur.version = cbVERSION_MAJOR * 100 + cbVERSION_MINOR; // Central's version field contains garbage data, so replace it with the protocol version cur.sysflags = leg.sysflags; - cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); - cur.sysinfo = fromLegacy(leg.sysinfo); - cur.procinfo = fromLegacy(leg.procinfo[instrument_idx]); + cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); + fromLegacy(cur.sysinfo, leg.sysinfo); + fromLegacy(cur.procinfo, leg.procinfo[instrument_idx]); copyArr(cur.bankinfo, leg.bankinfo[instrument_idx], this, &Adapter::fromLegacy); copyArr(cur.groupinfo, leg.groupinfo[instrument_idx], this, &Adapter::fromLegacy); copyArr(cur.filtinfo, leg.filtinfo[instrument_idx], this, &Adapter::fromLegacy); - cur.adaptinfo = fromLegacy(leg.adaptinfo[instrument_idx]); - cur.refelecinfo = fromLegacy(leg.refelecinfo[instrument_idx]); + fromLegacy(cur.adaptinfo, leg.adaptinfo[instrument_idx]); + fromLegacy(cur.refelecinfo, leg.refelecinfo[instrument_idx]); copyArr(cur.chaninfo, leg.chaninfo, this, &Adapter::fromLegacy); copyArr(cur.asBasis, leg.isSortingOptions.asBasis, this, &Adapter::fromLegacy); - copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); + // copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); // TODO: For some reason, this contains memory that's innaccessible // TODO: Move native isSortingOptions fields into a struct - cur.pktDetect = fromLegacy(leg.isSortingOptions.pktDetect); - cur.pktArtifReject = fromLegacy(leg.isSortingOptions.pktArtifReject); + fromLegacy(cur.pktDetect, leg.isSortingOptions.pktDetect); + fromLegacy(cur.pktArtifReject, leg.isSortingOptions.pktArtifReject); copyArr(cur.pktNoiseBoundary, leg.isSortingOptions.pktNoiseBoundary, this, &Adapter::fromLegacy); - cur.pktStatistics = fromLegacy(leg.isSortingOptions.pktStatistics); - cur.pktStatus = fromLegacy(leg.isSortingOptions.pktStatus); + fromLegacy(cur.pktStatistics, leg.isSortingOptions.pktStatistics); + fromLegacy(cur.pktStatus, leg.isSortingOptions.pktStatus); copyArr(cur.isNTrodeInfo, leg.isNTrodeInfo, this, &Adapter::fromLegacy); copyArr2D(cur.isWaveform, leg.isWaveform, this, &Adapter::fromLegacy); - cur.isLnc = fromLegacy(leg.isLnc[instrument_idx]); - cur.isNPlay = fromLegacy(leg.isNPlay); + fromLegacy(cur.isLnc, leg.isLnc[instrument_idx]); + fromLegacy(cur.isNPlay, leg.isNPlay); copyArr(cur.isVideoSource, leg.isVideoSource, this, &Adapter::fromLegacy); copyArr(cur.isTrackObj, leg.isTrackObj, this, &Adapter::fromLegacy); - cur.fileinfo = fromLegacy(leg.fileinfo); - return cur; + fromLegacy(cur.fileinfo, leg.fileinfo); } -NativeNSPStatus Adapter::fromLegacy(const NSPStatus& leg) const { +void Adapter::fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const { switch(leg) { case NSPStatus::NSP_INIT: - return NativeNSPStatus::NSP_INIT; + cur = NativeNSPStatus::NSP_INIT; + break; case NSPStatus::NSP_NOIPADDR: - return NativeNSPStatus::NSP_NOIPADDR; + cur = NativeNSPStatus::NSP_NOIPADDR; + break; case NSPStatus::NSP_NOREPLY: - return NativeNSPStatus::NSP_NOREPLY; + cur = NativeNSPStatus::NSP_NOREPLY; + break; case NSPStatus::NSP_FOUND: - return NativeNSPStatus::NSP_FOUND; + cur = NativeNSPStatus::NSP_FOUND; + break; case NSPStatus::NSP_INVALID: + /* fallthrough */ default: - return NativeNSPStatus::NSP_INVALID; + cur = NativeNSPStatus::NSP_INVALID; + break; } } -::cbPKT_UNIT_SELECTION Adapter::fromLegacy(const cbPKT_UNIT_SELECTION& leg) const { - ::cbPKT_UNIT_SELECTION cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.lastchan = leg.lastchan; copyArr(cur.abyUnitSelections, leg.abyUnitSelections); - return cur; } -NativePCStatus Adapter::fromLegacy(const cbPcStatus& leg) const { - NativePCStatus cur{}; - cur.isSelection = fromLegacy(leg.isSelection[instrument_idx]); +void Adapter::fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const { + fromLegacy(cur.isSelection, leg.isSelection[instrument_idx]); cur.m_iBlockRecording = leg.m_iBlockRecording; cur.m_nPCStatusFlags = leg.m_nPCStatusFlags; cur.m_nNumFEChans = leg.m_nNumFEChans; @@ -512,101 +453,83 @@ NativePCStatus Adapter::fromLegacy(const cbPcStatus& leg) const { cur.m_nNumSerialChans = leg.m_nNumSerialChans; cur.m_nNumDigoutChans = leg.m_nNumDigoutChans; cur.m_nNumTotalChans = leg.m_nNumTotalChans; - cur.m_nNspStatus = fromLegacy(leg.m_nNspStatus[instrument_idx]); + fromLegacy(cur.m_nNspStatus, leg.m_nNspStatus[instrument_idx]); cur.m_nNumNTrodesPerInstrument = leg.m_nNumNTrodesPerInstrument[instrument_idx]; cur.m_nGeminiSystem = leg.m_nGeminiSystem; - return cur; } -NativeReceiveBuffer Adapter::fromLegacy(const cbRECBUFF& leg) const { - NativeReceiveBuffer cur{}; +void Adapter::fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const { cur.received = leg.received; cur.lasttime = leg.lasttime; cur.headwrap = leg.headwrap; cur.headindex = leg.headindex; copyArr(cur.buffer, leg.buffer); - return cur; } -NativeTransmitBuffer Adapter::fromLegacy(const cbXMTBUFF& leg) const { - NativeTransmitBuffer cur{}; +void Adapter::fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const { cur.transmitted = leg.transmitted; cur.headindex = leg.headindex; cur.tailindex = leg.tailindex; cur.last_valid_index = leg.last_valid_index; cur.bufferlen = leg.bufferlen; copyArr(cur.buffer, leg.buffer); - return cur; } -NativeTransmitBufferLocal Adapter::fromLegacy(const cbXMTBUFFLOCAL& leg) const { - NativeTransmitBufferLocal cur{}; +void Adapter::fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const { cur.transmitted = leg.transmitted; cur.headindex = leg.headindex; cur.tailindex = leg.tailindex; cur.last_valid_index = leg.last_valid_index; cur.bufferlen = leg.bufferlen; copyArr(cur.buffer, leg.buffer); - return cur; } -::cbPKT_SPK Adapter::fromLegacy(const cbPKT_SPK& leg) const { - ::cbPKT_SPK cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); copyArr(cur.fPattern, leg.fPattern); cur.nPeak = leg.nPeak; cur.nValley = leg.nValley; copyArr(cur.wave, leg.wave); - return cur; } -NativeSpikeCache Adapter::fromLegacy(const cbSPKCACHE& leg) const { - NativeSpikeCache cur{}; +void Adapter::fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const { cur.chid = leg.chid; cur.pktcnt = leg.pktcnt; cur.pktsize = leg.pktsize; cur.head = leg.head; cur.valid = leg.valid; copyArr(cur.spkpkt, leg.spkpkt, this, &Adapter::fromLegacy); - return cur; } -NativeSpikeBuffer Adapter::fromLegacy(const cbSPKBUFF& leg) const { - NativeSpikeBuffer cur{}; +void Adapter::fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const { cur.flags = leg.flags; cur.chidmax = leg.chidmax; cur.linesize = leg.linesize; cur.spkcount = leg.spkcount; copyArr(cur.cache, leg.cache, this, &Adapter::fromLegacy); - return cur; } -cbPKT_HEADER Adapter::toLegacy(const ::cbPKT_HEADER& cur) const { - cbPKT_HEADER leg{}; +void Adapter::toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const { leg.time = cur.time; leg.chid = cur.chid; leg.type = cur.type; leg.dlen = cur.dlen; leg.instrument = cur.instrument; leg.reserved = cur.reserved; - return leg; } -cbPKT_SYSINFO Adapter::toLegacy(const ::cbPKT_SYSINFO& cur) const { - cbPKT_SYSINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.sysfreq = cur.sysfreq; leg.spikelen = cur.spikelen; leg.spikepre = cur.spikepre; leg.resetque = cur.resetque; leg.runlevel = cur.runlevel; leg.runflags = cur.runflags; - return leg; } -cbPKT_PROCINFO Adapter::toLegacy(const ::cbPKT_PROCINFO& cur) const { - cbPKT_PROCINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.idcode = cur.idcode; leg.idcode = cur.idcode; @@ -621,12 +544,10 @@ cbPKT_PROCINFO Adapter::toLegacy(const ::cbPKT_PROCINFO& cur) const { leg.hoopcount = cur.hoopcount; leg.reserved = cur.reserved; leg.version = cur.version; - return leg; } -cbPKT_BANKINFO Adapter::toLegacy(const ::cbPKT_BANKINFO& cur) const { - cbPKT_BANKINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.bank = cur.bank; leg.idcode = cur.idcode; @@ -634,24 +555,20 @@ cbPKT_BANKINFO Adapter::toLegacy(const ::cbPKT_BANKINFO& cur) const { copyArr(leg.label, cur.label); leg.chanbase = cur.chanbase; leg.chancount = cur.chancount; - return leg; } -cbPKT_GROUPINFO Adapter::toLegacy(const ::cbPKT_GROUPINFO& cur) const { - cbPKT_GROUPINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.group = cur.group; copyArr(leg.label, cur.label); leg.period = cur.period; leg.length = cur.length; copyArr(leg.list, cur.list); - return leg; } -cbPKT_FILTINFO Adapter::toLegacy(const ::cbPKT_FILTINFO& cur) const { - cbPKT_FILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.filt = cur.filt; copyArr(leg.label, cur.label); @@ -670,73 +587,59 @@ cbPKT_FILTINFO Adapter::toLegacy(const ::cbPKT_FILTINFO& cur) const { leg.sos2a2 = cur.sos2a2; leg.sos2b1 = cur.sos2b1; leg.sos2b2 = cur.sos2b2; - return leg; } -cbPKT_ADAPTFILTINFO Adapter::toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) const { - cbPKT_ADAPTFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.nMode = cur.nMode; leg.dLearningRate = cur.dLearningRate; leg.nRefChan1 = cur.nRefChan1; leg.nRefChan2 = cur.nRefChan2; - return leg; } -cbPKT_REFELECFILTINFO Adapter::toLegacy(const ::cbPKT_REFELECFILTINFO& cur) const { - cbPKT_REFELECFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.nMode = cur.nMode; leg.nRefChan = cur.nRefChan; - return leg; } -cbSCALING Adapter::toLegacy(const ::cbSCALING& cur) const { - cbSCALING leg{}; +void Adapter::toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const { leg.digmin = cur.digmin; leg.digmax = cur.digmax; leg.anamin = cur.anamin; leg.anamax = cur.anamax; leg.anagain = cur.anagain; copyArr(leg.anaunit, cur.anaunit); - return leg; } -cbFILTDESC Adapter::toLegacy(const ::cbFILTDESC& cur) const { - cbFILTDESC leg{}; +void Adapter::toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const { leg.hpfreq = cur.hpfreq; leg.hporder = cur.hporder; leg.hptype = cur.hptype; leg.lpfreq = cur.lpfreq; leg.lporder = cur.lporder; leg.lptype = cur.lptype; - return leg; } -cbMANUALUNITMAPPING Adapter::toLegacy(const ::cbMANUALUNITMAPPING& cur) const { - cbMANUALUNITMAPPING leg{}; +void Adapter::toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const { leg.nOverride = cur.nOverride; copyArr(leg.afOrigin, cur.afOrigin); copyArr2D(leg.afShape, cur.afShape); leg.aPhi = cur.aPhi; leg.bValid = cur.bValid; - return leg; } -cbHOOP Adapter::toLegacy(const ::cbHOOP& cur) const { - cbHOOP leg{}; +void Adapter::toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const { leg.valid = cur.valid; leg.time = cur.time; leg.min = cur.min; leg.max = cur.max; - return leg; } -cbPKT_CHANINFO Adapter::toLegacy(const ::cbPKT_CHANINFO& cur) const { - cbPKT_CHANINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.proc = cur.proc; leg.bank = cur.bank; @@ -747,15 +650,15 @@ cbPKT_CHANINFO Adapter::toLegacy(const ::cbPKT_CHANINFO& cur) const { leg.aoutcaps = cur.aoutcaps; leg.ainpcaps = cur.ainpcaps; leg.spkcaps = cur.spkcaps; - leg.physcalin = toLegacy(cur.physcalin); - leg.phyfiltin = toLegacy(cur.phyfiltin); - leg.physcalout = toLegacy(cur.physcalout); - leg.phyfiltout = toLegacy(cur.phyfiltout); + toLegacy(leg.physcalin, cur.physcalin); + toLegacy(leg.phyfiltin, cur.phyfiltin); + toLegacy(leg.physcalout, cur.physcalout); + toLegacy(leg.phyfiltout, cur.phyfiltout); copyArr(leg.label, cur.label); leg.userflags = cur.userflags; copyArr(leg.position, cur.position); - leg.scalin = toLegacy(cur.scalin); - leg.scalout = toLegacy(cur.scalout); + toLegacy(leg.scalin, cur.scalin); + toLegacy(leg.scalout, cur.scalout); leg.doutopts = cur.doutopts; leg.dinpopts = cur.dinpopts; leg.aoutopts = cur.aoutopts; @@ -786,22 +689,18 @@ cbPKT_CHANINFO Adapter::toLegacy(const ::cbPKT_CHANINFO& cur) const { leg.refelecchan = cur.refelecchan; copyArr(leg.unitmapping, cur.unitmapping, this, &Adapter::toLegacy); copyArr2D(leg.spkhoops, cur.spkhoops, this, &Adapter::toLegacy); - return leg; } -cbPKT_FS_BASIS Adapter::toLegacy(const ::cbPKT_FS_BASIS& cur) const { - cbPKT_FS_BASIS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.mode = cur.mode; leg.fs = cur.fs; copyArr2D(leg.basis, cur.basis); - return leg; } -cbPKT_SS_MODELSET Adapter::toLegacy(const ::cbPKT_SS_MODELSET& cur) const { - cbPKT_SS_MODELSET leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.unit_number = cur.unit_number; leg.valid = cur.valid; @@ -816,37 +715,29 @@ cbPKT_SS_MODELSET Adapter::toLegacy(const ::cbPKT_SS_MODELSET& cur) const { leg.subcluster_spread_factor_denominator = cur.subcluster_spread_factor_denominator; leg.mu_e = cur.mu_e; leg.sigma_e_squared = cur.sigma_e_squared; - return leg; } -cbPKT_SS_DETECT Adapter::toLegacy(const ::cbPKT_SS_DETECT& cur) const { - cbPKT_SS_DETECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.fThreshold = cur.fThreshold; leg.fMultiplier = cur.fMultiplier; - return leg; } -cbPKT_SS_ARTIF_REJECT Adapter::toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) const { - cbPKT_SS_ARTIF_REJECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.nMaxSimulChans = cur.nMaxSimulChans; leg.nRefractoryCount = cur.nRefractoryCount; - return leg; } -cbPKT_SS_NOISE_BOUNDARY Adapter::toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) const { - cbPKT_SS_NOISE_BOUNDARY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; copyArr(leg.afc, cur.afc); copyArr2D(leg.afS, cur.afS); - return leg; } -cbPKT_SS_STATISTICS Adapter::toLegacy(const ::cbPKT_SS_STATISTICS& cur) const { - cbPKT_SS_STATISTICS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.nUpdateSpikes = cur.nUpdateSpikes; leg.nAutoalg = cur.nAutoalg; leg.nMode = cur.nMode; @@ -859,63 +750,51 @@ cbPKT_SS_STATISTICS Adapter::toLegacy(const ::cbPKT_SS_STATISTICS& cur) const { leg.fClusterHistMinPeakPercentage = cur.fClusterHistMinPeakPercentage; leg.nWaveBasisSize = cur.nWaveBasisSize; leg.nWaveSampleSize = cur.nWaveSampleSize; - return leg; } -cbAdaptControl Adapter::toLegacy(const ::cbAdaptControl& cur) const { - cbAdaptControl leg{}; +void Adapter::toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const { leg.nMode = cur.nMode; leg.fTimeOutMinutes = cur.fTimeOutMinutes; leg.fElapsedMinutes = cur.fElapsedMinutes; - return leg; } -cbPKT_SS_STATUS Adapter::toLegacy(const ::cbPKT_SS_STATUS& cur) const { - cbPKT_SS_STATUS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); - leg.cntlUnitStats = toLegacy(cur.cntlUnitStats); - leg.cntlNumUnits = toLegacy(cur.cntlNumUnits); - return leg; +void Adapter::toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + toLegacy(leg.cntlUnitStats, cur.cntlUnitStats); + toLegacy(leg.cntlNumUnits, cur.cntlNumUnits); } -cbSPIKE_SORTING Adapter::toLegacy(const ::cbproto::SpikeSorting& cur) const { - cbSPIKE_SORTING leg{}; +void Adapter::toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const { copyArr(leg.asBasis, cur.basis, this, &Adapter::toLegacy); copyArr2D(leg.asSortModel, cur.models, this, &Adapter::toLegacy); - leg.pktDetect = toLegacy(cur.detect); - leg.pktArtifReject = toLegacy(cur.artifact_reject); + toLegacy(leg.pktDetect, cur.detect); + toLegacy(leg.pktArtifReject, cur.artifact_reject); copyArr(leg.pktNoiseBoundary, cur.noise_boundary, this, &Adapter::toLegacy); - leg.pktStatistics = toLegacy(cur.statistics); - leg.pktStatus = toLegacy(cur.status); - return leg; + toLegacy(leg.pktStatistics, cur.statistics); + toLegacy(leg.pktStatus, cur.status); } -cbPKT_NTRODEINFO Adapter::toLegacy(const ::cbPKT_NTRODEINFO& cur) const { - cbPKT_NTRODEINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.ntrode = cur.ntrode; copyArr(leg.label, cur.label); copyArr2D(leg.ellipses, cur.ellipses, this, &Adapter::toLegacy); leg.nSite = cur.nSite; leg.fs = cur.fs; copyArr(leg.nChan, cur.nChan); - return leg; } -cbWaveformData Adapter::toLegacy(const ::cbWaveformData& cur) const { - cbWaveformData leg{}; +void Adapter::toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const { leg.offset = cur.offset; // aka sineFrequency leg.seq = cur.seq; // aka sineAmplitude leg.seqTotal = cur.seqTotal; leg.phases = cur.phases; copyArr(leg.duration, cur.duration); copyArr(leg.amplitude, cur.amplitude); - return leg; } -cbPKT_AOUT_WAVEFORM Adapter::toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const { - cbPKT_AOUT_WAVEFORM leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.mode = cur.mode; leg.repeats = cur.repeats; @@ -925,22 +804,18 @@ cbPKT_AOUT_WAVEFORM Adapter::toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const { leg.trigValue = cur.trigValue; leg.trigNum = cur.trigNum; leg.active = cur.active; - leg.wave = toLegacy(cur.wave); - return leg; + toLegacy(leg.wave, cur.wave); } -cbPKT_LNC Adapter::toLegacy(const ::cbPKT_LNC& cur) const { - cbPKT_LNC leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.lncFreq = cur.lncFreq; leg.lncRefChan = cur.lncRefChan; leg.lncGlobalMode = cur.lncGlobalMode; - return leg; } -cbPKT_NPLAY Adapter::toLegacy(const ::cbPKT_NPLAY& cur) const { - cbPKT_NPLAY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.ftime = cur.ftime; // aka opt leg.stime = cur.stime; leg.etime = cur.etime; @@ -949,27 +824,21 @@ cbPKT_NPLAY Adapter::toLegacy(const ::cbPKT_NPLAY& cur) const { leg.flags = cur.flags; leg.speed = cur.speed; copyArr(leg.fname, cur.fname); - return leg; } -cbVIDEOSOURCE Adapter::toLegacy(const ::cbVIDEOSOURCE& cur) const { - cbVIDEOSOURCE leg{}; +void Adapter::toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const { copyArr(leg.name, cur.name); leg.fps = cur.fps; - return leg; } -cbTRACKOBJ Adapter::toLegacy(const ::cbTRACKOBJ& cur) const { - cbTRACKOBJ leg{}; +void Adapter::toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const { copyArr(leg.name, cur.name); leg.type = cur.type; leg.pointCount = cur.pointCount; - return leg; } -cbPKT_FILECFG Adapter::toLegacy(const ::cbPKT_FILECFG& cur) const { - cbPKT_FILECFG leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.options = cur.options; leg.duration = cur.duration; leg.recording = cur.recording; @@ -977,73 +846,68 @@ cbPKT_FILECFG Adapter::toLegacy(const ::cbPKT_FILECFG& cur) const { copyArr(leg.username, cur.username); copyArr(leg.filename, cur.filename); // aka datetime copyArr(leg.comment, cur.comment); - return leg; } -NSPStatus Adapter::toLegacy(const NativeNSPStatus& cur) const { +void Adapter::toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const { switch(cur) { case NativeNSPStatus::NSP_INIT: - return NSPStatus::NSP_INIT; + leg = NSPStatus::NSP_INIT; + break; case NativeNSPStatus::NSP_NOIPADDR: - return NSPStatus::NSP_NOIPADDR; + leg = NSPStatus::NSP_NOIPADDR; + break; case NativeNSPStatus::NSP_NOREPLY: - return NSPStatus::NSP_NOREPLY; + leg = NSPStatus::NSP_NOREPLY; + break; case NativeNSPStatus::NSP_FOUND: - return NSPStatus::NSP_FOUND; + leg = NSPStatus::NSP_FOUND; + break; case NativeNSPStatus::NSP_INVALID: + /* fallthrough */ default: - return NSPStatus::NSP_INVALID; + leg = NSPStatus::NSP_INVALID; + break; } } -cbPKT_UNIT_SELECTION Adapter::toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const { - cbPKT_UNIT_SELECTION leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.lastchan = cur.lastchan; copyArr(leg.abyUnitSelections, cur.abyUnitSelections); - return leg; } -cbRECBUFF Adapter::toLegacy(const NativeReceiveBuffer& cur) const { - cbRECBUFF leg{}; +void Adapter::toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const { leg.received = cur.received; leg.lasttime = cur.lasttime; leg.headwrap = cur.headwrap; leg.headindex = cur.headindex; copyArr(leg.buffer, cur.buffer); - return leg; } -cbXMTBUFF Adapter::toLegacy(const NativeTransmitBuffer& cur) const { - cbXMTBUFF leg{}; +void Adapter::toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const { leg.transmitted = cur.transmitted; leg.headindex = cur.headindex; leg.tailindex = cur.tailindex; leg.last_valid_index = cur.last_valid_index; leg.bufferlen = cur.bufferlen; copyArr(leg.buffer, cur.buffer); - return leg; } -cbXMTBUFFLOCAL Adapter::toLegacy(const NativeTransmitBufferLocal& cur) const { - cbXMTBUFFLOCAL leg{}; +void Adapter::toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const { leg.transmitted = cur.transmitted; leg.headindex = cur.headindex; leg.tailindex = cur.tailindex; leg.last_valid_index = cur.last_valid_index; leg.bufferlen = cur.bufferlen; copyArr(leg.buffer, cur.buffer); - return leg; } -cbPKT_SPK Adapter::toLegacy(const ::cbPKT_SPK& cur) const { - cbPKT_SPK leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); copyArr(leg.fPattern, leg.fPattern); leg.nPeak = cur.nPeak; leg.nValley = cur.nValley; copyArr(leg.wave, cur.wave); - return leg; } Adapter::Adapter(uint8_t instrument_idx, void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) @@ -1132,106 +996,88 @@ uint32_t* Adapter::getLocalXmtBufferPtr() { return xmt->buffer; } -Result<::cbPKT_PROCINFO> Adapter::getProcInfo() const { - if (instrument_idx >= std::size(cfg->procinfo)) { - return Result<::cbPKT_PROCINFO>::error("Instrument index out of range"); - } - return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx])); +Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { + fromLegacy(buf, cfg->procinfo[instrument_idx]); + return Result::ok(); } -Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint32_t bank_num) const { - if (instrument_idx >= std::size(cfg->bankinfo)) { - return Result<::cbPKT_BANKINFO>::error("Instrument index out of range"); - } +Result Adapter::getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const { uint32_t bank_idx = bank_num - 1; if (bank_idx >= std::size(cfg->bankinfo[0])) { - return Result<::cbPKT_BANKINFO>::error("Bank number out of range"); + return Result::error("Bank number out of range"); } - return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx])); + fromLegacy(buf, cfg->bankinfo[instrument_idx][bank_idx]); + return Result::ok(); } -Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint32_t filter_num) const { - if (instrument_idx >= std::size(cfg->filtinfo)) { - return Result<::cbPKT_FILTINFO>::error("Instrument index out of range"); - } +Result Adapter::getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const { uint32_t filter_idx = filter_num - 1; if (filter_idx >= std::size(cfg->filtinfo[0])) { - return Result<::cbPKT_FILTINFO>::error("Filter number out of range"); + return Result::error("Filter number out of range"); } - return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx])); + fromLegacy(buf, cfg->filtinfo[instrument_idx][filter_idx]); + return Result::ok(); } -Result<::cbPKT_CHANINFO> Adapter::getChanInfo(uint32_t channel_idx) const { +Result Adapter::getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const { if (channel_idx >= std::size(cfg->chaninfo)) { - return Result<::cbPKT_CHANINFO>::error("Channel number out of range"); + return Result::error("Channel number out of range"); } - return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx])); + fromLegacy(buf, cfg->chaninfo[channel_idx]); + return Result::ok(); } -Result<::cbPKT_SYSINFO> Adapter::getSysInfo() const { - return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo)); +Result Adapter::getSysInfo(::cbPKT_SYSINFO& buf) const { + fromLegacy(buf, cfg->sysinfo); + return Result::ok(); } -Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint32_t group_idx) const { - if (instrument_idx >= std::size(cfg->groupinfo)) { - return Result<::cbPKT_GROUPINFO>::error("Instrument index out of range"); - } +Result Adapter::getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const { if (group_idx >= std::size(cfg->groupinfo[0])) { - return Result<::cbPKT_GROUPINFO>::error("Group index out of range"); + return Result::error("Group index out of range"); } - return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx])); + fromLegacy(buf, cfg->groupinfo[instrument_idx][group_idx]); + return Result::ok(); } -Result Adapter::getConfigBuffer() const { - if (instrument_idx >= std::size(cfg->procinfo)) { - return Result::error("Instrument index out of range"); - } - return Result::ok(fromLegacy(*cfg)); +Result Adapter::getConfigBuffer(NativeConfigBuffer& buf) const { + fromLegacy(buf, *cfg); + return Result::ok(); } -Result Adapter::getPcStatus() const { - if (instrument_idx >= std::size(status->isSelection)) { - return Result::error("Instrument index out of range"); - } - return Result::ok(fromLegacy(*status)); +Result Adapter::getPcStatus(NativePCStatus& buf) const { + fromLegacy(buf, *status); + return Result::ok(); } -Result Adapter::getSpikeCache(uint32_t channel_idx) const { +Result Adapter::getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const { if (channel_idx >= std::size(spike->cache)) { - return Result::error("Channel index out of range"); + return Result::error("Channel index out of range"); } - return Result::ok(fromLegacy(spike->cache[channel_idx])); + fromLegacy(buf, spike->cache[channel_idx]); + return Result::ok(); } Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { - if (instrument_idx >= std::size(cfg->procinfo)) { - return Result::error("Instrument index out of range"); - } - cfg->procinfo[instrument_idx] = toLegacy(info); + toLegacy(cfg->procinfo[instrument_idx], info); return Result::ok(); } Result Adapter::setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) { - if (instrument_idx >= std::size(cfg->bankinfo)) { - return Result::error("Instrument index out of range"); - } uint32_t bank_idx = bank_num - 1; if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result::error("Bank number out of range"); } - cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info); + toLegacy(cfg->bankinfo[instrument_idx][bank_idx], info); return Result::ok(); } Result Adapter::setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) { - if (instrument_idx >= std::size(cfg->filtinfo)) { - return Result::error("Instrument index out of range"); - } uint32_t filter_idx = filter_num - 1; if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result::error("Filter number out of range"); } - cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info); + toLegacy(cfg->filtinfo[instrument_idx][filter_idx], info); return Result::ok(); } @@ -1239,31 +1085,25 @@ Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& if (channel_idx >= std::size(cfg->chaninfo)) { return Result::error("Channel number out of range"); } - cfg->chaninfo[channel_idx] = toLegacy(info); + toLegacy(cfg->chaninfo[channel_idx], info); return Result::ok(); } Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { - cfg->sysinfo = toLegacy(info); + toLegacy(cfg->sysinfo, info); return Result::ok(); } Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { - if (instrument_idx >= std::size(cfg->groupinfo)) { - return Result::error("Instrument index out of range"); - } if (group_idx >= std::size(cfg->groupinfo[0])) { return Result::error("Group index out of range"); } - cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info); + toLegacy(cfg->groupinfo[instrument_idx][group_idx], info); return Result::ok(); } Result Adapter::setNspStatus(const NativeNSPStatus& status) const { - if (instrument_idx >= std::size(this->status->isSelection)) { - return Result::error("Instrument index out of range"); - } - this->status->m_nNspStatus[instrument_idx] = toLegacy(status); + toLegacy(this->status->m_nNspStatus[instrument_idx], status); return Result::ok(); } diff --git a/src/cbshm/src/central_adapters/v4_2.cpp b/src/cbshm/src/central_adapters/v4_2.cpp index df4fd5f7..fa30af03 100644 --- a/src/cbshm/src/central_adapters/v4_2.cpp +++ b/src/cbshm/src/central_adapters/v4_2.cpp @@ -42,32 +42,27 @@ size_t BootstrapAdapter::getReceiveBufferLen() const { return sizeof(cbRECBUFFLEN); } -::cbPKT_HEADER Adapter::fromLegacy(const cbPKT_HEADER& leg) const { - ::cbPKT_HEADER cur{}; +void Adapter::fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const { cur.time = leg.time; cur.chid = leg.chid; cur.type = leg.type; cur.dlen = leg.dlen; cur.instrument = leg.instrument; cur.reserved = leg.reserved; - return cur; } -::cbPKT_SYSINFO Adapter::fromLegacy(const cbPKT_SYSINFO& leg) const { - ::cbPKT_SYSINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.sysfreq = leg.sysfreq; cur.spikelen = leg.spikelen; cur.spikepre = leg.spikepre; cur.resetque = leg.resetque; cur.runlevel = leg.runlevel; cur.runflags = leg.runflags; - return cur; } -::cbPKT_PROCINFO Adapter::fromLegacy(const cbPKT_PROCINFO& leg) const { - ::cbPKT_PROCINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.idcode = leg.idcode; cur.idcode = leg.idcode; @@ -82,12 +77,10 @@ ::cbPKT_PROCINFO Adapter::fromLegacy(const cbPKT_PROCINFO& leg) const { cur.hoopcount = leg.hoopcount; cur.reserved = leg.reserved; cur.version = leg.version; - return cur; } -::cbPKT_BANKINFO Adapter::fromLegacy(const cbPKT_BANKINFO& leg) const { - ::cbPKT_BANKINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.bank = leg.bank; cur.idcode = leg.idcode; @@ -95,24 +88,20 @@ ::cbPKT_BANKINFO Adapter::fromLegacy(const cbPKT_BANKINFO& leg) const { copyArr(cur.label, leg.label); cur.chanbase = leg.chanbase; cur.chancount = leg.chancount; - return cur; } -::cbPKT_GROUPINFO Adapter::fromLegacy(const cbPKT_GROUPINFO& leg) const { - ::cbPKT_GROUPINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.group = leg.group; copyArr(cur.label, leg.label); cur.period = leg.period; cur.length = leg.length; copyArr(cur.list, leg.list); - return cur; } -::cbPKT_FILTINFO Adapter::fromLegacy(const cbPKT_FILTINFO& leg) const { - ::cbPKT_FILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.filt = leg.filt; copyArr(cur.label, leg.label); @@ -131,73 +120,59 @@ ::cbPKT_FILTINFO Adapter::fromLegacy(const cbPKT_FILTINFO& leg) const { cur.sos2a2 = leg.sos2a2; cur.sos2b1 = leg.sos2b1; cur.sos2b2 = leg.sos2b2; - return cur; } -::cbPKT_ADAPTFILTINFO Adapter::fromLegacy(const cbPKT_ADAPTFILTINFO& leg) const { - ::cbPKT_ADAPTFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.nMode = leg.nMode; cur.dLearningRate = leg.dLearningRate; cur.nRefChan1 = leg.nRefChan1; cur.nRefChan2 = leg.nRefChan2; - return cur; } -::cbPKT_REFELECFILTINFO Adapter::fromLegacy(const cbPKT_REFELECFILTINFO& leg) const { - ::cbPKT_REFELECFILTINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.nMode = leg.nMode; cur.nRefChan = leg.nRefChan; - return cur; } -::cbSCALING Adapter::fromLegacy(const cbSCALING& leg) const { - ::cbSCALING cur{}; +void Adapter::fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const { cur.digmin = leg.digmin; cur.digmax = leg.digmax; cur.anamin = leg.anamin; cur.anamax = leg.anamax; cur.anagain = leg.anagain; copyArr(cur.anaunit, leg.anaunit); - return cur; } -::cbFILTDESC Adapter::fromLegacy(const cbFILTDESC& leg) const { - ::cbFILTDESC cur{}; +void Adapter::fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const { cur.hpfreq = leg.hpfreq; cur.hporder = leg.hporder; cur.hptype = leg.hptype; cur.lpfreq = leg.lpfreq; cur.lporder = leg.lporder; cur.lptype = leg.lptype; - return cur; } -::cbMANUALUNITMAPPING Adapter::fromLegacy(const cbMANUALUNITMAPPING& leg) const { - ::cbMANUALUNITMAPPING cur{}; +void Adapter::fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const { cur.nOverride = leg.nOverride; copyArr(cur.afOrigin, leg.afOrigin); copyArr2D(cur.afShape, leg.afShape); cur.aPhi = leg.aPhi; cur.bValid = leg.bValid; - return cur; } -::cbHOOP Adapter::fromLegacy(const cbHOOP& leg) const { - ::cbHOOP cur{}; +void Adapter::fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const { cur.valid = leg.valid; cur.time = leg.time; cur.min = leg.min; cur.max = leg.max; - return cur; } -::cbPKT_CHANINFO Adapter::fromLegacy(const cbPKT_CHANINFO& leg) const { - ::cbPKT_CHANINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.proc = leg.proc; cur.bank = leg.bank; @@ -208,15 +183,15 @@ ::cbPKT_CHANINFO Adapter::fromLegacy(const cbPKT_CHANINFO& leg) const { cur.aoutcaps = leg.aoutcaps; cur.ainpcaps = leg.ainpcaps; cur.spkcaps = leg.spkcaps; - cur.physcalin = fromLegacy(leg.physcalin); - cur.phyfiltin = fromLegacy(leg.phyfiltin); - cur.physcalout = fromLegacy(leg.physcalout); - cur.phyfiltout = fromLegacy(leg.phyfiltout); + fromLegacy(cur.physcalin, leg.physcalin); + fromLegacy(cur.phyfiltin, leg.phyfiltin); + fromLegacy(cur.physcalout, leg.physcalout); + fromLegacy(cur.phyfiltout, leg.phyfiltout); copyArr(cur.label, leg.label); cur.userflags = leg.userflags; copyArr(cur.position, leg.position); - cur.scalin = fromLegacy(leg.scalin); - cur.scalout = fromLegacy(leg.scalout); + fromLegacy(cur.scalin, leg.scalin); + fromLegacy(cur.scalout, leg.scalout); cur.doutopts = leg.doutopts; cur.dinpopts = leg.dinpopts; cur.aoutopts = leg.aoutopts; @@ -247,22 +222,18 @@ ::cbPKT_CHANINFO Adapter::fromLegacy(const cbPKT_CHANINFO& leg) const { cur.refelecchan = leg.refelecchan; copyArr(cur.unitmapping, leg.unitmapping, this, &Adapter::fromLegacy); copyArr2D(cur.spkhoops, leg.spkhoops, this, &Adapter::fromLegacy); - return cur; } -::cbPKT_FS_BASIS Adapter::fromLegacy(const cbPKT_FS_BASIS& leg) const { - ::cbPKT_FS_BASIS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.mode = leg.mode; cur.fs = leg.fs; copyArr2D(cur.basis, leg.basis); - return cur; } -::cbPKT_SS_MODELSET Adapter::fromLegacy(const cbPKT_SS_MODELSET& leg) const { - ::cbPKT_SS_MODELSET cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.unit_number = leg.unit_number; cur.valid = leg.valid; @@ -277,37 +248,29 @@ ::cbPKT_SS_MODELSET Adapter::fromLegacy(const cbPKT_SS_MODELSET& leg) const { cur.subcluster_spread_factor_denominator = leg.subcluster_spread_factor_denominator; cur.mu_e = leg.mu_e; cur.sigma_e_squared = leg.sigma_e_squared; - return cur; } -::cbPKT_SS_DETECT Adapter::fromLegacy(const cbPKT_SS_DETECT& leg) const { - ::cbPKT_SS_DETECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.fThreshold = leg.fThreshold; cur.fMultiplier = leg.fMultiplier; - return cur; } -::cbPKT_SS_ARTIF_REJECT Adapter::fromLegacy(const cbPKT_SS_ARTIF_REJECT& leg) const { - ::cbPKT_SS_ARTIF_REJECT cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.nMaxSimulChans = leg.nMaxSimulChans; cur.nRefractoryCount = leg.nRefractoryCount; - return cur; } -::cbPKT_SS_NOISE_BOUNDARY Adapter::fromLegacy(const cbPKT_SS_NOISE_BOUNDARY& leg) const { - ::cbPKT_SS_NOISE_BOUNDARY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; copyArr(cur.afc, leg.afc); copyArr2D(cur.afS, leg.afS); - return cur; } -::cbPKT_SS_STATISTICS Adapter::fromLegacy(const cbPKT_SS_STATISTICS& leg) const { - ::cbPKT_SS_STATISTICS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.nUpdateSpikes = leg.nUpdateSpikes; cur.nAutoalg = leg.nAutoalg; cur.nMode = leg.nMode; @@ -320,63 +283,51 @@ ::cbPKT_SS_STATISTICS Adapter::fromLegacy(const cbPKT_SS_STATISTICS& leg) const cur.fClusterHistMinPeakPercentage = leg.fClusterHistMinPeakPercentage; cur.nWaveBasisSize = leg.nWaveBasisSize; cur.nWaveSampleSize = leg.nWaveSampleSize; - return cur; } -::cbAdaptControl Adapter::fromLegacy(const cbAdaptControl& leg) const { - ::cbAdaptControl cur{}; +void Adapter::fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const { cur.nMode = leg.nMode; cur.fTimeOutMinutes = leg.fTimeOutMinutes; cur.fElapsedMinutes = leg.fElapsedMinutes; - return cur; } -::cbPKT_SS_STATUS Adapter::fromLegacy(const cbPKT_SS_STATUS& leg) const { - ::cbPKT_SS_STATUS cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); - cur.cntlUnitStats = fromLegacy(leg.cntlUnitStats); - cur.cntlNumUnits = fromLegacy(leg.cntlNumUnits); - return cur; +void Adapter::fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + fromLegacy(cur.cntlUnitStats, leg.cntlUnitStats); + fromLegacy(cur.cntlNumUnits, leg.cntlNumUnits); } -::cbproto::SpikeSorting Adapter::fromLegacy(const cbSPIKE_SORTING& leg) const { - ::cbproto::SpikeSorting cur{}; +void Adapter::fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const { copyArr(cur.basis, leg.asBasis, this, &Adapter::fromLegacy); copyArr2D(cur.models, leg.asSortModel, this, &Adapter::fromLegacy); - cur.detect = fromLegacy(leg.pktDetect); - cur.artifact_reject = fromLegacy(leg.pktArtifReject); + fromLegacy(cur.detect, leg.pktDetect); + fromLegacy(cur.artifact_reject, leg.pktArtifReject); copyArr(cur.noise_boundary, leg.pktNoiseBoundary, this, &Adapter::fromLegacy); - cur.statistics = fromLegacy(leg.pktStatistics); - cur.status = fromLegacy(leg.pktStatus); - return cur; + fromLegacy(cur.statistics, leg.pktStatistics); + fromLegacy(cur.status, leg.pktStatus); } -::cbPKT_NTRODEINFO Adapter::fromLegacy(const cbPKT_NTRODEINFO& leg) const { - ::cbPKT_NTRODEINFO cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.ntrode = leg.ntrode; copyArr(cur.label, leg.label); copyArr2D(cur.ellipses, leg.ellipses, this, &Adapter::fromLegacy); cur.nSite = leg.nSite; cur.fs = leg.fs; copyArr(cur.nChan, leg.nChan); - return cur; } -::cbWaveformData Adapter::fromLegacy(const cbWaveformData& leg) const { - ::cbWaveformData cur{}; +void Adapter::fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const { cur.offset = leg.offset; // aka sineFrequency cur.seq = leg.seq; // aka sineAmplitude cur.seqTotal = leg.seqTotal; cur.phases = leg.phases; copyArr(cur.duration, leg.duration); copyArr(cur.amplitude, leg.amplitude); - return cur; } -::cbPKT_AOUT_WAVEFORM Adapter::fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const { - ::cbPKT_AOUT_WAVEFORM cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.chan = leg.chan; cur.mode = leg.mode; cur.repeats = leg.repeats; @@ -386,22 +337,18 @@ ::cbPKT_AOUT_WAVEFORM Adapter::fromLegacy(const cbPKT_AOUT_WAVEFORM& leg) const cur.trigValue = leg.trigValue; cur.trigNum = leg.trigNum; cur.active = leg.active; - cur.wave = fromLegacy(leg.wave); - return cur; + fromLegacy(cur.wave, leg.wave); } -::cbPKT_LNC Adapter::fromLegacy(const cbPKT_LNC& leg) const { - ::cbPKT_LNC cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.lncFreq = leg.lncFreq; cur.lncRefChan = leg.lncRefChan; cur.lncGlobalMode = leg.lncGlobalMode; - return cur; } -::cbPKT_NPLAY Adapter::fromLegacy(const cbPKT_NPLAY& leg) const { - ::cbPKT_NPLAY cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.ftime = leg.ftime; // aka opt cur.stime = leg.stime; cur.etime = leg.etime; @@ -410,27 +357,21 @@ ::cbPKT_NPLAY Adapter::fromLegacy(const cbPKT_NPLAY& leg) const { cur.flags = leg.flags; cur.speed = leg.speed; copyArr(cur.fname, leg.fname); - return cur; } -::cbVIDEOSOURCE Adapter::fromLegacy(const cbVIDEOSOURCE& leg) const { - ::cbVIDEOSOURCE cur{}; +void Adapter::fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const { copyArr(cur.name, leg.name); cur.fps = leg.fps; - return cur; } -::cbTRACKOBJ Adapter::fromLegacy(const cbTRACKOBJ& leg) const { - ::cbTRACKOBJ cur{}; +void Adapter::fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const { copyArr(cur.name, leg.name); cur.type = leg.type; cur.pointCount = leg.pointCount; - return cur; } -::cbPKT_FILECFG Adapter::fromLegacy(const cbPKT_FILECFG& leg) const { - ::cbPKT_FILECFG cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.options = leg.options; cur.duration = leg.duration; cur.recording = leg.recording; @@ -438,68 +379,68 @@ ::cbPKT_FILECFG Adapter::fromLegacy(const cbPKT_FILECFG& leg) const { copyArr(cur.username, leg.username); copyArr(cur.filename, leg.filename); // aka datetime copyArr(cur.comment, leg.comment); - return cur; } -NativeConfigBuffer Adapter::fromLegacy(const cbCFGBUFF& leg) const { +void Adapter::fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const { // TODO: VERIFY that each list that's assumed to be instrument-independent is in fact independent from any particular instrument. - NativeConfigBuffer cur{}; - cur.version = leg.version; + cur.version = cbVERSION_MAJOR * 100 + cbVERSION_MINOR; // Central's version field contains garbage data, so replace it with the protocol version cur.sysflags = leg.sysflags; - cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); - cur.sysinfo = fromLegacy(leg.sysinfo); - cur.procinfo = fromLegacy(leg.procinfo[instrument_idx]); + cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); + fromLegacy(cur.sysinfo, leg.sysinfo); + fromLegacy(cur.procinfo, leg.procinfo[instrument_idx]); copyArr(cur.bankinfo, leg.bankinfo[instrument_idx], this, &Adapter::fromLegacy); copyArr(cur.groupinfo, leg.groupinfo[instrument_idx], this, &Adapter::fromLegacy); copyArr(cur.filtinfo, leg.filtinfo[instrument_idx], this, &Adapter::fromLegacy); - cur.adaptinfo = fromLegacy(leg.adaptinfo[instrument_idx]); - cur.refelecinfo = fromLegacy(leg.refelecinfo[instrument_idx]); + fromLegacy(cur.adaptinfo, leg.adaptinfo[instrument_idx]); + fromLegacy(cur.refelecinfo, leg.refelecinfo[instrument_idx]); copyArr(cur.chaninfo, leg.chaninfo, this, &Adapter::fromLegacy); copyArr(cur.asBasis, leg.isSortingOptions.asBasis, this, &Adapter::fromLegacy); - copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); + // copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); // TODO: For some reason, this contains memory that's innaccessible // TODO: Move native isSortingOptions fields into a struct - cur.pktDetect = fromLegacy(leg.isSortingOptions.pktDetect); - cur.pktArtifReject = fromLegacy(leg.isSortingOptions.pktArtifReject); + fromLegacy(cur.pktDetect, leg.isSortingOptions.pktDetect); + fromLegacy(cur.pktArtifReject, leg.isSortingOptions.pktArtifReject); copyArr(cur.pktNoiseBoundary, leg.isSortingOptions.pktNoiseBoundary, this, &Adapter::fromLegacy); - cur.pktStatistics = fromLegacy(leg.isSortingOptions.pktStatistics); - cur.pktStatus = fromLegacy(leg.isSortingOptions.pktStatus); + fromLegacy(cur.pktStatistics, leg.isSortingOptions.pktStatistics); + fromLegacy(cur.pktStatus, leg.isSortingOptions.pktStatus); copyArr(cur.isNTrodeInfo, leg.isNTrodeInfo, this, &Adapter::fromLegacy); copyArr2D(cur.isWaveform, leg.isWaveform, this, &Adapter::fromLegacy); - cur.isLnc = fromLegacy(leg.isLnc[instrument_idx]); - cur.isNPlay = fromLegacy(leg.isNPlay); + fromLegacy(cur.isLnc, leg.isLnc[instrument_idx]); + fromLegacy(cur.isNPlay, leg.isNPlay); copyArr(cur.isVideoSource, leg.isVideoSource, this, &Adapter::fromLegacy); copyArr(cur.isTrackObj, leg.isTrackObj, this, &Adapter::fromLegacy); - cur.fileinfo = fromLegacy(leg.fileinfo); - return cur; + fromLegacy(cur.fileinfo, leg.fileinfo); } -NativeNSPStatus Adapter::fromLegacy(const NSPStatus& leg) const { +void Adapter::fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const { switch(leg) { case NSPStatus::NSP_INIT: - return NativeNSPStatus::NSP_INIT; + cur = NativeNSPStatus::NSP_INIT; + break; case NSPStatus::NSP_NOIPADDR: - return NativeNSPStatus::NSP_NOIPADDR; + cur = NativeNSPStatus::NSP_NOIPADDR; + break; case NSPStatus::NSP_NOREPLY: - return NativeNSPStatus::NSP_NOREPLY; + cur = NativeNSPStatus::NSP_NOREPLY; + break; case NSPStatus::NSP_FOUND: - return NativeNSPStatus::NSP_FOUND; + cur = NativeNSPStatus::NSP_FOUND; + break; case NSPStatus::NSP_INVALID: + /* fallthrough */ default: - return NativeNSPStatus::NSP_INVALID; + cur = NativeNSPStatus::NSP_INVALID; + break; } } -::cbPKT_UNIT_SELECTION Adapter::fromLegacy(const cbPKT_UNIT_SELECTION& leg) const { - ::cbPKT_UNIT_SELECTION cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.lastchan = leg.lastchan; copyArr(cur.abyUnitSelections, leg.abyUnitSelections); - return cur; } -NativePCStatus Adapter::fromLegacy(const cbPcStatus& leg) const { - NativePCStatus cur{}; - cur.isSelection = fromLegacy(leg.isSelection[instrument_idx]); +void Adapter::fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const { + fromLegacy(cur.isSelection, leg.isSelection[instrument_idx]); cur.m_iBlockRecording = leg.m_iBlockRecording; cur.m_nPCStatusFlags = leg.m_nPCStatusFlags; cur.m_nNumFEChans = leg.m_nNumFEChans; @@ -512,102 +453,84 @@ NativePCStatus Adapter::fromLegacy(const cbPcStatus& leg) const { cur.m_nNumSerialChans = leg.m_nNumSerialChans; cur.m_nNumDigoutChans = leg.m_nNumDigoutChans; cur.m_nNumTotalChans = leg.m_nNumTotalChans; - cur.m_nNspStatus = fromLegacy(leg.m_nNspStatus[instrument_idx]); + fromLegacy(cur.m_nNspStatus, leg.m_nNspStatus[instrument_idx]); cur.m_nNumNTrodesPerInstrument = leg.m_nNumNTrodesPerInstrument[instrument_idx]; cur.m_nGeminiSystem = leg.m_nGeminiSystem; // ignore APP_WORKSPACE - return cur; } -NativeReceiveBuffer Adapter::fromLegacy(const cbRECBUFF& leg) const { - NativeReceiveBuffer cur{}; +void Adapter::fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const { cur.received = leg.received; cur.lasttime = leg.lasttime; cur.headwrap = leg.headwrap; cur.headindex = leg.headindex; copyArr(cur.buffer, leg.buffer); - return cur; } -NativeTransmitBuffer Adapter::fromLegacy(const cbXMTBUFF& leg) const { - NativeTransmitBuffer cur{}; +void Adapter::fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const { cur.transmitted = leg.transmitted; cur.headindex = leg.headindex; cur.tailindex = leg.tailindex; cur.last_valid_index = leg.last_valid_index; cur.bufferlen = leg.bufferlen; copyArr(cur.buffer, leg.buffer); - return cur; } -NativeTransmitBufferLocal Adapter::fromLegacy(const cbXMTBUFFLOCAL& leg) const { - NativeTransmitBufferLocal cur{}; +void Adapter::fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const { cur.transmitted = leg.transmitted; cur.headindex = leg.headindex; cur.tailindex = leg.tailindex; cur.last_valid_index = leg.last_valid_index; cur.bufferlen = leg.bufferlen; copyArr(cur.buffer, leg.buffer); - return cur; } -::cbPKT_SPK Adapter::fromLegacy(const cbPKT_SPK& leg) const { - ::cbPKT_SPK cur{}; - cur.cbpkt_header = fromLegacy(leg.cbpkt_header); +void Adapter::fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); copyArr(cur.fPattern, leg.fPattern); cur.nPeak = leg.nPeak; cur.nValley = leg.nValley; copyArr(cur.wave, leg.wave); - return cur; } -NativeSpikeCache Adapter::fromLegacy(const cbSPKCACHE& leg) const { - NativeSpikeCache cur{}; +void Adapter::fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const { cur.chid = leg.chid; cur.pktcnt = leg.pktcnt; cur.pktsize = leg.pktsize; cur.head = leg.head; cur.valid = leg.valid; copyArr(cur.spkpkt, leg.spkpkt, this, &Adapter::fromLegacy); - return cur; } -NativeSpikeBuffer Adapter::fromLegacy(const cbSPKBUFF& leg) const { - NativeSpikeBuffer cur{}; +void Adapter::fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const { cur.flags = leg.flags; cur.chidmax = leg.chidmax; cur.linesize = leg.linesize; cur.spkcount = leg.spkcount; copyArr(cur.cache, leg.cache, this, &Adapter::fromLegacy); - return cur; } -cbPKT_HEADER Adapter::toLegacy(const ::cbPKT_HEADER& cur) const { - cbPKT_HEADER leg{}; +void Adapter::toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const { leg.time = cur.time; leg.chid = cur.chid; leg.type = cur.type; leg.dlen = cur.dlen; leg.instrument = cur.instrument; leg.reserved = cur.reserved; - return leg; } -cbPKT_SYSINFO Adapter::toLegacy(const ::cbPKT_SYSINFO& cur) const { - cbPKT_SYSINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.sysfreq = cur.sysfreq; leg.spikelen = cur.spikelen; leg.spikepre = cur.spikepre; leg.resetque = cur.resetque; leg.runlevel = cur.runlevel; leg.runflags = cur.runflags; - return leg; } -cbPKT_PROCINFO Adapter::toLegacy(const ::cbPKT_PROCINFO& cur) const { - cbPKT_PROCINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.idcode = cur.idcode; leg.idcode = cur.idcode; @@ -622,12 +545,10 @@ cbPKT_PROCINFO Adapter::toLegacy(const ::cbPKT_PROCINFO& cur) const { leg.hoopcount = cur.hoopcount; leg.reserved = cur.reserved; leg.version = cur.version; - return leg; } -cbPKT_BANKINFO Adapter::toLegacy(const ::cbPKT_BANKINFO& cur) const { - cbPKT_BANKINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.bank = cur.bank; leg.idcode = cur.idcode; @@ -635,24 +556,20 @@ cbPKT_BANKINFO Adapter::toLegacy(const ::cbPKT_BANKINFO& cur) const { copyArr(leg.label, cur.label); leg.chanbase = cur.chanbase; leg.chancount = cur.chancount; - return leg; } -cbPKT_GROUPINFO Adapter::toLegacy(const ::cbPKT_GROUPINFO& cur) const { - cbPKT_GROUPINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.group = cur.group; copyArr(leg.label, cur.label); leg.period = cur.period; leg.length = cur.length; copyArr(leg.list, cur.list); - return leg; } -cbPKT_FILTINFO Adapter::toLegacy(const ::cbPKT_FILTINFO& cur) const { - cbPKT_FILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.filt = cur.filt; copyArr(leg.label, cur.label); @@ -671,73 +588,59 @@ cbPKT_FILTINFO Adapter::toLegacy(const ::cbPKT_FILTINFO& cur) const { leg.sos2a2 = cur.sos2a2; leg.sos2b1 = cur.sos2b1; leg.sos2b2 = cur.sos2b2; - return leg; } -cbPKT_ADAPTFILTINFO Adapter::toLegacy(const ::cbPKT_ADAPTFILTINFO& cur) const { - cbPKT_ADAPTFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.nMode = cur.nMode; leg.dLearningRate = cur.dLearningRate; leg.nRefChan1 = cur.nRefChan1; leg.nRefChan2 = cur.nRefChan2; - return leg; } -cbPKT_REFELECFILTINFO Adapter::toLegacy(const ::cbPKT_REFELECFILTINFO& cur) const { - cbPKT_REFELECFILTINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.nMode = cur.nMode; leg.nRefChan = cur.nRefChan; - return leg; } -cbSCALING Adapter::toLegacy(const ::cbSCALING& cur) const { - cbSCALING leg{}; +void Adapter::toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const { leg.digmin = cur.digmin; leg.digmax = cur.digmax; leg.anamin = cur.anamin; leg.anamax = cur.anamax; leg.anagain = cur.anagain; copyArr(leg.anaunit, cur.anaunit); - return leg; } -cbFILTDESC Adapter::toLegacy(const ::cbFILTDESC& cur) const { - cbFILTDESC leg{}; +void Adapter::toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const { leg.hpfreq = cur.hpfreq; leg.hporder = cur.hporder; leg.hptype = cur.hptype; leg.lpfreq = cur.lpfreq; leg.lporder = cur.lporder; leg.lptype = cur.lptype; - return leg; } -cbMANUALUNITMAPPING Adapter::toLegacy(const ::cbMANUALUNITMAPPING& cur) const { - cbMANUALUNITMAPPING leg{}; +void Adapter::toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const { leg.nOverride = cur.nOverride; copyArr(leg.afOrigin, cur.afOrigin); copyArr2D(leg.afShape, cur.afShape); leg.aPhi = cur.aPhi; leg.bValid = cur.bValid; - return leg; } -cbHOOP Adapter::toLegacy(const ::cbHOOP& cur) const { - cbHOOP leg{}; +void Adapter::toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const { leg.valid = cur.valid; leg.time = cur.time; leg.min = cur.min; leg.max = cur.max; - return leg; } -cbPKT_CHANINFO Adapter::toLegacy(const ::cbPKT_CHANINFO& cur) const { - cbPKT_CHANINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.proc = cur.proc; leg.bank = cur.bank; @@ -748,15 +651,15 @@ cbPKT_CHANINFO Adapter::toLegacy(const ::cbPKT_CHANINFO& cur) const { leg.aoutcaps = cur.aoutcaps; leg.ainpcaps = cur.ainpcaps; leg.spkcaps = cur.spkcaps; - leg.physcalin = toLegacy(cur.physcalin); - leg.phyfiltin = toLegacy(cur.phyfiltin); - leg.physcalout = toLegacy(cur.physcalout); - leg.phyfiltout = toLegacy(cur.phyfiltout); + toLegacy(leg.physcalin, cur.physcalin); + toLegacy(leg.phyfiltin, cur.phyfiltin); + toLegacy(leg.physcalout, cur.physcalout); + toLegacy(leg.phyfiltout, cur.phyfiltout); copyArr(leg.label, cur.label); leg.userflags = cur.userflags; copyArr(leg.position, cur.position); - leg.scalin = toLegacy(cur.scalin); - leg.scalout = toLegacy(cur.scalout); + toLegacy(leg.scalin, cur.scalin); + toLegacy(leg.scalout, cur.scalout); leg.doutopts = cur.doutopts; leg.dinpopts = cur.dinpopts; leg.aoutopts = cur.aoutopts; @@ -787,22 +690,18 @@ cbPKT_CHANINFO Adapter::toLegacy(const ::cbPKT_CHANINFO& cur) const { leg.refelecchan = cur.refelecchan; copyArr(leg.unitmapping, cur.unitmapping, this, &Adapter::toLegacy); copyArr2D(leg.spkhoops, cur.spkhoops, this, &Adapter::toLegacy); - return leg; } -cbPKT_FS_BASIS Adapter::toLegacy(const ::cbPKT_FS_BASIS& cur) const { - cbPKT_FS_BASIS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.mode = cur.mode; leg.fs = cur.fs; copyArr2D(leg.basis, cur.basis); - return leg; } -cbPKT_SS_MODELSET Adapter::toLegacy(const ::cbPKT_SS_MODELSET& cur) const { - cbPKT_SS_MODELSET leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.unit_number = cur.unit_number; leg.valid = cur.valid; @@ -817,37 +716,29 @@ cbPKT_SS_MODELSET Adapter::toLegacy(const ::cbPKT_SS_MODELSET& cur) const { leg.subcluster_spread_factor_denominator = cur.subcluster_spread_factor_denominator; leg.mu_e = cur.mu_e; leg.sigma_e_squared = cur.sigma_e_squared; - return leg; } -cbPKT_SS_DETECT Adapter::toLegacy(const ::cbPKT_SS_DETECT& cur) const { - cbPKT_SS_DETECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.fThreshold = cur.fThreshold; leg.fMultiplier = cur.fMultiplier; - return leg; } -cbPKT_SS_ARTIF_REJECT Adapter::toLegacy(const ::cbPKT_SS_ARTIF_REJECT& cur) const { - cbPKT_SS_ARTIF_REJECT leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.nMaxSimulChans = cur.nMaxSimulChans; leg.nRefractoryCount = cur.nRefractoryCount; - return leg; } -cbPKT_SS_NOISE_BOUNDARY Adapter::toLegacy(const ::cbPKT_SS_NOISE_BOUNDARY& cur) const { - cbPKT_SS_NOISE_BOUNDARY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; copyArr(leg.afc, cur.afc); copyArr2D(leg.afS, cur.afS); - return leg; } -cbPKT_SS_STATISTICS Adapter::toLegacy(const ::cbPKT_SS_STATISTICS& cur) const { - cbPKT_SS_STATISTICS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.nUpdateSpikes = cur.nUpdateSpikes; leg.nAutoalg = cur.nAutoalg; leg.nMode = cur.nMode; @@ -860,63 +751,51 @@ cbPKT_SS_STATISTICS Adapter::toLegacy(const ::cbPKT_SS_STATISTICS& cur) const { leg.fClusterHistMinPeakPercentage = cur.fClusterHistMinPeakPercentage; leg.nWaveBasisSize = cur.nWaveBasisSize; leg.nWaveSampleSize = cur.nWaveSampleSize; - return leg; } -cbAdaptControl Adapter::toLegacy(const ::cbAdaptControl& cur) const { - cbAdaptControl leg{}; +void Adapter::toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const { leg.nMode = cur.nMode; leg.fTimeOutMinutes = cur.fTimeOutMinutes; leg.fElapsedMinutes = cur.fElapsedMinutes; - return leg; } -cbPKT_SS_STATUS Adapter::toLegacy(const ::cbPKT_SS_STATUS& cur) const { - cbPKT_SS_STATUS leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); - leg.cntlUnitStats = toLegacy(cur.cntlUnitStats); - leg.cntlNumUnits = toLegacy(cur.cntlNumUnits); - return leg; +void Adapter::toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + toLegacy(leg.cntlUnitStats, cur.cntlUnitStats); + toLegacy(leg.cntlNumUnits, cur.cntlNumUnits); } -cbSPIKE_SORTING Adapter::toLegacy(const ::cbproto::SpikeSorting& cur) const { - cbSPIKE_SORTING leg{}; +void Adapter::toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const { copyArr(leg.asBasis, cur.basis, this, &Adapter::toLegacy); copyArr2D(leg.asSortModel, cur.models, this, &Adapter::toLegacy); - leg.pktDetect = toLegacy(cur.detect); - leg.pktArtifReject = toLegacy(cur.artifact_reject); + toLegacy(leg.pktDetect, cur.detect); + toLegacy(leg.pktArtifReject, cur.artifact_reject); copyArr(leg.pktNoiseBoundary, cur.noise_boundary, this, &Adapter::toLegacy); - leg.pktStatistics = toLegacy(cur.statistics); - leg.pktStatus = toLegacy(cur.status); - return leg; + toLegacy(leg.pktStatistics, cur.statistics); + toLegacy(leg.pktStatus, cur.status); } -cbPKT_NTRODEINFO Adapter::toLegacy(const ::cbPKT_NTRODEINFO& cur) const { - cbPKT_NTRODEINFO leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.ntrode = cur.ntrode; copyArr(leg.label, cur.label); copyArr2D(leg.ellipses, cur.ellipses, this, &Adapter::toLegacy); leg.nSite = cur.nSite; leg.fs = cur.fs; copyArr(leg.nChan, cur.nChan); - return leg; } -cbWaveformData Adapter::toLegacy(const ::cbWaveformData& cur) const { - cbWaveformData leg{}; +void Adapter::toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const { leg.offset = cur.offset; // aka sineFrequency leg.seq = cur.seq; // aka sineAmplitude leg.seqTotal = cur.seqTotal; leg.phases = cur.phases; copyArr(leg.duration, cur.duration); copyArr(leg.amplitude, cur.amplitude); - return leg; } -cbPKT_AOUT_WAVEFORM Adapter::toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const { - cbPKT_AOUT_WAVEFORM leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.chan = cur.chan; leg.mode = cur.mode; leg.repeats = cur.repeats; @@ -926,22 +805,18 @@ cbPKT_AOUT_WAVEFORM Adapter::toLegacy(const ::cbPKT_AOUT_WAVEFORM& cur) const { leg.trigValue = cur.trigValue; leg.trigNum = cur.trigNum; leg.active = cur.active; - leg.wave = toLegacy(cur.wave); - return leg; + toLegacy(leg.wave, cur.wave); } -cbPKT_LNC Adapter::toLegacy(const ::cbPKT_LNC& cur) const { - cbPKT_LNC leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.lncFreq = cur.lncFreq; leg.lncRefChan = cur.lncRefChan; leg.lncGlobalMode = cur.lncGlobalMode; - return leg; } -cbPKT_NPLAY Adapter::toLegacy(const ::cbPKT_NPLAY& cur) const { - cbPKT_NPLAY leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.ftime = cur.ftime; // aka opt leg.stime = cur.stime; leg.etime = cur.etime; @@ -950,27 +825,21 @@ cbPKT_NPLAY Adapter::toLegacy(const ::cbPKT_NPLAY& cur) const { leg.flags = cur.flags; leg.speed = cur.speed; copyArr(leg.fname, cur.fname); - return leg; } -cbVIDEOSOURCE Adapter::toLegacy(const ::cbVIDEOSOURCE& cur) const { - cbVIDEOSOURCE leg{}; +void Adapter::toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const { copyArr(leg.name, cur.name); leg.fps = cur.fps; - return leg; } -cbTRACKOBJ Adapter::toLegacy(const ::cbTRACKOBJ& cur) const { - cbTRACKOBJ leg{}; +void Adapter::toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const { copyArr(leg.name, cur.name); leg.type = cur.type; leg.pointCount = cur.pointCount; - return leg; } -cbPKT_FILECFG Adapter::toLegacy(const ::cbPKT_FILECFG& cur) const { - cbPKT_FILECFG leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.options = cur.options; leg.duration = cur.duration; leg.recording = cur.recording; @@ -978,73 +847,68 @@ cbPKT_FILECFG Adapter::toLegacy(const ::cbPKT_FILECFG& cur) const { copyArr(leg.username, cur.username); copyArr(leg.filename, cur.filename); // aka datetime copyArr(leg.comment, cur.comment); - return leg; } -NSPStatus Adapter::toLegacy(const NativeNSPStatus& cur) const { +void Adapter::toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const { switch(cur) { case NativeNSPStatus::NSP_INIT: - return NSPStatus::NSP_INIT; + leg = NSPStatus::NSP_INIT; + break; case NativeNSPStatus::NSP_NOIPADDR: - return NSPStatus::NSP_NOIPADDR; + leg = NSPStatus::NSP_NOIPADDR; + break; case NativeNSPStatus::NSP_NOREPLY: - return NSPStatus::NSP_NOREPLY; + leg = NSPStatus::NSP_NOREPLY; + break; case NativeNSPStatus::NSP_FOUND: - return NSPStatus::NSP_FOUND; + leg = NSPStatus::NSP_FOUND; + break; case NativeNSPStatus::NSP_INVALID: + /* fallthrough */ default: - return NSPStatus::NSP_INVALID; + leg = NSPStatus::NSP_INVALID; + break; } } -cbPKT_UNIT_SELECTION Adapter::toLegacy(const ::cbPKT_UNIT_SELECTION& cur) const { - cbPKT_UNIT_SELECTION leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.lastchan = cur.lastchan; copyArr(leg.abyUnitSelections, cur.abyUnitSelections); - return leg; } -cbRECBUFF Adapter::toLegacy(const NativeReceiveBuffer& cur) const { - cbRECBUFF leg{}; +void Adapter::toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const { leg.received = cur.received; leg.lasttime = cur.lasttime; leg.headwrap = cur.headwrap; leg.headindex = cur.headindex; copyArr(leg.buffer, cur.buffer); - return leg; } -cbXMTBUFF Adapter::toLegacy(const NativeTransmitBuffer& cur) const { - cbXMTBUFF leg{}; +void Adapter::toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const { leg.transmitted = cur.transmitted; leg.headindex = cur.headindex; leg.tailindex = cur.tailindex; leg.last_valid_index = cur.last_valid_index; leg.bufferlen = cur.bufferlen; copyArr(leg.buffer, cur.buffer); - return leg; } -cbXMTBUFFLOCAL Adapter::toLegacy(const NativeTransmitBufferLocal& cur) const { - cbXMTBUFFLOCAL leg{}; +void Adapter::toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const { leg.transmitted = cur.transmitted; leg.headindex = cur.headindex; leg.tailindex = cur.tailindex; leg.last_valid_index = cur.last_valid_index; leg.bufferlen = cur.bufferlen; copyArr(leg.buffer, cur.buffer); - return leg; } -cbPKT_SPK Adapter::toLegacy(const ::cbPKT_SPK& cur) const { - cbPKT_SPK leg{}; - leg.cbpkt_header = toLegacy(cur.cbpkt_header); +void Adapter::toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); copyArr(leg.fPattern, leg.fPattern); leg.nPeak = cur.nPeak; leg.nValley = cur.nValley; copyArr(leg.wave, cur.wave); - return leg; } Adapter::Adapter(uint8_t instrument_idx, void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) @@ -1133,106 +997,88 @@ uint32_t* Adapter::getLocalXmtBufferPtr() { return xmt->buffer; } -Result<::cbPKT_PROCINFO> Adapter::getProcInfo() const { - if (instrument_idx >= std::size(cfg->procinfo)) { - return Result<::cbPKT_PROCINFO>::error("Instrument index out of range"); - } - return Result<::cbPKT_PROCINFO>::ok(fromLegacy(cfg->procinfo[instrument_idx])); +Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { + fromLegacy(buf, cfg->procinfo[instrument_idx]); + return Result::ok(); } -Result<::cbPKT_BANKINFO> Adapter::getBankInfo(uint32_t bank_num) const { - if (instrument_idx >= std::size(cfg->bankinfo)) { - return Result<::cbPKT_BANKINFO>::error("Instrument index out of range"); - } +Result Adapter::getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const { uint32_t bank_idx = bank_num - 1; if (bank_idx >= std::size(cfg->bankinfo[0])) { - return Result<::cbPKT_BANKINFO>::error("Bank number out of range"); + return Result::error("Bank number out of range"); } - return Result<::cbPKT_BANKINFO>::ok(fromLegacy(cfg->bankinfo[instrument_idx][bank_idx])); + fromLegacy(buf, cfg->bankinfo[instrument_idx][bank_idx]); + return Result::ok(); } -Result<::cbPKT_FILTINFO> Adapter::getFilterInfo(uint32_t filter_num) const { - if (instrument_idx >= std::size(cfg->filtinfo)) { - return Result<::cbPKT_FILTINFO>::error("Instrument index out of range"); - } +Result Adapter::getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const { uint32_t filter_idx = filter_num - 1; if (filter_idx >= std::size(cfg->filtinfo[0])) { - return Result<::cbPKT_FILTINFO>::error("Filter number out of range"); + return Result::error("Filter number out of range"); } - return Result<::cbPKT_FILTINFO>::ok(fromLegacy(cfg->filtinfo[instrument_idx][filter_idx])); + fromLegacy(buf, cfg->filtinfo[instrument_idx][filter_idx]); + return Result::ok(); } -Result<::cbPKT_CHANINFO> Adapter::getChanInfo(uint32_t channel_idx) const { +Result Adapter::getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const { if (channel_idx >= std::size(cfg->chaninfo)) { - return Result<::cbPKT_CHANINFO>::error("Channel number out of range"); + return Result::error("Channel number out of range"); } - return Result<::cbPKT_CHANINFO>::ok(fromLegacy(cfg->chaninfo[channel_idx])); + fromLegacy(buf, cfg->chaninfo[channel_idx]); + return Result::ok(); } -Result<::cbPKT_SYSINFO> Adapter::getSysInfo() const { - return Result<::cbPKT_SYSINFO>::ok(fromLegacy(cfg->sysinfo)); +Result Adapter::getSysInfo(::cbPKT_SYSINFO& buf) const { + fromLegacy(buf, cfg->sysinfo); + return Result::ok(); } -Result<::cbPKT_GROUPINFO> Adapter::getGroupInfo(uint32_t group_idx) const { - if (instrument_idx >= std::size(cfg->groupinfo)) { - return Result<::cbPKT_GROUPINFO>::error("Instrument index out of range"); - } +Result Adapter::getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const { if (group_idx >= std::size(cfg->groupinfo[0])) { - return Result<::cbPKT_GROUPINFO>::error("Group index out of range"); + return Result::error("Group index out of range"); } - return Result<::cbPKT_GROUPINFO>::ok(fromLegacy(cfg->groupinfo[instrument_idx][group_idx])); + fromLegacy(buf, cfg->groupinfo[instrument_idx][group_idx]); + return Result::ok(); } -Result Adapter::getConfigBuffer() const { - if (instrument_idx >= std::size(cfg->procinfo)) { - return Result::error("Instrument index out of range"); - } - return Result::ok(fromLegacy(*cfg)); +Result Adapter::getConfigBuffer(NativeConfigBuffer& buf) const { + fromLegacy(buf, *cfg); + return Result::ok(); } -Result Adapter::getPcStatus() const { - if (instrument_idx >= std::size(status->isSelection)) { - return Result::error("Instrument index out of range"); - } - return Result::ok(fromLegacy(*status)); +Result Adapter::getPcStatus(NativePCStatus& buf) const { + fromLegacy(buf, *status); + return Result::ok(); } -Result Adapter::getSpikeCache(uint32_t channel_idx) const { +Result Adapter::getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const { if (channel_idx >= std::size(spike->cache)) { - return Result::error("Channel index out of range"); + return Result::error("Channel index out of range"); } - return Result::ok(fromLegacy(spike->cache[channel_idx])); + fromLegacy(buf, spike->cache[channel_idx]); + return Result::ok(); } Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { - if (instrument_idx >= std::size(cfg->procinfo)) { - return Result::error("Instrument index out of range"); - } - cfg->procinfo[instrument_idx] = toLegacy(info); + toLegacy(cfg->procinfo[instrument_idx], info); return Result::ok(); } Result Adapter::setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) { - if (instrument_idx >= std::size(cfg->bankinfo)) { - return Result::error("Instrument index out of range"); - } uint32_t bank_idx = bank_num - 1; if (bank_idx >= std::size(cfg->bankinfo[0])) { return Result::error("Bank number out of range"); } - cfg->bankinfo[instrument_idx][bank_idx] = toLegacy(info); + toLegacy(cfg->bankinfo[instrument_idx][bank_idx], info); return Result::ok(); } Result Adapter::setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) { - if (instrument_idx >= std::size(cfg->filtinfo)) { - return Result::error("Instrument index out of range"); - } uint32_t filter_idx = filter_num - 1; if (filter_idx >= std::size(cfg->filtinfo[0])) { return Result::error("Filter number out of range"); } - cfg->filtinfo[instrument_idx][filter_idx] = toLegacy(info); + toLegacy(cfg->filtinfo[instrument_idx][filter_idx], info); return Result::ok(); } @@ -1240,31 +1086,25 @@ Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& if (channel_idx >= std::size(cfg->chaninfo)) { return Result::error("Channel number out of range"); } - cfg->chaninfo[channel_idx] = toLegacy(info); + toLegacy(cfg->chaninfo[channel_idx], info); return Result::ok(); } Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { - cfg->sysinfo = toLegacy(info); + toLegacy(cfg->sysinfo, info); return Result::ok(); } Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { - if (instrument_idx >= std::size(cfg->groupinfo)) { - return Result::error("Instrument index out of range"); - } if (group_idx >= std::size(cfg->groupinfo[0])) { return Result::error("Group index out of range"); } - cfg->groupinfo[instrument_idx][group_idx] = toLegacy(info); + toLegacy(cfg->groupinfo[instrument_idx][group_idx], info); return Result::ok(); } Result Adapter::setNspStatus(const NativeNSPStatus& status) const { - if (instrument_idx >= std::size(this->status->isSelection)) { - return Result::error("Instrument index out of range"); - } - this->status->m_nNspStatus[instrument_idx] = toLegacy(status); + toLegacy(this->status->m_nNspStatus[instrument_idx], status); return Result::ok(); } diff --git a/src/cbshm/src/shmem_session.cpp b/src/cbshm/src/shmem_session.cpp index ff2926ef..a7ab5d84 100644 --- a/src/cbshm/src/shmem_session.cpp +++ b/src/cbshm/src/shmem_session.cpp @@ -834,6 +834,18 @@ struct ShmemSession::Impl { return Result::error("Compatibility with Central requires Windows"); #endif } + + // Helper: get sysfreq from cbPKT_SYSINFO + // Guaranteed to provide a frequency greater than or equal to 1 + // or the default frequency if the true value is unavailable. + decltype(cbPKT_SYSINFO::sysfreq) getSysFreq() { + cbPKT_SYSINFO sysinfo; + auto res = adapter->getSysInfo(sysinfo); + if (res.isError() || sysinfo.sysfreq == 0) { + return 30000; // default + } + return sysinfo.sysfreq; + } }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -942,7 +954,12 @@ Result ShmemSession::getProcInfo() const { if (m_impl->layout == ShmemLayout::NATIVE) { return Result::ok(m_impl->nativeCfg()->procinfo); } else { - return m_impl->adapter->getProcInfo(); + auto info = Result::ok({}); + auto res = m_impl->adapter->getProcInfo(info.value()); + if (res.isError()) { + return Result::error(res.error()); + } + return info; } } @@ -957,7 +974,12 @@ Result ShmemSession::getBankInfo(uint32_t bank) const { } return Result::ok(m_impl->nativeCfg()->bankinfo[bank - 1]); } else { - return m_impl->adapter->getBankInfo(bank); + auto info = Result::ok({}); + auto res = m_impl->adapter->getBankInfo(info.value(), bank); + if (res.isError()) { + return Result::error(res.error()); + } + return info; } } @@ -972,7 +994,12 @@ Result ShmemSession::getFilterInfo(uint32_t filter) const { } return Result::ok(m_impl->nativeCfg()->filtinfo[filter - 1]); } else { - return m_impl->adapter->getFilterInfo(filter); + auto info = Result::ok({}); + auto res = m_impl->adapter->getFilterInfo(info.value(), filter); + if (res.isError()) { + return Result::error(res.error()); + } + return info; } } @@ -987,7 +1014,12 @@ Result ShmemSession::getChanInfo(uint32_t channel) const { } return Result::ok(m_impl->nativeCfg()->chaninfo[channel]); } else { - return m_impl->adapter->getChanInfo(channel); + auto info = Result::ok({}); + auto res = m_impl->adapter->getChanInfo(info.value(), channel); + if (res.isError()) { + return Result::error(res.error()); + } + return info; } } @@ -999,7 +1031,12 @@ Result ShmemSession::getSysInfo() const { if (m_impl->layout == ShmemLayout::NATIVE) { return Result::ok(m_impl->nativeCfg()->sysinfo); } else { - return m_impl->adapter->getSysInfo(); + auto info = Result::ok({}); + auto res = m_impl->adapter->getSysInfo(info.value()); + if (res.isError()) { + return Result::error(res.error()); + } + return info; } } @@ -1014,7 +1051,12 @@ Result ShmemSession::getGroupInfo(uint32_t group) const { } return Result::ok(m_impl->nativeCfg()->groupinfo[group]); } else { - return m_impl->adapter->getGroupInfo(group); + auto info = Result::ok({}); + auto res = m_impl->adapter->getGroupInfo(info.value(), group); + if (res.isError()) { + return Result::error(res.error()); + } + return info; } } @@ -1130,11 +1172,11 @@ const NativeConfigBuffer* ShmemSession::getNativeConfigBuffer() const { return m_impl->nativeCfg(); } -Result ShmemSession::getLegacyConfigBuffer() { +Result ShmemSession::getLegacyConfigBuffer(NativeConfigBuffer& buf) { if (!isOpen() || m_impl->layout != ShmemLayout::CENTRAL) { - return Result::error("Not open or invalid layout"); + return Result::error("Not open or invalid layout"); } - return m_impl->adapter->getConfigBuffer(); + return m_impl->adapter->getConfigBuffer(buf); } Result ShmemSession::storePacket(const cbPKT_GENERIC& pkt) { @@ -1212,8 +1254,7 @@ Result ShmemSession::enqueuePacket(const cbPKT_GENERIC& pkt) { // Central's xmt consumer expects device-native format. auto gemini = isGeminiSystem(); if (gemini.isOk() && !gemini.value() && dest_hdr.time != 0) { - uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check the return value - if (sysfreq == 0) sysfreq = 30000; + uint32_t sysfreq = m_impl->getSysFreq(); uint64_t g = std::gcd(uint64_t(1000000000), uint64_t(sysfreq)); dest_hdr.time = dest_hdr.time * (sysfreq / g) / (1000000000 / g); } @@ -1235,8 +1276,7 @@ Result ShmemSession::enqueuePacket(const cbPKT_GENERIC& pkt) { // Non-Gemini: convert nanosecond timestamp back to device clock ticks. auto gemini = isGeminiSystem(); if (gemini.isOk() && !gemini.value() && dest_hdr.time != 0) { - uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check the return value - if (sysfreq == 0) sysfreq = 30000; + uint32_t sysfreq = m_impl->getSysFreq(); uint64_t g = std::gcd(uint64_t(1000000000), uint64_t(sysfreq)); dest_hdr.time = dest_hdr.time * (sysfreq / g) / (1000000000 / g); } @@ -1250,8 +1290,7 @@ Result ShmemSession::enqueuePacket(const cbPKT_GENERIC& pkt) { std::memcpy(translated_buf, &pkt, (cbPKT_HEADER_32SIZE + pkt.cbpkt_header.dlen) * sizeof(uint32_t)); auto& dest_hdr = *reinterpret_cast(translated_buf); - uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check the return value - if (sysfreq == 0) sysfreq = 30000; + uint32_t sysfreq = m_impl->getSysFreq(); uint64_t g = std::gcd(uint64_t(1000000000), uint64_t(sysfreq)); dest_hdr.time = dest_hdr.time * (sysfreq / g) / (1000000000 / g); write_data = translated_buf; @@ -1503,11 +1542,12 @@ Result ShmemSession::getNumTotalChans() const { if (m_impl->layout == ShmemLayout::NATIVE) { return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nNumTotalChans); } else { - auto status = m_impl->adapter->getPcStatus(); - if (status.isError()) { - return Result::error("Unable to fetch PC status"); + NativePCStatus status; + auto res = m_impl->adapter->getPcStatus(status); + if (res.isError()) { + return Result::error(res.error()); } - return Result::ok(status.value().m_nNumTotalChans); + return Result::ok(status.m_nNumTotalChans); } } @@ -1522,11 +1562,12 @@ Result ShmemSession::getNspStatus() const { if (m_impl->layout == ShmemLayout::NATIVE) { return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nNspStatus); } else { - auto status = m_impl->adapter->getPcStatus(); - if (status.isError()) { - return Result::error("Unable to fetch PC status"); + NativePCStatus status; + auto res = m_impl->adapter->getPcStatus(status); + if (res.isError()) { + return Result::error(res.error()); } - return Result::ok(status.value().m_nNspStatus); + return Result::ok(status.m_nNspStatus); } } @@ -1558,11 +1599,12 @@ Result ShmemSession::isGeminiSystem() const { if (m_impl->layout == ShmemLayout::NATIVE) { return Result::ok(static_cast(m_impl->status_buffer_raw)->m_nGeminiSystem != 0); } else { - auto status = m_impl->adapter->getPcStatus(); - if (status.isError()) { - return Result::error("Unable to fetch PC status"); + NativePCStatus status; + auto res = m_impl->adapter->getPcStatus(status); + if (res.isError()) { + return Result::error(res.error()); } - return Result::ok(status.value().m_nGeminiSystem); + return Result::ok(status.m_nGeminiSystem); } } @@ -1608,12 +1650,10 @@ Result ShmemSession::getSpikeCache(uint32_t channel, NativeSpikeCache& cac cache.valid = src.valid; std::memcpy(cache.spkpkt, src.spkpkt, sizeof(cbPKT_SPK) * src.pktcnt); } else { - auto res = m_impl->adapter->getSpikeCache(channel); + auto res = m_impl->adapter->getSpikeCache(cache, channel); if (res.isError()) { return Result::error(res.error()); } - cache = res.value(); - return Result::ok(); } return Result::ok(); @@ -1640,17 +1680,16 @@ Result ShmemSession::getRecentSpike(uint32_t channel, cbPKT_SPK& spike) co spike = cache.spkpkt[recent_idx]; return Result::ok(true); } else { - // TODO: Duplicate logic - auto res = m_impl->adapter->getSpikeCache(channel); + auto cache = std::make_unique(); + auto res = m_impl->adapter->getSpikeCache(*cache, channel); if (res.isError()) { return Result::error(res.error()); } - const auto& cache = res.value(); - if (cache.valid == 0) { + if (cache->valid == 0) { return Result::ok(false); } - uint32_t recent_idx = (cache.head == 0) ? (cache.pktcnt - 1) : (cache.head - 1); - spike = cache.spkpkt[recent_idx]; + uint32_t recent_idx = (cache->head == 0) ? (cache->pktcnt - 1) : (cache->head - 1); + spike = cache->spkpkt[recent_idx]; return Result::ok(true); } } @@ -1779,8 +1818,7 @@ PROCTIME ShmemSession::getLastTime() const { if (t != 0 && m_impl->layout == ShmemLayout::CENTRAL) { auto gemini = isGeminiSystem(); if (gemini.isOk() && !gemini.value()) { - uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check return value - if (sysfreq == 0) sysfreq = 30000; + uint32_t sysfreq = m_impl->getSysFreq(); uint64_t g = std::gcd(uint64_t(1000000000), uint64_t(sysfreq)); t = t * (1000000000 / g) / (sysfreq / g); } @@ -1831,8 +1869,7 @@ Result ShmemSession::readReceiveBuffer(cbPKT_GENERIC* packets, size_t max_ m_impl->status_buffer_raw) { auto gemini = isGeminiSystem(); if (gemini.isOk() && !gemini.value()) { - uint32_t sysfreq = m_impl->adapter->getSysInfo().value().sysfreq; // TODO: Check the return value - if (sysfreq == 0) sysfreq = 30000; + uint32_t sysfreq = m_impl->getSysFreq(); uint64_t g = std::gcd(uint64_t(1000000000), uint64_t(sysfreq)); ts_num = 1000000000 / g; ts_den = sysfreq / g; From f868deb53a253a22c2fb824f6d9b10fadfca5bab Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Thu, 18 Jun 2026 11:31:29 -0600 Subject: [PATCH 32/62] FIX: Central 7.7.0 -> procotol 4.1 --- src/cbshm/src/shmem_session.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cbshm/src/shmem_session.cpp b/src/cbshm/src/shmem_session.cpp index a7ab5d84..a88a5b09 100644 --- a/src/cbshm/src/shmem_session.cpp +++ b/src/cbshm/src/shmem_session.cpp @@ -802,9 +802,9 @@ struct ShmemSession::Impl { case 7: switch (minor_version) { case 8: - /* fallthrough */ - case 7: return Result::ok(CBPROTO_PROTOCOL_CURRENT); + case 7: + /* fallthrough */ case 6: return Result::ok(CBPROTO_PROTOCOL_410); case 5: From d5d98465f04c3837304b8dc483b19b84ef21aea4 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Thu, 18 Jun 2026 13:22:22 -0600 Subject: [PATCH 33/62] Split adapters.h into per-version header files --- .../include/cbshm/central_adapters/base.h | 163 ++++ .../include/cbshm/central_adapters/v3_11.h | 190 ++++ .../include/cbshm/central_adapters/v4_0.h | 190 ++++ .../include/cbshm/central_adapters/v4_1.h | 190 ++++ .../include/cbshm/central_adapters/v4_2.h | 190 ++++ .../current.h => central_current.h} | 14 +- .../include/cbshm/central_types/adapters.h | 850 ------------------ src/cbshm/include/cbshm/shmem_session.h | 2 +- src/cbshm/src/central_adapters/v3_11.cpp | 88 +- src/cbshm/src/central_adapters/v4_0.cpp | 88 +- src/cbshm/src/central_adapters/v4_1.cpp | 88 +- src/cbshm/src/central_adapters/v4_2.cpp | 88 +- src/cbshm/src/shmem_session.cpp | 7 +- 13 files changed, 1113 insertions(+), 1035 deletions(-) create mode 100644 src/cbshm/include/cbshm/central_adapters/base.h create mode 100644 src/cbshm/include/cbshm/central_adapters/v3_11.h create mode 100644 src/cbshm/include/cbshm/central_adapters/v4_0.h create mode 100644 src/cbshm/include/cbshm/central_adapters/v4_1.h create mode 100644 src/cbshm/include/cbshm/central_adapters/v4_2.h rename src/cbshm/include/cbshm/{central_types/current.h => central_current.h} (62%) delete mode 100644 src/cbshm/include/cbshm/central_types/adapters.h diff --git a/src/cbshm/include/cbshm/central_adapters/base.h b/src/cbshm/include/cbshm/central_adapters/base.h new file mode 100644 index 00000000..eb9729de --- /dev/null +++ b/src/cbshm/include/cbshm/central_adapters/base.h @@ -0,0 +1,163 @@ + +/// @file base.h +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Base classes for the Central-compatible shared memory access adapters +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef CBSHM_CENTRAL_ADAPTERS_BASE_H +#define CBSHM_CENTRAL_ADAPTERS_BASE_H + +#include +#include +#include +#include +#include +#include +#include + +namespace cbshm { + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Base-class adapter that provides information used to fetch pointers to Central's shared memory +/// +class CentralBootstrapAdapterBase { +public: + // Buffer sizes + virtual size_t getConfigBufferSize() const = 0; + virtual size_t getReceiveBufferSize() const = 0; + virtual size_t getTransmitBufferSize() const = 0; + virtual size_t getTransmitBufferLocalSize() const = 0; + virtual size_t getStatusBufferSize() const = 0; + virtual size_t getSpikeBufferSize() const = 0; + virtual size_t getReceiveBufferLen() const = 0; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Base-class adapter for Central-compatible shared memory access +/// +class CentralAdapterBase { +protected: + template + static void copyArr(T(&lhs)[lhs_n], const T(&rhs)[rhs_n]) { + if (lhs_n <= rhs_n) { + std::memcpy(lhs, rhs, lhs_n * sizeof(T)); + } else { + std::memcpy(lhs, rhs, rhs_n * sizeof(T)); + std::memset(lhs + rhs_n, 0, (lhs_n - rhs_n) * sizeof(T)); + } + } + + template + static void copyArr(LHS_T(&lhs)[lhs_n], const RHS_T(&rhs)[rhs_n], const A* adapter, void(A::*translation_func)(LHS_T&, const RHS_T&) const) { + if (lhs_n <= rhs_n) { + for (size_t i = 0; i < lhs_n; ++i) { + (adapter->*translation_func)(lhs[i], rhs[i]); + } + } else { + for (size_t i = 0; i < rhs_n; ++i) { + (adapter->*translation_func)(lhs[i], rhs[i]); + } + std::memset(lhs + rhs_n, 0, (lhs_n - rhs_n) * sizeof(LHS_T)); + } + } + + template + static void copyArr2D(T(&lhs)[lhs_ny][lhs_nx], const T(&rhs)[rhs_ny][rhs_nx]) { + if (lhs_ny <= rhs_ny) { + if (lhs_nx == rhs_nx) { + std::memcpy(lhs, rhs, (lhs_ny * lhs_nx) * sizeof(T)); + } else { + for (size_t i = 0; i < lhs_ny; ++i) { + copyArr(lhs[i], rhs[i]); + } + } + } else { + if (lhs_nx == rhs_nx) { + std::memcpy(lhs, rhs, (rhs_ny * rhs_nx) * sizeof(T)); + } else { + for (size_t i = 0; i < rhs_ny; ++i) { + copyArr(lhs[i], rhs[i]); + } + } + std::memset(lhs + rhs_ny, 0, ((lhs_ny - rhs_ny) * lhs_nx) * sizeof(T)); + } + } + + template + static const void copyArr2D(LHS_T(&lhs)[lhs_ny][lhs_nx], const RHS_T(&rhs)[rhs_ny][rhs_nx], const A* adapter, void(A::*translation_func)(LHS_T&, const RHS_T&) const) { + if (lhs_ny <= rhs_ny) { + for (size_t i = 0; i < lhs_ny; ++i) { + copyArr(lhs[i], rhs[i], adapter, translation_func); + } + } else { + for (size_t i = 0; i < rhs_ny; ++i) { + copyArr(lhs[i], rhs[i], adapter, translation_func); + } + std::memset(lhs + rhs_ny, 0, ((lhs_ny - rhs_ny) * lhs_nx) * sizeof(LHS_T)); + } + } + +public: + virtual ~CentralAdapterBase() = default; + + // Max instrument count + virtual uint32_t getMaxProcs() const = 0; + + /////////////////////////////////////////////////////////////////////////////////////////////// + // DANGER !!! + // These methods are brittle and serve as a workaround for the ShmemSession + // implementation requiring direct pointer access to the receive and transmit buffers. + + // Receive buffer access + virtual uint32_t& getRecReceived() = 0; + virtual uint64_t getRecLasttime() = 0; + virtual void setRecLasttime(uint64_t lasttime) = 0; + virtual uint32_t& getRecHeadwrapPtr() = 0; + virtual uint32_t& getRecHeadindexPtr() = 0; + virtual uint32_t* getRecBufferPtr() = 0; + + // Transmit buffer access + virtual uint32_t& getXmtTransmittedPtr() = 0; + virtual uint32_t& getXmtHeadindexPtr() = 0; + virtual uint32_t& getXmtTailindexPtr() = 0; + virtual uint32_t& getXmtLastValidIndexPtr() = 0; + virtual uint32_t& getXmtBufferlenPtr() = 0; + virtual uint32_t* getXmtBufferPtr() = 0; + + virtual uint32_t& getLocalXmtTransmittedPtr() = 0; + virtual uint32_t& getLocalXmtHeadindexPtr() = 0; + virtual uint32_t& getLocalXmtTailindexPtr() = 0; + virtual uint32_t& getLocalXmtLastValidIndexPtr() = 0; + virtual uint32_t& getLocalXmtBufferlenPtr() = 0; + virtual uint32_t* getLocalXmtBufferPtr() = 0; + + /////////////////////////////////////////////////////////////////////////////////////////////// + + /// Config read operations + virtual cbutil::Result getProcInfo(::cbPKT_PROCINFO& buf) const = 0; + virtual cbutil::Result getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const = 0; + virtual cbutil::Result getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const = 0; + virtual cbutil::Result getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const = 0; + virtual cbutil::Result getSysInfo(::cbPKT_SYSINFO& buf) const = 0; + virtual cbutil::Result getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const = 0; + virtual cbutil::Result getConfigBuffer(NativeConfigBuffer& buf) const = 0; + virtual cbutil::Result getPcStatus(NativePCStatus& buf) const = 0; + virtual cbutil::Result getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const = 0; + + /// Config write operations + virtual cbutil::Result setProcInfo(const ::cbPKT_PROCINFO& info) = 0; + virtual cbutil::Result setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) = 0; + virtual cbutil::Result setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) = 0; + virtual cbutil::Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) = 0; + virtual cbutil::Result setSysInfo(const ::cbPKT_SYSINFO& info) = 0; + virtual cbutil::Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) = 0; + virtual cbutil::Result setNspStatus(const NativeNSPStatus& status) const = 0; + virtual cbutil::Result setGeminiSystem(bool is_gemini) const = 0; +}; + +} // namespace cbshm + +#endif // CBSHM_CENTRAL_ADAPTERS_BASE_H diff --git a/src/cbshm/include/cbshm/central_adapters/v3_11.h b/src/cbshm/include/cbshm/central_adapters/v3_11.h new file mode 100644 index 00000000..90fc040e --- /dev/null +++ b/src/cbshm/include/cbshm/central_adapters/v3_11.h @@ -0,0 +1,190 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v3_11.h +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Adapter for Central-compatible shared memory access +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef CBSHM_CENTRAL_ADAPTERS_V3_11_H +#define CBSHM_CENTRAL_ADAPTERS_V3_11_H + +#include +#include + +namespace cbshm { + +namespace central_v3_11 { + +/// +/// @brief Adapter that provides information for fetching pointers to Central's shared memory +/// +class BootstrapAdapter : public ::cbshm::CentralBootstrapAdapterBase { +public: + // Buffer sizes + size_t getConfigBufferSize() const override; + size_t getReceiveBufferSize() const override; + size_t getTransmitBufferSize() const override; + size_t getTransmitBufferLocalSize() const override; + size_t getStatusBufferSize() const override; + size_t getSpikeBufferSize() const override; + size_t getReceiveBufferLen() const override; +}; + +/// +/// @brief Adapter for Central-compatible shared memory access +/// +class Adapter : public CentralAdapterBase { +private: + uint8_t instrument_idx; + cbCFGBUFF* cfg; + cbRECBUFF* rec; + cbXMTBUFF* xmt; + cbXMTBUFFLOCAL* xmt_local; + cbPcStatus* status; + cbSPKBUFF* spike; + + void fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const; + void fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const; + void fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const; + void fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const; + void fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const; + void fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const; + void fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const; + void fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const; + void fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const; + void fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const; + void fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const; + void fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const; + void fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const; + void fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const; + void fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const; + void fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const; + void fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const; + void fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const; + void fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const; + void fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const; + void fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const; + void fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const; + void fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const; + void fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const; + void fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const; + void fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const; + void fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const; + void fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const; + void fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const; + void fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const; + void fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const; + void fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const; + void fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const; + void fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const; + void fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const; + void fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const; + void fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const; + void fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const; + void fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const; + void fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const; + + void toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const; + void toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const; + void toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const; + void toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const; + void toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const; + void toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const; + void toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const; + void toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const; + void toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const; + void toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const; + void toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const; + void toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const; + void toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const; + void toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const; + void toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const; + void toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const; + void toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const; + void toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; + void toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const; + void toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const; + void toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const; + void toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const; + void toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const; + void toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const; + void toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const; + void toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const; + void toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const; + void toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const; + void toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const; + void toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const; + void toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const; + void toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const; + void toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const; + void toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const; + void toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const; + void toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const; + +public: + Adapter( + uint8_t instrument_idx, + void* cfg_ptr, + void* rec_ptr, + void* xmt_ptr, + void* xmt_local_ptr, + void* status_ptr, + void* spike_ptr + ); + ~Adapter() = default; + + // Max instrument count + uint32_t getMaxProcs() const override; + + // Receive buffer access + uint32_t& getRecReceived() override; + uint64_t getRecLasttime() override; + void setRecLasttime(uint64_t lasttime) override; + uint32_t& getRecHeadwrapPtr() override; + uint32_t& getRecHeadindexPtr() override; + uint32_t* getRecBufferPtr() override; + + // Transmit buffer access + uint32_t& getXmtTransmittedPtr() override; + uint32_t& getXmtHeadindexPtr() override; + uint32_t& getXmtTailindexPtr() override; + uint32_t& getXmtLastValidIndexPtr() override; + uint32_t& getXmtBufferlenPtr() override; + uint32_t* getXmtBufferPtr() override; + + uint32_t& getLocalXmtTransmittedPtr() override; + uint32_t& getLocalXmtHeadindexPtr() override; + uint32_t& getLocalXmtTailindexPtr() override; + uint32_t& getLocalXmtLastValidIndexPtr() override; + uint32_t& getLocalXmtBufferlenPtr() override; + uint32_t* getLocalXmtBufferPtr() override; + + /// Config read operations + cbutil::Result getProcInfo(::cbPKT_PROCINFO& buf) const override; + cbutil::Result getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const override; + cbutil::Result getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const override; + cbutil::Result getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const override; + cbutil::Result getSysInfo(::cbPKT_SYSINFO& buf) const override; + cbutil::Result getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const override; + cbutil::Result getConfigBuffer(NativeConfigBuffer& buf) const override; + cbutil::Result getPcStatus(NativePCStatus& buf) const override; + cbutil::Result getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const override; + + /// Config write operations + cbutil::Result setProcInfo(const ::cbPKT_PROCINFO& info) override; + cbutil::Result setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; + cbutil::Result setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; + cbutil::Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; + cbutil::Result setSysInfo(const ::cbPKT_SYSINFO& info) override; + cbutil::Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; + cbutil::Result setNspStatus(const NativeNSPStatus& status) const override; + cbutil::Result setGeminiSystem(bool is_gemini) const override; +}; + +} // namespace central_v3_11 + +} // namespace cbshm + +#endif // CBSHM_CENTRAL_ADAPTERS_V3_11_H diff --git a/src/cbshm/include/cbshm/central_adapters/v4_0.h b/src/cbshm/include/cbshm/central_adapters/v4_0.h new file mode 100644 index 00000000..ed60ba4c --- /dev/null +++ b/src/cbshm/include/cbshm/central_adapters/v4_0.h @@ -0,0 +1,190 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v4_0.h +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Adapter for Central-compatible shared memory access +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef CBSHM_CENTRAL_ADAPTERS_V4_0_H +#define CBSHM_CENTRAL_ADAPTERS_V4_0_H + +#include +#include + +namespace cbshm { + +namespace central_v4_0 { + +/// +/// @brief Adapter that provides information for fetching pointers to Central's shared memory +/// +class BootstrapAdapter : public ::cbshm::CentralBootstrapAdapterBase { +public: + // Buffer sizes + size_t getConfigBufferSize() const override; + size_t getReceiveBufferSize() const override; + size_t getTransmitBufferSize() const override; + size_t getTransmitBufferLocalSize() const override; + size_t getStatusBufferSize() const override; + size_t getSpikeBufferSize() const override; + size_t getReceiveBufferLen() const override; +}; + +/// +/// @brief Adapter for Central-compatible shared memory access +/// +class Adapter : public CentralAdapterBase { +private: + uint8_t instrument_idx; + cbCFGBUFF* cfg; + cbRECBUFF* rec; + cbXMTBUFF* xmt; + cbXMTBUFFLOCAL* xmt_local; + cbPcStatus* status; + cbSPKBUFF* spike; + + void fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const; + void fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const; + void fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const; + void fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const; + void fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const; + void fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const; + void fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const; + void fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const; + void fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const; + void fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const; + void fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const; + void fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const; + void fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const; + void fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const; + void fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const; + void fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const; + void fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const; + void fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const; + void fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const; + void fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const; + void fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const; + void fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const; + void fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const; + void fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const; + void fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const; + void fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const; + void fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const; + void fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const; + void fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const; + void fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const; + void fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const; + void fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const; + void fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const; + void fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const; + void fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const; + void fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const; + void fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const; + void fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const; + void fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const; + void fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const; + + void toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const; + void toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const; + void toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const; + void toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const; + void toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const; + void toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const; + void toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const; + void toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const; + void toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const; + void toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const; + void toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const; + void toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const; + void toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const; + void toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const; + void toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const; + void toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const; + void toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const; + void toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; + void toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const; + void toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const; + void toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const; + void toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const; + void toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const; + void toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const; + void toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const; + void toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const; + void toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const; + void toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const; + void toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const; + void toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const; + void toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const; + void toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const; + void toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const; + void toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const; + void toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const; + void toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const; + +public: + Adapter( + uint8_t instrument_idx, + void* cfg_ptr, + void* rec_ptr, + void* xmt_ptr, + void* xmt_local_ptr, + void* status_ptr, + void* spike_ptr + ); + ~Adapter() = default; + + // Max instrument count + uint32_t getMaxProcs() const override; + + // Receive buffer access + uint32_t& getRecReceived() override; + uint64_t getRecLasttime() override; + void setRecLasttime(uint64_t lasttime) override; + uint32_t& getRecHeadwrapPtr() override; + uint32_t& getRecHeadindexPtr() override; + uint32_t* getRecBufferPtr() override; + + // Transmit buffer access + uint32_t& getXmtTransmittedPtr() override; + uint32_t& getXmtHeadindexPtr() override; + uint32_t& getXmtTailindexPtr() override; + uint32_t& getXmtLastValidIndexPtr() override; + uint32_t& getXmtBufferlenPtr() override; + uint32_t* getXmtBufferPtr() override; + + uint32_t& getLocalXmtTransmittedPtr() override; + uint32_t& getLocalXmtHeadindexPtr() override; + uint32_t& getLocalXmtTailindexPtr() override; + uint32_t& getLocalXmtLastValidIndexPtr() override; + uint32_t& getLocalXmtBufferlenPtr() override; + uint32_t* getLocalXmtBufferPtr() override; + + /// Config read operations + cbutil::Result getProcInfo(::cbPKT_PROCINFO& buf) const override; + cbutil::Result getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const override; + cbutil::Result getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const override; + cbutil::Result getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const override; + cbutil::Result getSysInfo(::cbPKT_SYSINFO& buf) const override; + cbutil::Result getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const override; + cbutil::Result getConfigBuffer(NativeConfigBuffer& buf) const override; + cbutil::Result getPcStatus(NativePCStatus& buf) const override; + cbutil::Result getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const override; + + /// Config write operations + cbutil::Result setProcInfo(const ::cbPKT_PROCINFO& info) override; + cbutil::Result setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; + cbutil::Result setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; + cbutil::Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; + cbutil::Result setSysInfo(const ::cbPKT_SYSINFO& info) override; + cbutil::Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; + cbutil::Result setNspStatus(const NativeNSPStatus& status) const override; + cbutil::Result setGeminiSystem(bool is_gemini) const override; +}; + +} // namespace central_v4_0 + +} // namespace cbshm + +#endif // CBSHM_CENTRAL_ADAPTERS_V4_0_H diff --git a/src/cbshm/include/cbshm/central_adapters/v4_1.h b/src/cbshm/include/cbshm/central_adapters/v4_1.h new file mode 100644 index 00000000..736871aa --- /dev/null +++ b/src/cbshm/include/cbshm/central_adapters/v4_1.h @@ -0,0 +1,190 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v4_1.h +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Adapter for Central-compatible shared memory access +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef CBSHM_CENTRAL_ADAPTERS_V4_1_H +#define CBSHM_CENTRAL_ADAPTERS_V4_1_H + +#include +#include + +namespace cbshm { + +namespace central_v4_1 { + +/// +/// @brief Adapter that provides information for fetching pointers to Central's shared memory +/// +class BootstrapAdapter : public ::cbshm::CentralBootstrapAdapterBase { +public: + // Buffer sizes + size_t getConfigBufferSize() const override; + size_t getReceiveBufferSize() const override; + size_t getTransmitBufferSize() const override; + size_t getTransmitBufferLocalSize() const override; + size_t getStatusBufferSize() const override; + size_t getSpikeBufferSize() const override; + size_t getReceiveBufferLen() const override; +}; + +/// +/// @brief Adapter for Central-compatible shared memory access +/// +class Adapter : public CentralAdapterBase { +private: + uint8_t instrument_idx; + cbCFGBUFF* cfg; + cbRECBUFF* rec; + cbXMTBUFF* xmt; + cbXMTBUFFLOCAL* xmt_local; + cbPcStatus* status; + cbSPKBUFF* spike; + + void fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const; + void fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const; + void fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const; + void fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const; + void fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const; + void fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const; + void fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const; + void fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const; + void fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const; + void fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const; + void fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const; + void fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const; + void fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const; + void fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const; + void fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const; + void fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const; + void fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const; + void fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const; + void fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const; + void fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const; + void fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const; + void fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const; + void fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const; + void fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const; + void fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const; + void fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const; + void fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const; + void fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const; + void fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const; + void fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const; + void fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const; + void fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const; + void fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const; + void fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const; + void fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const; + void fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const; + void fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const; + void fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const; + void fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const; + void fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const; + + void toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const; + void toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const; + void toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const; + void toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const; + void toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const; + void toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const; + void toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const; + void toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const; + void toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const; + void toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const; + void toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const; + void toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const; + void toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const; + void toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const; + void toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const; + void toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const; + void toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const; + void toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; + void toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const; + void toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const; + void toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const; + void toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const; + void toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const; + void toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const; + void toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const; + void toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const; + void toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const; + void toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const; + void toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const; + void toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const; + void toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const; + void toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const; + void toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const; + void toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const; + void toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const; + void toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const; + +public: + Adapter( + uint8_t instrument_idx, + void* cfg_ptr, + void* rec_ptr, + void* xmt_ptr, + void* xmt_local_ptr, + void* status_ptr, + void* spike_ptr + ); + ~Adapter() = default; + + // Max instrument count + uint32_t getMaxProcs() const override; + + // Receive buffer access + uint32_t& getRecReceived() override; + uint64_t getRecLasttime() override; + void setRecLasttime(uint64_t lasttime) override; + uint32_t& getRecHeadwrapPtr() override; + uint32_t& getRecHeadindexPtr() override; + uint32_t* getRecBufferPtr() override; + + // Transmit buffer access + uint32_t& getXmtTransmittedPtr() override; + uint32_t& getXmtHeadindexPtr() override; + uint32_t& getXmtTailindexPtr() override; + uint32_t& getXmtLastValidIndexPtr() override; + uint32_t& getXmtBufferlenPtr() override; + uint32_t* getXmtBufferPtr() override; + + uint32_t& getLocalXmtTransmittedPtr() override; + uint32_t& getLocalXmtHeadindexPtr() override; + uint32_t& getLocalXmtTailindexPtr() override; + uint32_t& getLocalXmtLastValidIndexPtr() override; + uint32_t& getLocalXmtBufferlenPtr() override; + uint32_t* getLocalXmtBufferPtr() override; + + /// Config read operations + cbutil::Result getProcInfo(::cbPKT_PROCINFO& buf) const override; + cbutil::Result getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const override; + cbutil::Result getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const override; + cbutil::Result getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const override; + cbutil::Result getSysInfo(::cbPKT_SYSINFO& buf) const override; + cbutil::Result getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const override; + cbutil::Result getConfigBuffer(NativeConfigBuffer& buf) const override; + cbutil::Result getPcStatus(NativePCStatus& buf) const override; + cbutil::Result getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const override; + + /// Config write operations + cbutil::Result setProcInfo(const ::cbPKT_PROCINFO& info) override; + cbutil::Result setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; + cbutil::Result setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; + cbutil::Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; + cbutil::Result setSysInfo(const ::cbPKT_SYSINFO& info) override; + cbutil::Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; + cbutil::Result setNspStatus(const NativeNSPStatus& status) const override; + cbutil::Result setGeminiSystem(bool is_gemini) const override; +}; + +} // namespace central_v4_1 + +} // namespace cbshm + +#endif // CBSHM_CENTRAL_ADAPTERS_V4_1_H diff --git a/src/cbshm/include/cbshm/central_adapters/v4_2.h b/src/cbshm/include/cbshm/central_adapters/v4_2.h new file mode 100644 index 00000000..005deba3 --- /dev/null +++ b/src/cbshm/include/cbshm/central_adapters/v4_2.h @@ -0,0 +1,190 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v4_2.h +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Adapter for Central-compatible shared memory access +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef CBSHM_CENTRAL_ADAPTERS_V4_2_H +#define CBSHM_CENTRAL_ADAPTERS_V4_2_H + +#include +#include + +namespace cbshm { + +namespace central_v4_2 { + +/// +/// @brief Adapter that provides information for fetching pointers to Central's shared memory +/// +class BootstrapAdapter : public ::cbshm::CentralBootstrapAdapterBase { +public: + // Buffer sizes + size_t getConfigBufferSize() const override; + size_t getReceiveBufferSize() const override; + size_t getTransmitBufferSize() const override; + size_t getTransmitBufferLocalSize() const override; + size_t getStatusBufferSize() const override; + size_t getSpikeBufferSize() const override; + size_t getReceiveBufferLen() const override; +}; + +/// +/// @brief Adapter for Central-compatible shared memory access +/// +class Adapter : public CentralAdapterBase { +private: + uint8_t instrument_idx; + cbCFGBUFF* cfg; + cbRECBUFF* rec; + cbXMTBUFF* xmt; + cbXMTBUFFLOCAL* xmt_local; + cbPcStatus* status; + cbSPKBUFF* spike; + + void fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const; + void fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const; + void fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const; + void fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const; + void fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const; + void fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const; + void fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const; + void fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const; + void fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const; + void fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const; + void fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const; + void fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const; + void fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const; + void fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const; + void fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const; + void fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const; + void fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const; + void fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const; + void fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const; + void fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const; + void fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const; + void fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const; + void fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const; + void fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const; + void fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const; + void fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const; + void fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const; + void fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const; + void fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const; + void fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const; + void fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const; + void fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const; + void fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const; + void fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const; + void fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const; + void fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const; + void fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const; + void fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const; + void fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const; + void fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const; + + void toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const; + void toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const; + void toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const; + void toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const; + void toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const; + void toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const; + void toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const; + void toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const; + void toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const; + void toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const; + void toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const; + void toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const; + void toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const; + void toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const; + void toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const; + void toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const; + void toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const; + void toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; + void toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const; + void toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const; + void toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const; + void toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const; + void toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const; + void toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const; + void toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const; + void toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const; + void toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const; + void toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const; + void toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const; + void toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const; + void toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const; + void toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const; + void toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const; + void toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const; + void toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const; + void toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const; + +public: + Adapter( + uint8_t instrument_idx, + void* cfg_ptr, + void* rec_ptr, + void* xmt_ptr, + void* xmt_local_ptr, + void* status_ptr, + void* spike_ptr + ); + ~Adapter() = default; + + // Max instrument count + uint32_t getMaxProcs() const override; + + // Receive buffer access + uint32_t& getRecReceived() override; + uint64_t getRecLasttime() override; + void setRecLasttime(uint64_t lasttime) override; + uint32_t& getRecHeadwrapPtr() override; + uint32_t& getRecHeadindexPtr() override; + uint32_t* getRecBufferPtr() override; + + // Transmit buffer access + uint32_t& getXmtTransmittedPtr() override; + uint32_t& getXmtHeadindexPtr() override; + uint32_t& getXmtTailindexPtr() override; + uint32_t& getXmtLastValidIndexPtr() override; + uint32_t& getXmtBufferlenPtr() override; + uint32_t* getXmtBufferPtr() override; + + uint32_t& getLocalXmtTransmittedPtr() override; + uint32_t& getLocalXmtHeadindexPtr() override; + uint32_t& getLocalXmtTailindexPtr() override; + uint32_t& getLocalXmtLastValidIndexPtr() override; + uint32_t& getLocalXmtBufferlenPtr() override; + uint32_t* getLocalXmtBufferPtr() override; + + /// Config read operations + cbutil::Result getProcInfo(::cbPKT_PROCINFO& buf) const override; + cbutil::Result getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const override; + cbutil::Result getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const override; + cbutil::Result getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const override; + cbutil::Result getSysInfo(::cbPKT_SYSINFO& buf) const override; + cbutil::Result getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const override; + cbutil::Result getConfigBuffer(NativeConfigBuffer& buf) const override; + cbutil::Result getPcStatus(NativePCStatus& buf) const override; + cbutil::Result getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const override; + + /// Config write operations + cbutil::Result setProcInfo(const ::cbPKT_PROCINFO& info) override; + cbutil::Result setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; + cbutil::Result setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; + cbutil::Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; + cbutil::Result setSysInfo(const ::cbPKT_SYSINFO& info) override; + cbutil::Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; + cbutil::Result setNspStatus(const NativeNSPStatus& status) const override; + cbutil::Result setGeminiSystem(bool is_gemini) const override; +}; + +} // namespace central_v4_2 + +} // namespace cbshm + +#endif // CBSHM_CENTRAL_ADAPTERS_V4_2_H diff --git a/src/cbshm/include/cbshm/central_types/current.h b/src/cbshm/include/cbshm/central_current.h similarity index 62% rename from src/cbshm/include/cbshm/central_types/current.h rename to src/cbshm/include/cbshm/central_current.h index d02932ba..bbd95e1f 100644 --- a/src/cbshm/include/cbshm/central_types/current.h +++ b/src/cbshm/include/cbshm/central_current.h @@ -1,20 +1,22 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// /// @file current.h /// @author Caden Shmookler -/// @date 2026-05-15 +/// @date 2026-05-22 /// /// @brief Default version selection for Central-compatible shared memory -/// structure definitions +/// structure and adapter definitions /// /// Central-compatible shared memory structure definitions have been moved to -/// version-specific files in central_types/. +/// version-specific files in central_types/. Adapters are declared in +/// central_adapters/. /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifndef CBSHM_CENTRAL_TYPES_CURRENT_H -#define CBSHM_CENTRAL_TYPES_CURRENT_H +#ifndef CBSHM_CENTRAL_ADAPTERS_CURRENT_H +#define CBSHM_CENTRAL_ADAPTERS_CURRENT_H #include +#include namespace cbshm { @@ -22,4 +24,4 @@ namespace central = cbshm::central_v4_2; } // namespace cbshm -#endif // CBSHMEM_CENTRAL_TYPES_CURRENT_H +#endif // CBSHMEM_CENTRAL_ADAPTERS_CURRENT_H diff --git a/src/cbshm/include/cbshm/central_types/adapters.h b/src/cbshm/include/cbshm/central_types/adapters.h deleted file mode 100644 index 6922ef64..00000000 --- a/src/cbshm/include/cbshm/central_types/adapters.h +++ /dev/null @@ -1,850 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file adapters.h -/// @author Caden Shmookler -/// @date 2026-05-22 -/// -/// @brief Adapters for Central-compatible shared memory access -/// -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#ifndef CBSHM_CENTRAL_TYPES_ADAPTERS_H -#define CBSHM_CENTRAL_TYPES_ADAPTERS_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace cbshm { - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Base-class adapter that provides information used to fetch pointers to Central's shared memory -/// -class CentralBootstrapAdapterBase { -public: - // Buffer sizes - virtual size_t getConfigBufferSize() const = 0; - virtual size_t getReceiveBufferSize() const = 0; - virtual size_t getTransmitBufferSize() const = 0; - virtual size_t getTransmitBufferLocalSize() const = 0; - virtual size_t getStatusBufferSize() const = 0; - virtual size_t getSpikeBufferSize() const = 0; - virtual size_t getReceiveBufferLen() const = 0; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Base-class adapter for Central-compatible shared memory access -/// -class CentralAdapterBase { -protected: - template - static void copyArr(T(&lhs)[lhs_n], const T(&rhs)[rhs_n]) { - if (lhs_n <= rhs_n) { - std::memcpy(lhs, rhs, lhs_n * sizeof(T)); - } else { - std::memcpy(lhs, rhs, rhs_n * sizeof(T)); - std::memset(lhs + rhs_n, 0, (lhs_n - rhs_n) * sizeof(T)); - } - } - - template - static void copyArr(LHS_T(&lhs)[lhs_n], const RHS_T(&rhs)[rhs_n], const A* adapter, void(A::*translation_func)(LHS_T&, const RHS_T&) const) { - if (lhs_n <= rhs_n) { - for (size_t i = 0; i < lhs_n; ++i) { - (adapter->*translation_func)(lhs[i], rhs[i]); - } - } else { - for (size_t i = 0; i < rhs_n; ++i) { - (adapter->*translation_func)(lhs[i], rhs[i]); - } - std::memset(lhs + rhs_n, 0, (lhs_n - rhs_n) * sizeof(LHS_T)); - } - } - - template - static void copyArr2D(T(&lhs)[lhs_ny][lhs_nx], const T(&rhs)[rhs_ny][rhs_nx]) { - if (lhs_ny <= rhs_ny) { - if (lhs_nx == rhs_nx) { - std::memcpy(lhs, rhs, (lhs_ny * lhs_nx) * sizeof(T)); - } else { - for (size_t i = 0; i < lhs_ny; ++i) { - copyArr(lhs[i], rhs[i]); - } - } - } else { - if (lhs_nx == rhs_nx) { - std::memcpy(lhs, rhs, (rhs_ny * rhs_nx) * sizeof(T)); - } else { - for (size_t i = 0; i < rhs_ny; ++i) { - copyArr(lhs[i], rhs[i]); - } - } - std::memset(lhs + rhs_ny, 0, ((lhs_ny - rhs_ny) * lhs_nx) * sizeof(T)); - } - } - - template - static const void copyArr2D(LHS_T(&lhs)[lhs_ny][lhs_nx], const RHS_T(&rhs)[rhs_ny][rhs_nx], const A* adapter, void(A::*translation_func)(LHS_T&, const RHS_T&) const) { - if (lhs_ny <= rhs_ny) { - for (size_t i = 0; i < lhs_ny; ++i) { - copyArr(lhs[i], rhs[i], adapter, translation_func); - } - } else { - for (size_t i = 0; i < rhs_ny; ++i) { - copyArr(lhs[i], rhs[i], adapter, translation_func); - } - std::memset(lhs + rhs_ny, 0, ((lhs_ny - rhs_ny) * lhs_nx) * sizeof(LHS_T)); - } - } - -public: - virtual ~CentralAdapterBase() = default; - - // Max instrument count - virtual uint32_t getMaxProcs() const = 0; - - /////////////////////////////////////////////////////////////////////////////////////////////// - // DANGER !!! - // These methods are brittle and serve as a workaround for the ShmemSession - // implementation requiring direct pointer access to the receive and transmit buffers. - - // Receive buffer access - virtual uint32_t& getRecReceived() = 0; - virtual uint64_t getRecLasttime() = 0; - virtual void setRecLasttime(uint64_t lasttime) = 0; - virtual uint32_t& getRecHeadwrapPtr() = 0; - virtual uint32_t& getRecHeadindexPtr() = 0; - virtual uint32_t* getRecBufferPtr() = 0; - - // Transmit buffer access - virtual uint32_t& getXmtTransmittedPtr() = 0; - virtual uint32_t& getXmtHeadindexPtr() = 0; - virtual uint32_t& getXmtTailindexPtr() = 0; - virtual uint32_t& getXmtLastValidIndexPtr() = 0; - virtual uint32_t& getXmtBufferlenPtr() = 0; - virtual uint32_t* getXmtBufferPtr() = 0; - - virtual uint32_t& getLocalXmtTransmittedPtr() = 0; - virtual uint32_t& getLocalXmtHeadindexPtr() = 0; - virtual uint32_t& getLocalXmtTailindexPtr() = 0; - virtual uint32_t& getLocalXmtLastValidIndexPtr() = 0; - virtual uint32_t& getLocalXmtBufferlenPtr() = 0; - virtual uint32_t* getLocalXmtBufferPtr() = 0; - - /////////////////////////////////////////////////////////////////////////////////////////////// - - /// Config read operations - virtual Result getProcInfo(::cbPKT_PROCINFO& buf) const = 0; - virtual Result getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const = 0; - virtual Result getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const = 0; - virtual Result getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const = 0; - virtual Result getSysInfo(::cbPKT_SYSINFO& buf) const = 0; - virtual Result getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const = 0; - virtual Result getConfigBuffer(NativeConfigBuffer& buf) const = 0; - virtual Result getPcStatus(NativePCStatus& buf) const = 0; - virtual Result getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const = 0; - - /// Config write operations - virtual Result setProcInfo(const ::cbPKT_PROCINFO& info) = 0; - virtual Result setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) = 0; - virtual Result setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) = 0; - virtual Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) = 0; - virtual Result setSysInfo(const ::cbPKT_SYSINFO& info) = 0; - virtual Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) = 0; - virtual Result setNspStatus(const NativeNSPStatus& status) const = 0; - virtual Result setGeminiSystem(bool is_gemini) const = 0; -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace central_v4_2 { - -/// -/// @brief Adapter that provides information for fetching pointers to Central's shared memory -/// -class BootstrapAdapter : public CentralBootstrapAdapterBase { -public: - // Buffer sizes - size_t getConfigBufferSize() const override; - size_t getReceiveBufferSize() const override; - size_t getTransmitBufferSize() const override; - size_t getTransmitBufferLocalSize() const override; - size_t getStatusBufferSize() const override; - size_t getSpikeBufferSize() const override; - size_t getReceiveBufferLen() const override; -}; - -/// -/// @brief Adapter for Central-compatible shared memory access -/// -class Adapter : public CentralAdapterBase { -private: - uint8_t instrument_idx; - cbCFGBUFF* cfg; - cbRECBUFF* rec; - cbXMTBUFF* xmt; - cbXMTBUFFLOCAL* xmt_local; - cbPcStatus* status; - cbSPKBUFF* spike; - - void fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const; - void fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const; - void fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const; - void fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const; - void fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const; - void fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const; - void fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const; - void fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const; - void fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const; - void fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const; - void fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const; - void fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const; - void fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const; - void fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const; - void fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const; - void fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const; - void fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const; - void fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const; - void fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const; - void fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const; - void fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const; - void fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const; - void fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const; - void fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const; - void fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const; - void fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const; - void fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const; - void fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const; - void fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const; - void fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const; - void fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const; - void fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const; - void fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const; - void fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const; - void fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const; - void fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const; - void fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const; - void fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const; - void fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const; - void fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const; - - void toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const; - void toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const; - void toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const; - void toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const; - void toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const; - void toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const; - void toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const; - void toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const; - void toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const; - void toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const; - void toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const; - void toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const; - void toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const; - void toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const; - void toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const; - void toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const; - void toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const; - void toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; - void toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const; - void toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const; - void toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const; - void toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const; - void toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const; - void toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const; - void toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const; - void toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const; - void toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const; - void toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const; - void toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const; - void toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const; - void toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const; - void toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const; - void toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const; - void toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const; - void toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const; - void toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const; - -public: - Adapter( - uint8_t instrument_idx, - void* cfg_ptr, - void* rec_ptr, - void* xmt_ptr, - void* xmt_local_ptr, - void* status_ptr, - void* spike_ptr - ); - ~Adapter() = default; - - // Max instrument count - uint32_t getMaxProcs() const override; - - // Receive buffer access - uint32_t& getRecReceived() override; - uint64_t getRecLasttime() override; - void setRecLasttime(uint64_t lasttime) override; - uint32_t& getRecHeadwrapPtr() override; - uint32_t& getRecHeadindexPtr() override; - uint32_t* getRecBufferPtr() override; - - // Transmit buffer access - uint32_t& getXmtTransmittedPtr() override; - uint32_t& getXmtHeadindexPtr() override; - uint32_t& getXmtTailindexPtr() override; - uint32_t& getXmtLastValidIndexPtr() override; - uint32_t& getXmtBufferlenPtr() override; - uint32_t* getXmtBufferPtr() override; - - uint32_t& getLocalXmtTransmittedPtr() override; - uint32_t& getLocalXmtHeadindexPtr() override; - uint32_t& getLocalXmtTailindexPtr() override; - uint32_t& getLocalXmtLastValidIndexPtr() override; - uint32_t& getLocalXmtBufferlenPtr() override; - uint32_t* getLocalXmtBufferPtr() override; - - /// Config read operations - Result getProcInfo(::cbPKT_PROCINFO& buf) const override; - Result getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const override; - Result getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const override; - Result getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const override; - Result getSysInfo(::cbPKT_SYSINFO& buf) const override; - Result getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const override; - Result getConfigBuffer(NativeConfigBuffer& buf) const override; - Result getPcStatus(NativePCStatus& buf) const override; - Result getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const override; - - /// Config write operations - Result setProcInfo(const ::cbPKT_PROCINFO& info) override; - Result setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; - Result setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; - Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; - Result setSysInfo(const ::cbPKT_SYSINFO& info) override; - Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; - Result setNspStatus(const NativeNSPStatus& status) const override; - Result setGeminiSystem(bool is_gemini) const override; -}; - -} // namespace central_v4_2 - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace central_v4_1 { - -/// -/// @brief Adapter that provides information for fetching pointers to Central's shared memory -/// -class BootstrapAdapter : public CentralBootstrapAdapterBase { -public: - // Buffer sizes - size_t getConfigBufferSize() const override; - size_t getReceiveBufferSize() const override; - size_t getTransmitBufferSize() const override; - size_t getTransmitBufferLocalSize() const override; - size_t getStatusBufferSize() const override; - size_t getSpikeBufferSize() const override; - size_t getReceiveBufferLen() const override; -}; - -/// -/// @brief Adapter for Central-compatible shared memory access -/// -class Adapter : public CentralAdapterBase { -private: - uint8_t instrument_idx; - cbCFGBUFF* cfg; - cbRECBUFF* rec; - cbXMTBUFF* xmt; - cbXMTBUFFLOCAL* xmt_local; - cbPcStatus* status; - cbSPKBUFF* spike; - - void fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const; - void fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const; - void fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const; - void fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const; - void fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const; - void fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const; - void fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const; - void fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const; - void fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const; - void fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const; - void fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const; - void fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const; - void fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const; - void fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const; - void fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const; - void fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const; - void fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const; - void fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const; - void fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const; - void fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const; - void fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const; - void fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const; - void fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const; - void fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const; - void fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const; - void fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const; - void fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const; - void fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const; - void fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const; - void fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const; - void fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const; - void fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const; - void fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const; - void fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const; - void fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const; - void fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const; - void fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const; - void fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const; - void fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const; - void fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const; - - void toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const; - void toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const; - void toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const; - void toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const; - void toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const; - void toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const; - void toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const; - void toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const; - void toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const; - void toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const; - void toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const; - void toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const; - void toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const; - void toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const; - void toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const; - void toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const; - void toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const; - void toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; - void toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const; - void toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const; - void toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const; - void toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const; - void toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const; - void toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const; - void toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const; - void toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const; - void toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const; - void toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const; - void toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const; - void toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const; - void toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const; - void toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const; - void toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const; - void toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const; - void toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const; - void toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const; - -public: - Adapter( - uint8_t instrument_idx, - void* cfg_ptr, - void* rec_ptr, - void* xmt_ptr, - void* xmt_local_ptr, - void* status_ptr, - void* spike_ptr - ); - ~Adapter() = default; - - // Max instrument count - uint32_t getMaxProcs() const override; - - // Receive buffer access - uint32_t& getRecReceived() override; - uint64_t getRecLasttime() override; - void setRecLasttime(uint64_t lasttime) override; - uint32_t& getRecHeadwrapPtr() override; - uint32_t& getRecHeadindexPtr() override; - uint32_t* getRecBufferPtr() override; - - // Transmit buffer access - uint32_t& getXmtTransmittedPtr() override; - uint32_t& getXmtHeadindexPtr() override; - uint32_t& getXmtTailindexPtr() override; - uint32_t& getXmtLastValidIndexPtr() override; - uint32_t& getXmtBufferlenPtr() override; - uint32_t* getXmtBufferPtr() override; - - uint32_t& getLocalXmtTransmittedPtr() override; - uint32_t& getLocalXmtHeadindexPtr() override; - uint32_t& getLocalXmtTailindexPtr() override; - uint32_t& getLocalXmtLastValidIndexPtr() override; - uint32_t& getLocalXmtBufferlenPtr() override; - uint32_t* getLocalXmtBufferPtr() override; - - /// Config read operations - Result getProcInfo(::cbPKT_PROCINFO& buf) const override; - Result getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const override; - Result getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const override; - Result getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const override; - Result getSysInfo(::cbPKT_SYSINFO& buf) const override; - Result getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const override; - Result getConfigBuffer(NativeConfigBuffer& buf) const override; - Result getPcStatus(NativePCStatus& buf) const override; - Result getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const override; - - /// Config write operations - Result setProcInfo(const ::cbPKT_PROCINFO& info) override; - Result setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; - Result setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; - Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; - Result setSysInfo(const ::cbPKT_SYSINFO& info) override; - Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; - Result setNspStatus(const NativeNSPStatus& status) const override; - Result setGeminiSystem(bool is_gemini) const override; -}; - -} // namespace central_v4_1 - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace central_v4_0 { - -/// -/// @brief Adapter that provides information for fetching pointers to Central's shared memory -/// -class BootstrapAdapter : public CentralBootstrapAdapterBase { -public: - // Buffer sizes - size_t getConfigBufferSize() const override; - size_t getReceiveBufferSize() const override; - size_t getTransmitBufferSize() const override; - size_t getTransmitBufferLocalSize() const override; - size_t getStatusBufferSize() const override; - size_t getSpikeBufferSize() const override; - size_t getReceiveBufferLen() const override; -}; - -/// -/// @brief Adapter for Central-compatible shared memory access -/// -class Adapter : public CentralAdapterBase { -private: - uint8_t instrument_idx; - cbCFGBUFF* cfg; - cbRECBUFF* rec; - cbXMTBUFF* xmt; - cbXMTBUFFLOCAL* xmt_local; - cbPcStatus* status; - cbSPKBUFF* spike; - - void fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const; - void fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const; - void fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const; - void fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const; - void fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const; - void fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const; - void fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const; - void fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const; - void fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const; - void fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const; - void fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const; - void fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const; - void fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const; - void fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const; - void fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const; - void fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const; - void fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const; - void fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const; - void fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const; - void fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const; - void fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const; - void fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const; - void fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const; - void fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const; - void fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const; - void fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const; - void fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const; - void fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const; - void fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const; - void fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const; - void fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const; - void fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const; - void fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const; - void fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const; - void fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const; - void fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const; - void fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const; - void fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const; - void fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const; - void fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const; - - void toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const; - void toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const; - void toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const; - void toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const; - void toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const; - void toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const; - void toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const; - void toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const; - void toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const; - void toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const; - void toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const; - void toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const; - void toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const; - void toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const; - void toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const; - void toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const; - void toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const; - void toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; - void toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const; - void toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const; - void toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const; - void toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const; - void toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const; - void toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const; - void toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const; - void toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const; - void toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const; - void toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const; - void toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const; - void toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const; - void toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const; - void toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const; - void toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const; - void toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const; - void toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const; - void toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const; - -public: - Adapter( - uint8_t instrument_idx, - void* cfg_ptr, - void* rec_ptr, - void* xmt_ptr, - void* xmt_local_ptr, - void* status_ptr, - void* spike_ptr - ); - ~Adapter() = default; - - // Max instrument count - uint32_t getMaxProcs() const override; - - // Receive buffer access - uint32_t& getRecReceived() override; - uint64_t getRecLasttime() override; - void setRecLasttime(uint64_t lasttime) override; - uint32_t& getRecHeadwrapPtr() override; - uint32_t& getRecHeadindexPtr() override; - uint32_t* getRecBufferPtr() override; - - // Transmit buffer access - uint32_t& getXmtTransmittedPtr() override; - uint32_t& getXmtHeadindexPtr() override; - uint32_t& getXmtTailindexPtr() override; - uint32_t& getXmtLastValidIndexPtr() override; - uint32_t& getXmtBufferlenPtr() override; - uint32_t* getXmtBufferPtr() override; - - uint32_t& getLocalXmtTransmittedPtr() override; - uint32_t& getLocalXmtHeadindexPtr() override; - uint32_t& getLocalXmtTailindexPtr() override; - uint32_t& getLocalXmtLastValidIndexPtr() override; - uint32_t& getLocalXmtBufferlenPtr() override; - uint32_t* getLocalXmtBufferPtr() override; - - /// Config read operations - Result getProcInfo(::cbPKT_PROCINFO& buf) const override; - Result getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const override; - Result getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const override; - Result getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const override; - Result getSysInfo(::cbPKT_SYSINFO& buf) const override; - Result getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const override; - Result getConfigBuffer(NativeConfigBuffer& buf) const override; - Result getPcStatus(NativePCStatus& buf) const override; - Result getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const override; - - /// Config write operations - Result setProcInfo(const ::cbPKT_PROCINFO& info) override; - Result setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; - Result setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; - Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; - Result setSysInfo(const ::cbPKT_SYSINFO& info) override; - Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; - Result setNspStatus(const NativeNSPStatus& status) const override; - Result setGeminiSystem(bool is_gemini) const override; -}; - -} // namespace central_v4_0 - -/////////////////////////////////////////////////////////////////////////////////////////////////// -namespace central_v3_11 { - -/// -/// @brief Adapter that provides information for fetching pointers to Central's shared memory -/// -class BootstrapAdapter : public CentralBootstrapAdapterBase { -public: - // Buffer sizes - size_t getConfigBufferSize() const override; - size_t getReceiveBufferSize() const override; - size_t getTransmitBufferSize() const override; - size_t getTransmitBufferLocalSize() const override; - size_t getStatusBufferSize() const override; - size_t getSpikeBufferSize() const override; - size_t getReceiveBufferLen() const override; -}; - -/// -/// @brief Adapter for Central-compatible shared memory access -/// -class Adapter : public CentralAdapterBase { -private: - uint8_t instrument_idx; - cbCFGBUFF* cfg; - cbRECBUFF* rec; - cbXMTBUFF* xmt; - cbXMTBUFFLOCAL* xmt_local; - cbPcStatus* status; - cbSPKBUFF* spike; - - void fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const; - void fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const; - void fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const; - void fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const; - void fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const; - void fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const; - void fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const; - void fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const; - void fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const; - void fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const; - void fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const; - void fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const; - void fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const; - void fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const; - void fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const; - void fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const; - void fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const; - void fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const; - void fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const; - void fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const; - void fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const; - void fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const; - void fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const; - void fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const; - void fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const; - void fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const; - void fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const; - void fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const; - void fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const; - void fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const; - void fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const; - void fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const; - void fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const; - void fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const; - void fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const; - void fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const; - void fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const; - void fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const; - void fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const; - void fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const; - - void toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const; - void toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const; - void toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const; - void toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const; - void toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const; - void toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const; - void toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const; - void toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const; - void toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const; - void toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const; - void toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const; - void toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const; - void toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const; - void toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const; - void toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const; - void toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const; - void toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const; - void toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; - void toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const; - void toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const; - void toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const; - void toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const; - void toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const; - void toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const; - void toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const; - void toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const; - void toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const; - void toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const; - void toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const; - void toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const; - void toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const; - void toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const; - void toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const; - void toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const; - void toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const; - void toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const; - -public: - Adapter( - uint8_t instrument_idx, - void* cfg_ptr, - void* rec_ptr, - void* xmt_ptr, - void* xmt_local_ptr, - void* status_ptr, - void* spike_ptr - ); - ~Adapter() = default; - - // Max instrument count - uint32_t getMaxProcs() const override; - - // Receive buffer access - uint32_t& getRecReceived() override; - uint64_t getRecLasttime() override; - void setRecLasttime(uint64_t lasttime) override; - uint32_t& getRecHeadwrapPtr() override; - uint32_t& getRecHeadindexPtr() override; - uint32_t* getRecBufferPtr() override; - - // Transmit buffer access - uint32_t& getXmtTransmittedPtr() override; - uint32_t& getXmtHeadindexPtr() override; - uint32_t& getXmtTailindexPtr() override; - uint32_t& getXmtLastValidIndexPtr() override; - uint32_t& getXmtBufferlenPtr() override; - uint32_t* getXmtBufferPtr() override; - - uint32_t& getLocalXmtTransmittedPtr() override; - uint32_t& getLocalXmtHeadindexPtr() override; - uint32_t& getLocalXmtTailindexPtr() override; - uint32_t& getLocalXmtLastValidIndexPtr() override; - uint32_t& getLocalXmtBufferlenPtr() override; - uint32_t* getLocalXmtBufferPtr() override; - - /// Config read operations - Result getProcInfo(::cbPKT_PROCINFO& buf) const override; - Result getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const override; - Result getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const override; - Result getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const override; - Result getSysInfo(::cbPKT_SYSINFO& buf) const override; - Result getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const override; - Result getConfigBuffer(NativeConfigBuffer& buf) const override; - Result getPcStatus(NativePCStatus& buf) const override; - Result getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const override; - - /// Config write operations - Result setProcInfo(const ::cbPKT_PROCINFO& info) override; - Result setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; - Result setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; - Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; - Result setSysInfo(const ::cbPKT_SYSINFO& info) override; - Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; - Result setNspStatus(const NativeNSPStatus& status) const override; - Result setGeminiSystem(bool is_gemini) const override; -}; - -} // namespace central_v3_11 -/////////////////////////////////////////////////////////////////////////////////////////////////// - -} // namespace cbshm - -#endif // CBSHM_CENTRAL_TYPES_ADAPTERS_H diff --git a/src/cbshm/include/cbshm/shmem_session.h b/src/cbshm/include/cbshm/shmem_session.h index 5ae42cd2..5c60cc52 100644 --- a/src/cbshm/include/cbshm/shmem_session.h +++ b/src/cbshm/include/cbshm/shmem_session.h @@ -20,7 +20,7 @@ #define CBSHM_SHMEM_SESSION_H // Include Central-compatible types which bring in protocol definitions -#include +#include #include #include #include diff --git a/src/cbshm/src/central_adapters/v3_11.cpp b/src/cbshm/src/central_adapters/v3_11.cpp index de8758e9..cf363053 100644 --- a/src/cbshm/src/central_adapters/v3_11.cpp +++ b/src/cbshm/src/central_adapters/v3_11.cpp @@ -7,7 +7,7 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#include +#include #include namespace cbshm { @@ -991,118 +991,118 @@ uint32_t* Adapter::getLocalXmtBufferPtr() { return xmt->buffer; } -Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { +cbutil::Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { fromLegacy(buf, cfg->procinfo[instrument_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const { +cbutil::Result Adapter::getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const { uint32_t bank_idx = bank_num - 1; if (bank_idx >= std::size(cfg->bankinfo[0])) { - return Result::error("Bank number out of range"); + return cbutil::Result::error("Bank number out of range"); } fromLegacy(buf, cfg->bankinfo[instrument_idx][bank_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const { +cbutil::Result Adapter::getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const { uint32_t filter_idx = filter_num - 1; if (filter_idx >= std::size(cfg->filtinfo[0])) { - return Result::error("Filter number out of range"); + return cbutil::Result::error("Filter number out of range"); } fromLegacy(buf, cfg->filtinfo[instrument_idx][filter_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const { +cbutil::Result Adapter::getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const { if (channel_idx >= std::size(cfg->chaninfo)) { - return Result::error("Channel number out of range"); + return cbutil::Result::error("Channel number out of range"); } fromLegacy(buf, cfg->chaninfo[channel_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getSysInfo(::cbPKT_SYSINFO& buf) const { +cbutil::Result Adapter::getSysInfo(::cbPKT_SYSINFO& buf) const { fromLegacy(buf, cfg->sysinfo); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const { +cbutil::Result Adapter::getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const { if (group_idx >= std::size(cfg->groupinfo[0])) { - return Result::error("Group index out of range"); + return cbutil::Result::error("Group index out of range"); } fromLegacy(buf, cfg->groupinfo[instrument_idx][group_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getConfigBuffer(NativeConfigBuffer& buf) const { +cbutil::Result Adapter::getConfigBuffer(NativeConfigBuffer& buf) const { fromLegacy(buf, *cfg); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getPcStatus(NativePCStatus& buf) const { +cbutil::Result Adapter::getPcStatus(NativePCStatus& buf) const { fromLegacy(buf, *status); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const { +cbutil::Result Adapter::getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const { if (channel_idx >= std::size(spike->cache)) { - return Result::error("Channel index out of range"); + return cbutil::Result::error("Channel index out of range"); } fromLegacy(buf, spike->cache[channel_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { +cbutil::Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { toLegacy(cfg->procinfo[instrument_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) { +cbutil::Result Adapter::setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) { uint32_t bank_idx = bank_num - 1; if (bank_idx >= std::size(cfg->bankinfo[0])) { - return Result::error("Bank number out of range"); + return cbutil::Result::error("Bank number out of range"); } toLegacy(cfg->bankinfo[instrument_idx][bank_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) { +cbutil::Result Adapter::setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) { uint32_t filter_idx = filter_num - 1; if (filter_idx >= std::size(cfg->filtinfo[0])) { - return Result::error("Filter number out of range"); + return cbutil::Result::error("Filter number out of range"); } toLegacy(cfg->filtinfo[instrument_idx][filter_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) { +cbutil::Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) { if (channel_idx >= std::size(cfg->chaninfo)) { - return Result::error("Channel number out of range"); + return cbutil::Result::error("Channel number out of range"); } toLegacy(cfg->chaninfo[channel_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { +cbutil::Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { toLegacy(cfg->sysinfo, info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { +cbutil::Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { if (group_idx >= std::size(cfg->groupinfo[0])) { - return Result::error("Group index out of range"); + return cbutil::Result::error("Group index out of range"); } toLegacy(cfg->groupinfo[instrument_idx][group_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setNspStatus(const NativeNSPStatus& status) const { - return Result::error("Central v3.11 does not have fields for NSP status"); +cbutil::Result Adapter::setNspStatus(const NativeNSPStatus& status) const { + return cbutil::Result::error("Central v3.11 does not have fields for NSP status"); } -Result Adapter::setGeminiSystem(bool is_gemini) const { - return Result::error("Central v3.11 does not recognize Gemini systems"); +cbutil::Result Adapter::setGeminiSystem(bool is_gemini) const { + return cbutil::Result::error("Central v3.11 does not recognize Gemini systems"); } } // namespace central_v3_11 diff --git a/src/cbshm/src/central_adapters/v4_0.cpp b/src/cbshm/src/central_adapters/v4_0.cpp index 67605a1e..23bb942b 100644 --- a/src/cbshm/src/central_adapters/v4_0.cpp +++ b/src/cbshm/src/central_adapters/v4_0.cpp @@ -7,7 +7,7 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#include +#include #include namespace cbshm { @@ -992,120 +992,120 @@ uint32_t* Adapter::getLocalXmtBufferPtr() { return xmt->buffer; } -Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { +cbutil::Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { fromLegacy(buf, cfg->procinfo[instrument_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const { +cbutil::Result Adapter::getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const { uint32_t bank_idx = bank_num - 1; if (bank_idx >= std::size(cfg->bankinfo[0])) { - return Result::error("Bank number out of range"); + return cbutil::Result::error("Bank number out of range"); } fromLegacy(buf, cfg->bankinfo[instrument_idx][bank_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const { +cbutil::Result Adapter::getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const { uint32_t filter_idx = filter_num - 1; if (filter_idx >= std::size(cfg->filtinfo[0])) { - return Result::error("Filter number out of range"); + return cbutil::Result::error("Filter number out of range"); } fromLegacy(buf, cfg->filtinfo[instrument_idx][filter_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const { +cbutil::Result Adapter::getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const { if (channel_idx >= std::size(cfg->chaninfo)) { - return Result::error("Channel number out of range"); + return cbutil::Result::error("Channel number out of range"); } fromLegacy(buf, cfg->chaninfo[channel_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getSysInfo(::cbPKT_SYSINFO& buf) const { +cbutil::Result Adapter::getSysInfo(::cbPKT_SYSINFO& buf) const { fromLegacy(buf, cfg->sysinfo); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const { +cbutil::Result Adapter::getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const { if (group_idx >= std::size(cfg->groupinfo[0])) { - return Result::error("Group index out of range"); + return cbutil::Result::error("Group index out of range"); } fromLegacy(buf, cfg->groupinfo[instrument_idx][group_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getConfigBuffer(NativeConfigBuffer& buf) const { +cbutil::Result Adapter::getConfigBuffer(NativeConfigBuffer& buf) const { fromLegacy(buf, *cfg); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getPcStatus(NativePCStatus& buf) const { +cbutil::Result Adapter::getPcStatus(NativePCStatus& buf) const { fromLegacy(buf, *status); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const { +cbutil::Result Adapter::getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const { if (channel_idx >= std::size(spike->cache)) { - return Result::error("Channel index out of range"); + return cbutil::Result::error("Channel index out of range"); } fromLegacy(buf, spike->cache[channel_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { +cbutil::Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { toLegacy(cfg->procinfo[instrument_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) { +cbutil::Result Adapter::setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) { uint32_t bank_idx = bank_num - 1; if (bank_idx >= std::size(cfg->bankinfo[0])) { - return Result::error("Bank number out of range"); + return cbutil::Result::error("Bank number out of range"); } toLegacy(cfg->bankinfo[instrument_idx][bank_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) { +cbutil::Result Adapter::setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) { uint32_t filter_idx = filter_num - 1; if (filter_idx >= std::size(cfg->filtinfo[0])) { - return Result::error("Filter number out of range"); + return cbutil::Result::error("Filter number out of range"); } toLegacy(cfg->filtinfo[instrument_idx][filter_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) { +cbutil::Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) { if (channel_idx >= std::size(cfg->chaninfo)) { - return Result::error("Channel number out of range"); + return cbutil::Result::error("Channel number out of range"); } toLegacy(cfg->chaninfo[channel_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { +cbutil::Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { toLegacy(cfg->sysinfo, info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { +cbutil::Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { if (group_idx >= std::size(cfg->groupinfo[0])) { - return Result::error("Group index out of range"); + return cbutil::Result::error("Group index out of range"); } toLegacy(cfg->groupinfo[instrument_idx][group_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setNspStatus(const NativeNSPStatus& status) const { +cbutil::Result Adapter::setNspStatus(const NativeNSPStatus& status) const { toLegacy(this->status->m_nNspStatus[instrument_idx], status); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setGeminiSystem(bool is_gemini) const { +cbutil::Result Adapter::setGeminiSystem(bool is_gemini) const { status->m_nGeminiSystem = is_gemini ? 1 : 0; - return Result::ok(); + return cbutil::Result::ok(); } } // namespace central_v4_0 diff --git a/src/cbshm/src/central_adapters/v4_1.cpp b/src/cbshm/src/central_adapters/v4_1.cpp index 015934d8..1c82bfbc 100644 --- a/src/cbshm/src/central_adapters/v4_1.cpp +++ b/src/cbshm/src/central_adapters/v4_1.cpp @@ -7,7 +7,7 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#include +#include #include namespace cbshm { @@ -996,120 +996,120 @@ uint32_t* Adapter::getLocalXmtBufferPtr() { return xmt->buffer; } -Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { +cbutil::Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { fromLegacy(buf, cfg->procinfo[instrument_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const { +cbutil::Result Adapter::getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const { uint32_t bank_idx = bank_num - 1; if (bank_idx >= std::size(cfg->bankinfo[0])) { - return Result::error("Bank number out of range"); + return cbutil::Result::error("Bank number out of range"); } fromLegacy(buf, cfg->bankinfo[instrument_idx][bank_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const { +cbutil::Result Adapter::getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const { uint32_t filter_idx = filter_num - 1; if (filter_idx >= std::size(cfg->filtinfo[0])) { - return Result::error("Filter number out of range"); + return cbutil::Result::error("Filter number out of range"); } fromLegacy(buf, cfg->filtinfo[instrument_idx][filter_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const { +cbutil::Result Adapter::getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const { if (channel_idx >= std::size(cfg->chaninfo)) { - return Result::error("Channel number out of range"); + return cbutil::Result::error("Channel number out of range"); } fromLegacy(buf, cfg->chaninfo[channel_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getSysInfo(::cbPKT_SYSINFO& buf) const { +cbutil::Result Adapter::getSysInfo(::cbPKT_SYSINFO& buf) const { fromLegacy(buf, cfg->sysinfo); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const { +cbutil::Result Adapter::getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const { if (group_idx >= std::size(cfg->groupinfo[0])) { - return Result::error("Group index out of range"); + return cbutil::Result::error("Group index out of range"); } fromLegacy(buf, cfg->groupinfo[instrument_idx][group_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getConfigBuffer(NativeConfigBuffer& buf) const { +cbutil::Result Adapter::getConfigBuffer(NativeConfigBuffer& buf) const { fromLegacy(buf, *cfg); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getPcStatus(NativePCStatus& buf) const { +cbutil::Result Adapter::getPcStatus(NativePCStatus& buf) const { fromLegacy(buf, *status); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const { +cbutil::Result Adapter::getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const { if (channel_idx >= std::size(spike->cache)) { - return Result::error("Channel index out of range"); + return cbutil::Result::error("Channel index out of range"); } fromLegacy(buf, spike->cache[channel_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { +cbutil::Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { toLegacy(cfg->procinfo[instrument_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) { +cbutil::Result Adapter::setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) { uint32_t bank_idx = bank_num - 1; if (bank_idx >= std::size(cfg->bankinfo[0])) { - return Result::error("Bank number out of range"); + return cbutil::Result::error("Bank number out of range"); } toLegacy(cfg->bankinfo[instrument_idx][bank_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) { +cbutil::Result Adapter::setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) { uint32_t filter_idx = filter_num - 1; if (filter_idx >= std::size(cfg->filtinfo[0])) { - return Result::error("Filter number out of range"); + return cbutil::Result::error("Filter number out of range"); } toLegacy(cfg->filtinfo[instrument_idx][filter_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) { +cbutil::Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) { if (channel_idx >= std::size(cfg->chaninfo)) { - return Result::error("Channel number out of range"); + return cbutil::Result::error("Channel number out of range"); } toLegacy(cfg->chaninfo[channel_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { +cbutil::Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { toLegacy(cfg->sysinfo, info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { +cbutil::Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { if (group_idx >= std::size(cfg->groupinfo[0])) { - return Result::error("Group index out of range"); + return cbutil::Result::error("Group index out of range"); } toLegacy(cfg->groupinfo[instrument_idx][group_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setNspStatus(const NativeNSPStatus& status) const { +cbutil::Result Adapter::setNspStatus(const NativeNSPStatus& status) const { toLegacy(this->status->m_nNspStatus[instrument_idx], status); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setGeminiSystem(bool is_gemini) const { +cbutil::Result Adapter::setGeminiSystem(bool is_gemini) const { status->m_nGeminiSystem = is_gemini ? 1 : 0; - return Result::ok(); + return cbutil::Result::ok(); } } // namespace central_v4_1 diff --git a/src/cbshm/src/central_adapters/v4_2.cpp b/src/cbshm/src/central_adapters/v4_2.cpp index fa30af03..8049511c 100644 --- a/src/cbshm/src/central_adapters/v4_2.cpp +++ b/src/cbshm/src/central_adapters/v4_2.cpp @@ -7,7 +7,7 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#include +#include #include namespace cbshm { @@ -997,120 +997,120 @@ uint32_t* Adapter::getLocalXmtBufferPtr() { return xmt->buffer; } -Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { +cbutil::Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { fromLegacy(buf, cfg->procinfo[instrument_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const { +cbutil::Result Adapter::getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const { uint32_t bank_idx = bank_num - 1; if (bank_idx >= std::size(cfg->bankinfo[0])) { - return Result::error("Bank number out of range"); + return cbutil::Result::error("Bank number out of range"); } fromLegacy(buf, cfg->bankinfo[instrument_idx][bank_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const { +cbutil::Result Adapter::getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const { uint32_t filter_idx = filter_num - 1; if (filter_idx >= std::size(cfg->filtinfo[0])) { - return Result::error("Filter number out of range"); + return cbutil::Result::error("Filter number out of range"); } fromLegacy(buf, cfg->filtinfo[instrument_idx][filter_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const { +cbutil::Result Adapter::getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const { if (channel_idx >= std::size(cfg->chaninfo)) { - return Result::error("Channel number out of range"); + return cbutil::Result::error("Channel number out of range"); } fromLegacy(buf, cfg->chaninfo[channel_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getSysInfo(::cbPKT_SYSINFO& buf) const { +cbutil::Result Adapter::getSysInfo(::cbPKT_SYSINFO& buf) const { fromLegacy(buf, cfg->sysinfo); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const { +cbutil::Result Adapter::getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const { if (group_idx >= std::size(cfg->groupinfo[0])) { - return Result::error("Group index out of range"); + return cbutil::Result::error("Group index out of range"); } fromLegacy(buf, cfg->groupinfo[instrument_idx][group_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getConfigBuffer(NativeConfigBuffer& buf) const { +cbutil::Result Adapter::getConfigBuffer(NativeConfigBuffer& buf) const { fromLegacy(buf, *cfg); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getPcStatus(NativePCStatus& buf) const { +cbutil::Result Adapter::getPcStatus(NativePCStatus& buf) const { fromLegacy(buf, *status); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const { +cbutil::Result Adapter::getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const { if (channel_idx >= std::size(spike->cache)) { - return Result::error("Channel index out of range"); + return cbutil::Result::error("Channel index out of range"); } fromLegacy(buf, spike->cache[channel_idx]); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { +cbutil::Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { toLegacy(cfg->procinfo[instrument_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) { +cbutil::Result Adapter::setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) { uint32_t bank_idx = bank_num - 1; if (bank_idx >= std::size(cfg->bankinfo[0])) { - return Result::error("Bank number out of range"); + return cbutil::Result::error("Bank number out of range"); } toLegacy(cfg->bankinfo[instrument_idx][bank_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) { +cbutil::Result Adapter::setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) { uint32_t filter_idx = filter_num - 1; if (filter_idx >= std::size(cfg->filtinfo[0])) { - return Result::error("Filter number out of range"); + return cbutil::Result::error("Filter number out of range"); } toLegacy(cfg->filtinfo[instrument_idx][filter_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) { +cbutil::Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) { if (channel_idx >= std::size(cfg->chaninfo)) { - return Result::error("Channel number out of range"); + return cbutil::Result::error("Channel number out of range"); } toLegacy(cfg->chaninfo[channel_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { +cbutil::Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { toLegacy(cfg->sysinfo, info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { +cbutil::Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { if (group_idx >= std::size(cfg->groupinfo[0])) { - return Result::error("Group index out of range"); + return cbutil::Result::error("Group index out of range"); } toLegacy(cfg->groupinfo[instrument_idx][group_idx], info); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setNspStatus(const NativeNSPStatus& status) const { +cbutil::Result Adapter::setNspStatus(const NativeNSPStatus& status) const { toLegacy(this->status->m_nNspStatus[instrument_idx], status); - return Result::ok(); + return cbutil::Result::ok(); } -Result Adapter::setGeminiSystem(bool is_gemini) const { +cbutil::Result Adapter::setGeminiSystem(bool is_gemini) const { status->m_nGeminiSystem = is_gemini ? 1 : 0; - return Result::ok(); + return cbutil::Result::ok(); } } // namespace central_v4_2 diff --git a/src/cbshm/src/shmem_session.cpp b/src/cbshm/src/shmem_session.cpp index a88a5b09..9e9a4caa 100644 --- a/src/cbshm/src/shmem_session.cpp +++ b/src/cbshm/src/shmem_session.cpp @@ -33,8 +33,11 @@ #endif #include -#include -#include +#include +#include +#include +#include +#include #include #include #include From 6ba6f0e381e1458974da489f886b9c66d94232ea Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Tue, 23 Jun 2026 16:04:31 -0600 Subject: [PATCH 34/62] Add documentation for multi-version-central-compat Rename the proposal to distinquish it from the feature overview (README.md). Fix shared_memory_architecture.md to reflect the changes to the shared memory implementation. --- README.md | 2 +- docs/multi_version_central_compat/README.md | 189 ++++++++++++ .../proposal.md} | 8 +- docs/shared_memory_architecture.md | 280 +++++++----------- 4 files changed, 301 insertions(+), 178 deletions(-) create mode 100644 docs/multi_version_central_compat/README.md rename docs/{planning/multi_version_central_compat.md => multi_version_central_compat/proposal.md} (98%) diff --git a/README.md b/README.md index 4140ed35..dc96836e 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Modular library stack: - **STANDALONE** — CereLink owns the device connection and shared memory - **CLIENT** — Attach to another CereLink instance's shared memory -- **CENTRAL_COMPAT CLIENT** — Attach to Central's shared memory with on-the-fly protocol translation +- **CENTRAL CLIENT** — Attach to Central's shared memory with on-the-fly protocol translation ## Build diff --git a/docs/multi_version_central_compat/README.md b/docs/multi_version_central_compat/README.md new file mode 100644 index 00000000..6cd3bbaf --- /dev/null +++ b/docs/multi_version_central_compat/README.md @@ -0,0 +1,189 @@ +# Multi-Version Central Compatibility + +**Author**: Caden Shmookler +**Date**: 2026-06-16 + + +## Brief + +This document describes a compatibility layer within CereLink which enables cross-version compatibility with Central's shared memory. Previous versions of CereLink only supported the latest version of Central. This compatibility layer consists of an `Adapter` class which hides the implementation differences between protocol versions behind a common interface. + +Central has a 'protocol version' and an 'application version'. As of the writing of this document, the most recent protocol and application versions are 4.2 and 7.8.0 respectively. Shared memory compatibility is dependent on the protocol version. Protocols with different major version numbers are completely incompatible whereas protocols with different minor version numbers may be partially compatible. Different application versions do not break protocol compatibility unless the protocol version has also changed. + + +## Organization + +Each supported protocol version has a `BootstrapAdapter` and `Adapter`. The `BootstrapAdapter` class fetches the sizes of shared memory structs in order to instantiate an `Adapter` with raw pointers to each struct. Each adapter has a collection of Central structs which are translated to and from the native CereLink equivalents. These native equivalents (defined in cbproto and native_types.h) are the common language used by `ShmemSession` to perform operations on the shared memory buffers. + +The structure and sizes of types are defined in `src/cbshm/include/cbshm/central_types/*`. The translation behavior is defined in `src/cbshm/src/central_adapters/*`. Version headers in `src/cbshm/include/cbshm/central_adapters/*` should be nearly identical. + + +## Limitations + +This compatibility layer is limited to Central's configuration, status, and spike buffers. The receive and transmit buffers are handled by brittle logic spread throughout cbdev, cbproto, and cbshm. Replacing this brittle logic with another adapter class encapsulating all version-specific code would dramatically simplify the process of adding protocol versions. + + +## Add a Version + +This section provides instructions for adding support for a version of Central's shared memory. + +By default, new application versions of Central are assumed to use the latest protocol version. If Central's application version increments but it's protocol version remains the same, no action is required to enable compatibility. + +If a version of Central has a newer protocol version than what's currently supported, follow the [newer version](#add-a-newer-protocol-version) instructions below. + +If a version of Central has an older protocol version than what's currently supported, follow the [older version](#add-an-older-protocol-version) instructions below. + + +### Add a newer protocol version + +#### 1. Add the version to cbproto_protocol_version + +```bash +editor src/cbproto/include/cbproto/connection.h +``` + +`CBPROTO_PROTOCOL_CURRENT` now codes for the added version. Add a new value for the replaced version (e.g. `CBPROTO_PROTOCOL_420`). + +#### 2. Implement receive/transmit buffer operations + +Multiple files throughout cbdev, cbproto, and cbshm contain version-specific logic (pertaining to the receive and transmit buffers) that must be changed to include a case for the added version. + +> Note: This is a complex operation involving large portions of CereLink (depending on what was changed in the new protocol). See the [limitations](#limitations) section for an idea on how this process could be simplified in the future. + +#### 3. Duplicate version headers and implementation from an existing version + +Replace `` with the name of an existing version and `` with the name of the version that's being added. Duplicate an existing version that's similar in structure and behavior to the version that's being added. + +```bash +cp src/cbshm/include/cbshm/central_types/.h src/cbshm/include/cbshm/central_types/.h +cp src/cbshm/include/cbshm/central_adapters/.h src/cbshm/include/cbshm/central_adapters/.h +cp src/cbshm/src/central_adapters/.cpp src/cbshm/src/central_adapters/.cpp +``` + +#### 4. Name the added version + +Change all references to the existing version to the added version. + +```bash +editor src/cbshm/include/cbshm/central_adapters/.h +editor src/cbshm/include/cbshm/central_types/.h +editor src/cbshm/src/central_adapters/.cpp +``` + +#### 5. Rectify the types for the added version + +```bash +editor src/cbshm/include/cbshm/central_types/.h +``` + +If the added version contains changes to types or constants that are not already in the header, add them by copying directly from Central or cbproto. Verify your changes by diffing the existing version header with the added version header. + +#### 6. Rectify the translators and adapter for the added version + +```bash +editor src/cbshm/src/central_adapters/.cpp +``` + +Verify your changes by diffing the existing version header with the added version header. + +#### 7. Add the version to ShmemSession::Impl + +```bash +editor src/cbshm/src/shmem_session.cpp +``` + +Add `#include .h>` at the top of the file and append the adapter and bootstrap adapter to the corresponding switch statements in `ShmemSession::Impl::open`. Modify the switch statement at the bottom of `detectCompatProtocol` so corresponding application versions are mapped to the added protocol version. + +#### 8. Add the adapter implementation to CMakeLists.txt + +```bash +editor src/cbshm/CMakeLists.txt +``` + +Append `src/central_adapters/.cpp` to the `CBSHMEM_SOURCES` environment variable. + +#### 9. Update types in cbproto to match the added version + +The types in cbproto must match the most recent protocol version, `CBPROTO_PROTOCOL_CURRENT`. Changes to these types may cause downstream side effects elsewhere in CereLink, including but not limited to the `PacketTranslator` and `DeviceSession` classes. + +> Note: The cbproto types are used for direct communication with instruments instead of with Central. If there are differences in the protocol between these targets then they must be reflected in the code. + +> Note: This is a complex operation involving large portions of CereLink (depending on what was changed in the new protocol). See the [limitations](#limitations) section for an idea on how this process could be simplified in the future. + +#### 10. Rectify the translators and adapters for all older versions + +All translators and adapters use the cbproto types, so these methods must be fixed to translate to the added version instead. + + +### Add an older protocol version + +#### 1. Add the version to cbproto_protocol_version + +```bash +editor src/cbproto/include/cbproto/connection.h +``` + +Add a new value for the added version (e.g. `CBPROTO_PROTOCOL_309`). + +#### 2. Implement receive/transmit buffer operations + +Multiple files throughout cbdev, cbproto, and cbshm contain version-specific logic (pertaining to the receive and transmit buffers) that must be changed to include a case for the added version. + +> Note: This is a complex operation involving large portions of CereLink (depending on what was changed in the new protocol). See the [limitations](#limitations) section for an idea on how this process could be simplified in the future. + +#### 3. Duplicate version headers and implementation from an existing version + +Replace `` with the name of an existing version and `` with the name of the version that's being added. Duplicate an existing version that's similar in structure and behavior to the version that's being added. + +```bash +cp src/cbshm/include/cbshm/central_types/.h src/cbshm/include/cbshm/central_types/.h +cp src/cbshm/include/cbshm/central_adapters/.h src/cbshm/include/cbshm/central_adapters/.h +cp src/cbshm/src/central_adapters/.cpp src/cbshm/src/central_adapters/.cpp +``` + +#### 4. Name the added version + +Change all references to the existing version to the added version. + +```bash +editor src/cbshm/include/cbshm/central_adapters/.h +editor src/cbshm/include/cbshm/central_types/.h +editor src/cbshm/src/central_adapters/.cpp +``` + +#### 5. Rectify the types for the added version + +```bash +editor src/cbshm/include/cbshm/central_types/.h +``` + +If the added version contains changes to types or constants that are not already in the header, add them by copying directly from Central or cbproto. Verify your changes by diffing the existing version header with the added version header. + +#### 6. Rectify the translators and adapter for the added version + +```bash +editor src/cbshm/src/central_adapters/.cpp +``` + +Verify your changes by diffing the existing version header with the added version header. + +#### 7. Add the version to ShmemSession::Impl + +```bash +editor src/cbshm/src/shmem_session.cpp +``` + +Add `#include .h>` at the top of the file and append the adapter and bootstrap adapter to the corresponding switch statements in `ShmemSession::Impl::open`. Modify the switch statement at the bottom of `detectCompatProtocol` so corresponding application versions are mapped to the added protocol version. + +#### 8. Add the adapter implementation to CMakeLists.txt + +```bash +editor src/cbshm/CMakeLists.txt +``` + +Append `src/central_adapters/.cpp` to the `CBSHMEM_SOURCES` environment variable. + + +## Remove a protocol version + +Follow the instructions for adding a new version in reverse. To disable support for a specific version instead of outright removing it, replace the adapter construction in `ShmemSession::Impl::open` within `src/cbshm/src/shmem_session.cpp` with an error. diff --git a/docs/planning/multi_version_central_compat.md b/docs/multi_version_central_compat/proposal.md similarity index 98% rename from docs/planning/multi_version_central_compat.md rename to docs/multi_version_central_compat/proposal.md index 33145fe3..dc94606d 100644 --- a/docs/planning/multi_version_central_compat.md +++ b/docs/multi_version_central_compat/proposal.md @@ -37,9 +37,9 @@ a stable interface, and keeps the most-common path (no Central running) unchange ## 2. Background -See [shared_memory_architecture.md](shared_memory_architecture.md) for the current +See [shared_memory_architecture.md](../shared_memory_architecture.md) for the current two-mode (NATIVE / CENTRAL_COMPAT) layout, and -[central_shared_memory_layout.md](central_shared_memory_layout.md) for upstream +[central_shared_memory_layout.md](../central_shared_memory_layout.md) for upstream Central's layout. The current `ShmemSession` carries a `ShmemLayout` enum (`CENTRAL`, `CENTRAL_COMPAT`, @@ -559,8 +559,8 @@ Each step is independently shippable; old behavior is preserved until step 6. ## 13. References -- [shared_memory_architecture.md](shared_memory_architecture.md) — current architecture -- [central_shared_memory_layout.md](central_shared_memory_layout.md) — Central's layout +- [shared_memory_architecture.md](../shared_memory_architecture.md) — current architecture +- [central_shared_memory_layout.md](../central_shared_memory_layout.md) — Central's layout - `src/cbproto/include/cbproto/packet_translator.h` — existing version-tagged packet translation - `src/cbshm/src/shmem_session.cpp` — current `ShmemSession` dispatch sites - `src/cbshm/include/cbshm/central_types.h` — current `CentralLegacyCFGBUFF` diff --git a/docs/shared_memory_architecture.md b/docs/shared_memory_architecture.md index be9e45e1..88f4168b 100644 --- a/docs/shared_memory_architecture.md +++ b/docs/shared_memory_architecture.md @@ -8,17 +8,17 @@ CereLink supports two shared memory modes: Lean, right-sized buffers. No instance index -- devices identified by type. Packets are always in the current protocol format. -- **Central compat mode** (fallback): CereLink attaches to Central's existing shared memory - as a CLIENT. Uses `CentralLegacyCFGBUFF` to match Central's exact binary layout (which - differs from CereLink's `cbConfigBuffer`). Instrument filtering extracts only the - requested device's packets from Central's shared receive buffer. Protocol translation - handles older Central formats (3.11, 4.0, 4.1) automatically. +- **Central mode** (fallback): CereLink attaches to Central's existing shared memory + as a CLIENT. Uses `cbCFGBUFF` to match Central's exact binary layout (which differs from + CereLink's `cbConfigBuffer`). Instrument filtering extracts only the requested device's + packets from Central's shared receive buffer. Protocol translation handles older Central + formats (3.11, 4.0, 4.1) automatically. -Mode is auto-detected at startup: if Central's shared memory exists, use compat mode; +Mode is auto-detected at startup: if Central's shared memory exists, use Central mode; otherwise, use native mode. **See also**: [Central's shared memory layout](central_shared_memory_layout.md) for the -upstream layout that compat mode interoperates with. +upstream layout that central mode interoperates with. ## Device Identification @@ -45,39 +45,39 @@ auto session = SdkSession::open(DeviceType::HUB1); ## Architecture Diagram (Native Mode) ``` -+------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------+ | CEREBUS DEVICE | | (NSP Hardware - UDP Protocol) | -+--------------------+-----------------------------------+---------------------------+ ++--------------------+-----------------------------------+----------------------------+ | | | UDP Packets | UDP Packets | (Port varies by device) | (Port varies by device) v ^ +-------------------------------------------------------------------------------------+ -| STANDALONE PROCESS (owns device) | +| STANDALONE PROCESS (owns device) | | +--------------------------------------------------------------------------------+ | -| | THREADS | | -| | | | -| | +----------------+ +----------------+ +-----------------+ | | -| | | UDP Receive | | UDP Send | | Callback | | | -| | | Thread | | Thread | | Dispatcher | | | -| | | (cbdev) | | (cbdev) | | Thread | | | +| | THREADS | | +| | | | +| | +----------------+ +----------------+ +-----------------+ | | +| | | UDP Receive | | UDP Send | | Callback | | | +| | | Thread | | Thread | | Dispatcher | | | +| | | (cbdev) | | (cbdev) | | Thread | | | | | +--------+-------+ +--------^-------+ +--------^-------+ | | -| | | | | | | -| | | Packets | Dequeue | Process | | -| | | (translated to | packets | callbacks | | -| | | current protocol) | | | | -| | v | | | | -| | +--------+-----------------------+-----------------------+-------+ | | -| | | onPacketsReceivedFromDevice() | | | -| | | | | | -| | | 1. storePacket() -> rec buffer (ring buffer) | | | -| | | 2. storePacket() -> cfg buffer (config updates) | | | -| | | 3. signalData() -> signal event <-----------+ | | | -| | | 4. Enqueue to local SPSC queue | SIGNAL! | | | -| | +--------------------------------------------------+ | | | +| | | | | | | +| | | Packets | Dequeue | Process | | +| | | (translated to | packets | callbacks | | +| | | current protocol) | | | | +| | v | | | | +| | +--------+-----------------------+-----------------------+-------+ | | +| | | onPacketsReceivedFromDevice() | | | +| | | | | | +| | | 1. storePacket() -> rec buffer (ring buffer) | | | +| | | 2. storePacket() -> cfg buffer (config updates) | | | +| | | 3. signalData() -> signal event <-----------+ | | | +| | | 4. Enqueue to local SPSC queue | SIGNAL! | | | +| | +--------------------------------------------------+ | | | | +--------------------------------------------------------------------------------+ | -+------------------+----------------------------------------------------------------------+ ++------------------+------------------------------------------------------------------+ | | Writes to (Producer) | @@ -101,17 +101,17 @@ auto session = SdkSession::open(DeviceType::HUB1); | Reads from (Consumer) | +------------------v-----------------------------------------------------------------------+ -| CLIENT PROCESS (attaches to shmem) | +| CLIENT PROCESS (attaches to shmem) | | +-------------------------------------------------------------------------------------+ | | | Shared Memory Receive Thread | | -| | | | -| | while (running) { | | -| | waitForData(250ms) <-- wakeup from signal | | -| | if (signaled) { | | -| | readReceiveBuffer() <-- all packets are this device's | | -| | packet_callback(packets, count) <-- direct invocation, no queue | | -| | } | | -| | } | | +| | | | +| | while (running) { | | +| | waitForData(250ms) <-- wakeup from signal | | +| | if (signaled) { | | +| | readReceiveBuffer() <-- all packets are this device's | | +| | packet_callback(packets, count) <-- direct invocation, no queue | | +| | } | | +| | } | | | +-------------------------------------------------------------------------------------+ | +-----------------------------------------------------------------------------------------+ ``` @@ -183,15 +183,15 @@ Channel count per device (`NATIVE_MAXCHANS` with `cbMAXPROCS=1`): ### Per-Device Memory Footprint -| Segment | Central-compat (4 instruments) | Native (1 device) | Savings | -|----------------|--------------------------------|---------------------------|----------| -| Config buffer | ~4 MB (880 ch, `[4]` arrays) | ~1 MB (284 ch, scalars) | ~75% | -| Receive buffer | ~768 MB (768 FE ch) | ~256 MB (256 FE ch) | ~67% | -| XmtGlobal | ~290 MB (5000 * max-UDP-size) | ~5 MB (5000 * 1024 bytes) | ~98% | -| XmtLocal | ~116 MB (2000 * max-UDP-size) | ~2 MB (2000 * 1024 bytes) | ~98% | -| Spike cache | large (832 analog ch) | ~1/3 (272 analog ch) | ~67% | -| Status | ~few KB | ~few KB | -- | -| **Total** | **~1.2 GB** | **~265 MB** | **~78%** | +| Segment | Central (4 instruments) | Native (1 device) | +|----------------|--------------------------------|---------------------------| +| Config buffer | ~4 MB (880 ch, `[4]` arrays) | ~1 MB (284 ch, scalars) | +| Receive buffer | ~768 MB (768 FE ch) | ~256 MB (256 FE ch) | +| XmtGlobal | ~290 MB (5000 * max-UDP-size) | ~5 MB (5000 * 1024 bytes) | +| XmtLocal | ~116 MB (2000 * max-UDP-size) | ~2 MB (2000 * 1024 bytes) | +| Spike cache | large (832 analog ch) | ~1/3 (272 analog ch) | +| Status | ~few KB | ~few KB | +| **Total** | **~1.2 GB** | **~265 MB** | The transmit buffers are dramatically smaller because they carry only config/command packets (max 1024 bytes each), not max-UDP-sized packets. Central's XmtGlobal is drained at 4 @@ -210,14 +210,13 @@ Device (any protocol) --> cbdev DeviceSession wrapper --> translates to current This means CLIENT processes never need to know what protocol the device speaks. -## Central Compat Mode +## Central Mode When CereLink detects that Central is running (its shared memory segments exist), it -attaches as a CLIENT using the `CENTRAL_COMPAT` shared memory layout. This layout uses -`CentralLegacyCFGBUFF` -- a struct matching Central's exact binary field order -- instead -of CereLink's own `cbConfigBuffer` (which has incompatible field ordering). +attaches as a CLIENT using the `CENTRAL` shared memory layout. This layout uses +`cbCFGBUFF` which matches Central's exact binary field order. -### Segment Names (Central's) +### Segment Names Central uses instance-0 bare names: - `cbCFGbuffer`, `cbRECbuffer`, `XmtGlobal`, `XmtLocal`, `cbSTATUSbuffer`, `cbSPKbuffer`, @@ -250,38 +249,40 @@ For legacy (non-Gemini) NSP systems, only instrument index 0 is used. ### Receive Buffer Filtering -In Central's shared memory, ALL devices' packets go into ONE receive ring buffer. CereLink's -`setInstrumentFilter()` method configures `readReceiveBuffer()` to filter by instrument: - -1. `SdkSession::create()` sets the instrument filter based on DeviceType → instrument index -2. `readReceiveBuffer()` reads all packets from `cbRECbuffer` (advances the ring buffer tail) -3. For each packet, checks `cbpkt_header.instrument` against the filter -4. Packets not matching the filter are consumed (tail advances) but not delivered to the caller - -```cpp -// Set automatically by SdkSession::create() in compat mode -shmem_session.setInstrumentFilter(getCentralInstrumentIndex(config.device_type)); - -// readReceiveBuffer() internally skips non-matching packets -session.readReceiveBuffer(packets, max_count, packets_read); -// packets_read only includes packets matching the instrument filter -``` +In Central's shared memory, ALL devices' packets go into ONE receive ring buffer. +`readReceiveBuffer()` filters these packets so only those belonging to the selected instrument +are read. This is less efficient than native mode (where the receive buffer only contains one device's -packets), but the large buffer size (~768 MB) makes this a negligible cost. +packets). Because `readReceiveBuffer()` copies and translates each packet into the output slot +*before* inspecting its instrument field, packets belonging to other instruments are fully +processed and then discarded (the slot is overwritten on the next iteration). The overhead +therefore scales with the total cross-instrument packet rate, not just the selected device's +traffic. The per-packet instrument check itself is a single integer comparison; the cost that +matters is the wasted copy/translate work for discarded packets. -### Protocol Translation in Compat Mode (Phase 3 - Complete) +### Protocol Translation in Compat Mode When CereLink attaches to Central's shared memory, Central may be running an older protocol (3.11, 4.0, or 4.1). Central stores raw device packets in `cbRECbuffer` without translation. CereLink detects the protocol version and translates packets on-the-fly. -**Protocol detection** reads `procinfo[0].version` from `CentralLegacyCFGBUFF`: -- `version = (major << 16) | minor` (MAKELONG format) -- major < 4 → Protocol 3.11 (8-byte headers, 32-bit timestamps) -- major=4, minor=0 → Protocol 4.0 (16-byte headers, different field layout) -- major=4, minor=1 → Protocol 4.1 (16-byte headers, current layout) -- major=4, minor≥2 → Current protocol (no translation needed) +**Protocol detection** (`detectCompatProtocol`) cannot rely on Central's shared memory: +the `version` field in `cbCFGBUFF` is a magic number (`96`), not a meaningful version, and +`procinfo[].version` is unusable because its byte offset shifts between protocol versions. +Instead, detection inspects the **application version** of the running `Central.exe` +(`VersionInfo.ProductVersion`) and maps it to a protocol version. This is **Windows-only**; +on other platforms compat mode is unavailable. + +The application-version → protocol-version mapping: +- Central 7.0 → Protocol 3.11 (8-byte headers, 32-bit timestamps) +- Central 7.5 → Protocol 4.0 (16-byte headers, different field layout) +- Central 7.6, 7.7 → Protocol 4.1 (16-byte headers, current layout) +- Central 7.8 (and newer 7.x) → Current protocol 4.2+ (no translation needed) +- Central major version < 7 → unsupported (caller must upgrade Central) + +This indirect approach is brittle: a future Central with a different executable name or +version-string format would defeat it. See `detectCompatProtocol` in `shmem_session.cpp`. **Receive path** (`readReceiveBuffer`): Parses the protocol-specific header to extract `dlen`, copies raw bytes from the ring buffer, translates header + payload to current @@ -297,30 +298,32 @@ library) so that both `cbshm` and `cbdev` can access it. ### Config Buffer Access in Compat Mode -Central's `cbCFGBUFF` has a different field layout than CereLink's `NativeConfigBuffer` or -`cbConfigBuffer` (see "Differences from Central" section below). The `CENTRAL_COMPAT` layout -uses a `CentralLegacyCFGBUFF` struct that matches Central's exact field order to read the -config buffer correctly. +Central's `cbCFGBUFF` has a different field layout than CereLink's `NativeConfigBuffer`. +The `CENTRAL` layout uses a `cbCFGBUFF` struct that matches Central's exact field order to +read the config buffer correctly. All `ShmemSession` accessor methods (`getProcInfo`, `setBankInfo`, `getFilterInfo`, etc.) -dispatch on the layout and use the correct struct: +dispatch on the layout and either use the native buffer or the Central adapter: ```cpp -// In CENTRAL_COMPAT mode, accessors use legacyCfg() -if (layout == ShmemLayout::CENTRAL_COMPAT) - return legacyCfg()->procinfo[idx]; // CentralLegacyCFGBUFF -else if (layout == ShmemLayout::NATIVE) - return nativeCfg()->procinfo; // NativeConfigBuffer (scalar) -else - return centralCfg()->procinfo[idx]; // cbConfigBuffer +if (layout == ShmemLayout::NATIVE) { + return Result::ok(nativeCfg()->procinfo); +} else { + auto info = Result::ok({}); + auto res = adapter->getProcInfo(info.value()); + if (res.isError()) { + return Result::error(res.error()); + } + return info; +} ``` -Instrument status in compat mode: +Instrument status in central mode: - `isInstrumentActive()` always returns **true** (Central has no `instrument_status` field; if the shared memory exists, instruments are configured by Central) - `setInstrumentActive()` returns **error** (read-only in compat mode) - `getConfigBuffer()` returns **nullptr** (wrong struct type for compat mode) -- `getLegacyConfigBuffer()` returns the `CentralLegacyCFGBUFF*` pointer +- `getLegacyConfigBuffer()` returns a copy of Central's configuration struct translated to a `NativeConfigBuffer` ## Mode Auto-Detection @@ -329,12 +332,12 @@ SdkSession::open(DeviceType::HUB1) | +-- Can open Central's "cbSharedDataMutex" (instance 0)? | | - | YES --> Central Compat Mode (CENTRAL_COMPAT layout) + | YES --> Central Mode (CENTRAL layout) | - Map Central's 7 instance-0 segments - | - Use CentralLegacyCFGBUFF for config buffer (Central's binary layout) + | - Use cbCFGBUFF for config buffer (Central's binary layout) | - Use GEMSTART==2 mapping: Hub1 = instrument index 0 - | - Set instrument filter (setInstrumentFilter) for receive buffer - | - Index into [4] arrays for config access via legacyCfg() + | - Set instrument filter for receive buffer + | - Target instrument is fixed for the session's lifetime (set at creation) | - Detect protocol version, translate packets if non-current | +-- NO --> Can open "cbshm_hub1_signal"? @@ -346,10 +349,10 @@ SdkSession::open(DeviceType::HUB1) | - Config is single-instrument (no indexing) | +-- NO --> Native Standalone Mode - - Create cbshm_hub1_* segments - - Start cbdev (protocol auto-detect + translation) - - Write current-format packets to native shmem - - Other CLIENTs can attach via Native Client Mode + - Create cbshm_hub1_* segments + - Start cbdev (protocol auto-detect + translation) + - Write current-format packets to native shmem + - Other CLIENTs can attach via Native Client Mode ``` ## Key Data Flow Paths @@ -443,79 +446,6 @@ an SPSC queue to buffer between fast UDP receive and slow callback processing. - One extra thread (simpler architecture, less overhead) - One extra data copy (receive buffer -> callback, no packet_queue needed) -## Differences from Central-Suite's Shared Memory Layout - -CereLink's current `cbConfigBuffer` struct is **NOT binary-compatible** with Central's -`cbCFGBUFF`. For a complete description of Central's layout, see -[central_shared_memory_layout.md](central_shared_memory_layout.md). - -### cbCFGbuffer / Config Buffer (INCOMPATIBLE) - -Field ordering is changed and fields are added/removed: - -| # | Central `cbCFGBUFF` | CereLink `cbConfigBuffer` | -|----|----------------------|----------------------------------| -| 1 | `version` | `version` | -| 2 | `sysflags` | `sysflags` | -| 3 | **`optiontable`** | **`instrument_status[4]`** (NEW) | -| 4 | **`colortable`** | `sysinfo` | -| 5 | `sysinfo` | `procinfo[4]` | -| 6 | `procinfo[4]` | `bankinfo[4][30]` | -| 7 | `bankinfo[4][30]` | `groupinfo[4][8]` | -| 8 | `groupinfo[4][8]` | `filtinfo[4][32]` | -| 9 | `filtinfo[4][32]` | `adaptinfo[4]` | -| 10 | `adaptinfo[4]` | `refelecinfo[4]` | -| 11 | `refelecinfo[4]` | **`isLnc[4]`** (MOVED earlier) | -| 12 | `chaninfo[880]` | `chaninfo[880]` | -| 13 | `isSortingOptions` | `isSortingOptions` | -| 14 | `isNTrodeInfo[..]` | `isNTrodeInfo[..]` | -| 15 | `isWaveform[..][..]` | `isWaveform[..][..]` | -| 16 | **`isLnc[4]`** | `isNPlay` | -| 17 | `isNPlay` | `isVideoSource[..]` | -| 18 | `isVideoSource[..]` | `isTrackObj[..]` | -| 19 | `isTrackObj[..]` | `fileinfo` | -| 20 | `fileinfo` | **`optiontable`** (MOVED later) | -| 21 | **`hwndCentral`** | **`colortable`** (MOVED later) | -| 22 | -- | (hwndCentral OMITTED) | - -Central compat mode requires a separate `CentralLegacyCFGBUFF` struct matching Central's -exact layout to read the config buffer correctly. - -### cbSTATUSbuffer / PC Status (PARTIALLY COMPATIBLE) - -| Difference | Central `cbPcStatus` | CereLink `CentralPCStatus` | -|---------------------|-----------------------------------------------|-----------------------------| -| Type | C++ class (private/public) | Plain C struct | -| `APP_WORKSPACE[10]` | Present (at end) | **Omitted** | -| Overlap | Fields match in order up to `m_nGeminiSystem` | Same | - -CereLink's struct is a subset -- safe to read, safe to write (omitted field is at the end). - -### cbRECbuffer, XmtGlobal, XmtLocal (COMPATIBLE) - -Same field layout: -- `received`, `lasttime`, `headwrap`, `headindex`, `buffer[N]` (receive) -- `transmitted`, `headindex`, `tailindex`, `last_valid_index`, `bufferlen`, `buffer[N]` (transmit) - -Central uses flexible array member (`buffer[0]`), CereLink uses fixed-size. Binary layout -matches as long as allocated sizes match. - -### cbSPKbuffer, cbSIGNALevent (COMPATIBLE) - -Same structure layouts and mechanisms. - -### Compatibility Summary - -| Segment | Compatible? | Notes | -|----------------|--------------|--------------------------------------------------| -| cbCFGbuffer | **NO** | Field order differs; need `CentralLegacyCFGBUFF` | -| cbRECbuffer | Yes | Same layout | -| XmtGlobal | Yes | Same layout | -| XmtLocal | Yes | Same layout | -| cbSTATUSbuffer | Partial | CereLink is a subset (missing workspace at end) | -| cbSPKbuffer | Yes | Same layout | -| cbSIGNALevent | Yes | Same mechanism | - ## Known Limitations - GEMSTART mapping is hardcoded to `GEMSTART==2`. If a Central build uses a different @@ -527,7 +457,10 @@ Same structure layouts and mechanisms. - **Shared Memory**: `src/cbshm/` - `include/cbshm/shmem_session.h` - Public API (ShmemSession class) - `src/shmem_session.cpp` - Implementation - - `include/cbshm/central_types.h` - Central-compatible buffer structures + `CentralLegacyCFGBUFF` + - `include/cbshm/central_adapters/base.h` - Base class of the Central adapters + - `include/cbshm/central_adapters/.h` - Per-version Central adapters + - `include/cbshm/central_types/.h` - Per-version Central-compatible buffer structures + `cbCFGBUFF` + - `src/central_adapters/.cpp` - Per-version Central adapter implementations - `include/cbshm/native_types.h` - Native-mode buffer structures (single-instrument) - `include/cbshm/config_buffer.h` - Configuration buffer struct definition (`cbConfigBuffer`) @@ -552,6 +485,7 @@ Same structure layouts and mechanisms. ## References - [Central's shared memory layout](central_shared_memory_layout.md) +- [Central adapter](multi_version_central_compat/README.md) - Central Suite source: `Central-Suite/cbhwlib/cbhwlib.h` and `cbhwlib.cpp` - Central instrument assignment: `Central-Suite/CentralCommon/CentralDlg.cpp` (GEMSTART) - Cerebus Protocol Specification From 4dcdedc2ded5025074ff4c7f06fb1439a2de937d Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Tue, 23 Jun 2026 17:30:02 -0600 Subject: [PATCH 35/62] FIX: Channel info unpacking in CCFTest --- examples/CCFTest/ccf_test.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/CCFTest/ccf_test.cpp b/examples/CCFTest/ccf_test.cpp index 28b8beeb..d12cd80c 100644 --- a/examples/CCFTest/ccf_test.cpp +++ b/examples/CCFTest/ccf_test.cpp @@ -35,8 +35,9 @@ DeviceType parseDeviceType(const std::string& s) { void printChannelSummary(SdkSession& session, const char* label, int n = 5) { std::cout << "=== " << label << " (channels 1-" << n << ") ===\n"; for (uint32_t ch = 1; ch <= (uint32_t)n; ++ch) { - const auto* info = session.getChanInfo(ch); - if (info) { + auto info_res = session.getChanInfo(ch); + if (info_res.isOk()) { + const auto* info = &info_res.value(); std::cout << " ch " << std::setw(3) << ch << ": spkopts=0x" << std::hex << std::setw(5) << std::setfill('0') << info->spkopts << " ainpopts=0x" << std::setw(4) << info->ainpopts @@ -125,8 +126,9 @@ int main(int argc, char* argv[]) { // Re-read saved CCF A to compare against current device state std::cout << "\n Field differences (ch 1-5) between saved A and current (B) state:\n"; for (uint32_t ch = 1; ch <= 5; ++ch) { - const auto* info = session.getChanInfo(ch); - if (!info) continue; + auto info_res = session.getChanInfo(ch); + if (info_res.isError()) continue; + const auto* info = &info_res.value(); std::cout << " ch " << ch << ":" << " spkopts=0x" << std::hex << info->spkopts << " ainpopts=0x" << info->ainpopts << std::dec From 3308e0b9968cc7b2957e272e568e706f4dda6d81 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Wed, 24 Jun 2026 08:12:58 -0600 Subject: [PATCH 36/62] FIX: cbCFGBUFF reference in the cbshm README --- src/cbshm/README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/cbshm/README.md b/src/cbshm/README.md index caca2edb..29a226c0 100644 --- a/src/cbshm/README.md +++ b/src/cbshm/README.md @@ -5,13 +5,13 @@ between STANDALONE and CLIENT sessions. ## Responsibilities -- **Three layout modes:** `NATIVE` (CereLink-to-CereLink), `CENTRAL_COMPAT` (attach to - Central's shared memory), `CENTRAL` (Central-compatible layout created by CereLink) +- **Two layout modes:** `NATIVE` (CereLink-to-CereLink), `CENTRAL` (attach to + Central's shared memory) - **Consistent packet indexing:** Always uses `packet.instrument` as the array index, regardless of mode - **Ring buffer I/O:** Write packets to the receive buffer (STANDALONE), read packets from it (CLIENT), with protocol-aware parsing and translation in compat mode -- **Instrument filtering:** In `CENTRAL_COMPAT` mode, filters packets from Central's +- **Instrument filtering:** In `CENTRAL` mode, filters packets from Central's shared receive buffer by instrument index - **Platform-specific implementations:** Windows (`CreateFileMapping`) and POSIX (`shm_open`) shared memory, plus platform-specific signaling @@ -21,14 +21,13 @@ between STANDALONE and CLIENT sessions. | Type | Purpose | |------|---------| | `ShmemSession` | Main API — create/attach segments, read/write buffers, access config | -| `ShmemLayout` | Enum: `CENTRAL`, `CENTRAL_COMPAT`, `NATIVE` | +| `ShmemLayout` | Enum: `CENTRAL`, `NATIVE` | | `NativeConfigBuffer` | Single-instrument config (284 channels, scalar arrays) | -| `CentralLegacyCFGBUFF` | Matches Central's exact binary layout for compat mode | -| `cbConfigBuffer` | CereLink's own multi-instrument config layout | +| `cbCFGBUFF` | Matches Central's exact binary layout for compat mode | ## Key Design Notes -- **Central vs CereLink constants:** Central uses `cbMAXPROCS=4`, `cbNUM_FE_CHANS=768`. +- **Central vs CereLink constants:** Central uses `cbMAXPROCS=4`, `cbNUM_FE_CHANS=768` (in v7.8.0). CereLink uses `cbMAXPROCS=1`, `cbNUM_FE_CHANS=256`. The compat types use Central's constants; native types use CereLink's. - **Not exposed to public API:** cbsdk orchestrates cbshm; users don't interact with it From 5f38df19b71e5605411c1cbc16beffa8188dc063 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Wed, 24 Jun 2026 08:13:27 -0600 Subject: [PATCH 37/62] FIX: CENTRAL mode in the cbsdk README --- src/cbsdk/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cbsdk/README.md b/src/cbsdk/README.md index 3c858199..ace88b1a 100644 --- a/src/cbsdk/README.md +++ b/src/cbsdk/README.md @@ -6,7 +6,7 @@ single session interface. ## Responsibilities - **Session lifecycle:** Create, start, stop, destroy -- **Mode auto-detection:** CENTRAL_COMPAT CLIENT → Native CLIENT → Native STANDALONE +- **Mode auto-detection:** CENTRAL CLIENT → NATIVE CLIENT → NATIVE STANDALONE (three-way fallback) - **Device handshake:** Protocol detection, configuration request, run-level control - **Callback system:** Per-type callbacks (event, group, group batch, config, packet) From 5fc2747635e43036d013424d3896378564bdd3a3 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Thu, 25 Jun 2026 13:55:26 -0600 Subject: [PATCH 38/62] Per-instrument ShmemSession Each ShmemSession instance pertains to a particular instrument. The names of each individual shared memory buffer have been collapsed into a single parameter passed to the constructor. All methods of ShmemSession that previously took an InstrumentId as an argument no longer accept this value. In the future, it may make sense to move the version detection logic in ShmemSession::Impl outside of ShmemSession so it isn't rerun every time a new ShmemSession instance is constructed. A protocol version field could be added to the create() method so the protocol version can be provided. --- src/cbsdk/src/sdk_session.cpp | 133 ++---------------- src/cbshm/include/cbshm/central_types/v3_11.h | 4 +- src/cbshm/include/cbshm/central_types/v4_0.h | 6 +- src/cbshm/include/cbshm/central_types/v4_1.h | 4 +- src/cbshm/include/cbshm/central_types/v4_2.h | 4 +- src/cbshm/include/cbshm/shmem_session.h | 40 +++--- src/cbshm/src/central_adapters/v3_11.cpp | 5 +- src/cbshm/src/central_adapters/v4_0.cpp | 5 +- src/cbshm/src/central_adapters/v4_1.cpp | 5 +- src/cbshm/src/central_adapters/v4_2.cpp | 5 +- src/cbshm/src/shmem_session.cpp | 64 ++++++--- 11 files changed, 100 insertions(+), 175 deletions(-) diff --git a/src/cbsdk/src/sdk_session.cpp b/src/cbsdk/src/sdk_session.cpp index 250d56af..d46aba39 100644 --- a/src/cbsdk/src/sdk_session.cpp +++ b/src/cbsdk/src/sdk_session.cpp @@ -577,97 +577,6 @@ SdkSession::~SdkSession() { } } -// Helper function to map DeviceType to shared memory instance number. -// Central creates a SINGLE shared memory instance (0) for ALL instruments in a -// Gemini system. The different instruments (Hub1-3, NSP) share the same buffers -// and are distinguished by instrument INDEX within the buffers, not by separate -// shared memory instances. Therefore all device types map to instance 0. -static int getInstanceNumber(DeviceType /*type*/) { - return 0; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Central-compatible shared memory naming -// Names match Central's naming convention: base name + optional instance suffix -/////////////////////////////////////////////////////////////////////////////////////////////////// - -// Helper function to get Central-compatible shared memory names -// Returns config buffer name (e.g., "cbCFGbuffer" or "cbCFGbuffer1") -static std::string getCentralConfigBufferName(DeviceType type) { - int instance = getInstanceNumber(type); - if (instance == 0) { - return "cbCFGbuffer"; - } else { - return "cbCFGbuffer" + std::to_string(instance); - } -} - -// Helper function to get Central-compatible transmit buffer name -// Returns transmit buffer name (e.g., "XmtGlobal" or "XmtGlobal1") -static std::string getCentralTransmitBufferName(DeviceType type) { - int instance = getInstanceNumber(type); - if (instance == 0) { - return "XmtGlobal"; - } else { - return "XmtGlobal" + std::to_string(instance); - } -} - -// Helper function to get Central-compatible receive buffer name -// Returns receive buffer name (e.g., "cbRECbuffer" or "cbRECbuffer1") -static std::string getCentralReceiveBufferName(DeviceType type) { - int instance = getInstanceNumber(type); - if (instance == 0) { - return "cbRECbuffer"; - } else { - return "cbRECbuffer" + std::to_string(instance); - } -} - -// Helper function to get Central-compatible local transmit buffer name -// Returns local transmit buffer name (e.g., "XmtLocal" or "XmtLocal1") -static std::string getCentralLocalTransmitBufferName(DeviceType type) { - int instance = getInstanceNumber(type); - if (instance == 0) { - return "XmtLocal"; - } else { - return "XmtLocal" + std::to_string(instance); - } -} - -// Helper function to get Central-compatible status buffer name -// Returns status buffer name (e.g., "cbSTATUSbuffer" or "cbSTATUSbuffer1") -static std::string getCentralStatusBufferName(DeviceType type) { - int instance = getInstanceNumber(type); - if (instance == 0) { - return "cbSTATUSbuffer"; - } else { - return "cbSTATUSbuffer" + std::to_string(instance); - } -} - -// Helper function to get Central-compatible spike cache buffer name -// Returns spike cache buffer name (e.g., "cbSPKbuffer" or "cbSPKbuffer1") -static std::string getCentralSpikeBufferName(DeviceType type) { - int instance = getInstanceNumber(type); - if (instance == 0) { - return "cbSPKbuffer"; - } else { - return "cbSPKbuffer" + std::to_string(instance); - } -} - -// Helper function to get Central-compatible signal event name -// Returns signal event name (e.g., "cbSIGNALevent" or "cbSIGNALevent1") -static std::string getCentralSignalEventName(DeviceType type) { - int instance = getInstanceNumber(type); - if (instance == 0) { - return "cbSIGNALevent"; - } else { - return "cbSIGNALevent" + std::to_string(instance); - } -} - /////////////////////////////////////////////////////////////////////////////////////////////////// // Native-mode shared memory naming // Names use per-device segments: "cbshm_{device}_{segment}" @@ -716,38 +625,22 @@ Result SdkSession::create(const SdkConfig& config) { // 3. Fall back to native STANDALONE: create new native-mode segments bool is_standalone = false; + // Device token used to build NATIVE segment names. The SDK always targets + // Central's primary instance, so the CENTRAL instance suffix is empty. + std::string device_tag = getNativeDeviceName(config.device_type); + // --- Attempt 1: Central-compatible CLIENT mode --- // Try to attach to Central's shared memory (Central is running) - std::string central_cfg = getCentralConfigBufferName(config.device_type); - std::string central_rec = getCentralReceiveBufferName(config.device_type); - std::string central_xmt = getCentralTransmitBufferName(config.device_type); - std::string central_xmt_local = getCentralLocalTransmitBufferName(config.device_type); - std::string central_status = getCentralStatusBufferName(config.device_type); - std::string central_spk = getCentralSpikeBufferName(config.device_type); - std::string central_signal = getCentralSignalEventName(config.device_type); - auto inst = cbproto::InstrumentId::fromIndex(getCentralInstrumentIndex(config.device_type)); auto shmem_result = cbshm::ShmemSession::create( - inst, central_cfg, central_rec, central_xmt, central_xmt_local, - central_status, central_spk, central_signal, - cbshm::Mode::CLIENT, cbshm::ShmemLayout::CENTRAL); + cbshm::Mode::CLIENT, cbshm::ShmemLayout::CENTRAL, /*instance=*/"", inst); if (shmem_result.isError()) { // --- Attempt 2: Native CLIENT mode --- // Try to attach to an existing CereLink STANDALONE's native segments - std::string native_cfg = getNativeSegmentName(config.device_type, "config"); - std::string native_rec = getNativeSegmentName(config.device_type, "receive"); - std::string native_xmt = getNativeSegmentName(config.device_type, "xmt_global"); - std::string native_xmt_local = getNativeSegmentName(config.device_type, "xmt_local"); - std::string native_status = getNativeSegmentName(config.device_type, "status"); - std::string native_spk = getNativeSegmentName(config.device_type, "spike"); - std::string native_signal = getNativeSegmentName(config.device_type, "signal"); - shmem_result = cbshm::ShmemSession::create( - cbproto::InstrumentId::fromIndex(0), - native_cfg, native_rec, native_xmt, native_xmt_local, - native_status, native_spk, native_signal, - cbshm::Mode::CLIENT, cbshm::ShmemLayout::NATIVE); + cbshm::Mode::CLIENT, cbshm::ShmemLayout::NATIVE, device_tag, + cbproto::InstrumentId::fromIndex(0)); // Liveness check: reject stale segments from a dead STANDALONE process. // The ShmemSession destructor (triggered by reassignment) unmaps the segments; @@ -761,10 +654,8 @@ Result SdkSession::create(const SdkConfig& config) { // --- Attempt 3: Native STANDALONE mode --- // No existing shared memory found, create new native-mode segments shmem_result = cbshm::ShmemSession::create( - cbproto::InstrumentId::fromIndex(0), - native_cfg, native_rec, native_xmt, native_xmt_local, - native_status, native_spk, native_signal, - cbshm::Mode::STANDALONE, cbshm::ShmemLayout::NATIVE); + cbshm::Mode::STANDALONE, cbshm::ShmemLayout::NATIVE, device_tag, + cbproto::InstrumentId::fromIndex(0)); if (shmem_result.isError()) { return Result::error("Failed to create shared memory: " + shmem_result.error()); @@ -2349,7 +2240,7 @@ std::optional SdkSession::getClockOffsetNs() const { return offset; } - // CLIENT fallback: use local ClockSync (CENTRAL_COMPAT — no shmem clock fields) + // CLIENT fallback: use local ClockSync (CENTRAL — no shmem clock fields) return m_impl->client_clock_sync.getOffsetNs(); } @@ -2364,7 +2255,7 @@ std::optional SdkSession::getClockUncertaintyNs() const { return uncert; } - // CLIENT fallback: use local ClockSync (CENTRAL_COMPAT) + // CLIENT fallback: use local ClockSync (CENTRAL) return m_impl->client_clock_sync.getUncertaintyNs(); } @@ -2382,7 +2273,7 @@ Result SdkSession::sendPacket(const cbPKT_GENERIC& pkt) { // Stamp packet with a nanosecond timestamp (Central's xmt consumer skips packets with time=0). // Use getLastTime() (always nanoseconds) so that enqueuePacket's per-protocol translation - // can convert to the format each consumer expects (e.g. 30kHz ticks for 3.11 CENTRAL_COMPAT). + // can convert to the format each consumer expects (e.g. 30kHz ticks for 3.11 CENTRAL). cbPKT_GENERIC stamped = pkt; PROCTIME t = m_impl->shmem_session->getLastTime(); stamped.cbpkt_header.time = (t != 0) ? t : 1; diff --git a/src/cbshm/include/cbshm/central_types/v3_11.h b/src/cbshm/include/cbshm/central_types/v3_11.h index a7a5df19..030f8ec4 100644 --- a/src/cbshm/include/cbshm/central_types/v3_11.h +++ b/src/cbshm/include/cbshm/central_types/v3_11.h @@ -666,8 +666,8 @@ typedef struct { /// /// This struct matches Central's cbCFGBUFF field order EXACTLY (from cbhwlib.h). /// It is NOT the same as CereLink's cbConfigBuffer (which reorders fields and adds -/// instrument_status). This struct is used in CENTRAL_COMPAT mode to read Central's -/// shared memory as a CLIENT. +/// instrument_status). This struct is used in CENTRAL mode to read Central's shared +/// memory as a CLIENT. /// /// Key differences from CereLink's cbConfigBuffer: /// - optiontable/colortable: 3rd/4th fields here (after sysflags), last fields in CereLink diff --git a/src/cbshm/include/cbshm/central_types/v4_0.h b/src/cbshm/include/cbshm/central_types/v4_0.h index ebd1f637..b734e940 100644 --- a/src/cbshm/include/cbshm/central_types/v4_0.h +++ b/src/cbshm/include/cbshm/central_types/v4_0.h @@ -102,7 +102,7 @@ constexpr uint32_t AOUT_NUM_GAIN_CHANS = cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS /// Spike cache constants constexpr uint32_t cbPKT_SPKCACHEPKTCNT = 400; ///< Packets per channel cache -constexpr uint32_t cbPKT_SPKCACHELINECNT = cbMAXCHANS; ///< One cache per channel (Central uses cbMAXCHANS, not cbNUM_ANALOG_CHANS) +constexpr uint32_t cbPKT_SPKCACHELINECNT = cbNUM_ANALOG_CHANS; ///< One cache per channel (Central uses cbMAXCHANS, not cbNUM_ANALOG_CHANS) /// Receive buffer size constexpr uint32_t cbRECBUFFLEN = cbNUM_FE_CHANS * 32768 * 4; @@ -666,8 +666,8 @@ typedef struct { /// /// This struct matches Central's cbCFGBUFF field order EXACTLY (from cbhwlib.h). /// It is NOT the same as CereLink's cbConfigBuffer (which reorders fields and adds -/// instrument_status). This struct is used in CENTRAL_COMPAT mode to read Central's -/// shared memory as a CLIENT. +/// instrument_status). This struct is used in CENTRAL mode to read Central's shared +/// memory as a CLIENT. /// /// Key differences from CereLink's cbConfigBuffer: /// - optiontable/colortable: 3rd/4th fields here (after sysflags), last fields in CereLink diff --git a/src/cbshm/include/cbshm/central_types/v4_1.h b/src/cbshm/include/cbshm/central_types/v4_1.h index 99b95acf..07aaa536 100644 --- a/src/cbshm/include/cbshm/central_types/v4_1.h +++ b/src/cbshm/include/cbshm/central_types/v4_1.h @@ -670,8 +670,8 @@ typedef struct { /// /// This struct matches Central's cbCFGBUFF field order EXACTLY (from cbhwlib.h). /// It is NOT the same as CereLink's cbConfigBuffer (which reorders fields and adds -/// instrument_status). This struct is used in CENTRAL_COMPAT mode to read Central's -/// shared memory as a CLIENT. +/// instrument_status). This struct is used in CENTRAL mode to read Central's shared +/// memory as a CLIENT. /// /// Key differences from CereLink's cbConfigBuffer: /// - optiontable/colortable: 3rd/4th fields here (after sysflags), last fields in CereLink diff --git a/src/cbshm/include/cbshm/central_types/v4_2.h b/src/cbshm/include/cbshm/central_types/v4_2.h index 5ccc5d69..4088cb05 100644 --- a/src/cbshm/include/cbshm/central_types/v4_2.h +++ b/src/cbshm/include/cbshm/central_types/v4_2.h @@ -670,8 +670,8 @@ typedef struct { /// /// This struct matches Central's cbCFGBUFF field order EXACTLY (from cbhwlib.h). /// It is NOT the same as CereLink's cbConfigBuffer (which reorders fields and adds -/// instrument_status). This struct is used in CENTRAL_COMPAT mode to read Central's -/// shared memory as a CLIENT. +/// instrument_status). This struct is used in CENTRAL mode to read Central's shared +/// memory as a CLIENT. /// /// Key differences from CereLink's cbConfigBuffer: /// - optiontable/colortable: 3rd/4th fields here (after sysflags), last fields in CereLink diff --git a/src/cbshm/include/cbshm/shmem_session.h b/src/cbshm/include/cbshm/shmem_session.h index 5c60cc52..e56ba1b2 100644 --- a/src/cbshm/include/cbshm/shmem_session.h +++ b/src/cbshm/include/cbshm/shmem_session.h @@ -47,7 +47,7 @@ enum class Mode { /// Controls buffer sizes, struct types, and bounds checking. /// enum class ShmemLayout { - CENTRAL, ///< Central's actual binary layout (CentralLegacyCFGBUFF) + CENTRAL, ///< Central's actual binary layout (cbCFGBUFF) NATIVE ///< Native single-instrument layout (NativeConfigBuffer) }; @@ -67,22 +67,24 @@ class ShmemSession { /// @{ /// @brief Create a new shared memory session - /// @param id Instrument ID (1-based) - /// @param cfg_name Config buffer shared memory name (e.g., "cbCFGbuffer") - /// @param rec_name Receive buffer shared memory name (e.g., "cbRECbuffer") - /// @param xmt_name Transmit buffer shared memory name (e.g., "XmtGlobal") - /// @param xmt_local_name Local transmit buffer shared memory name (e.g., "XmtLocal") - /// @param status_name PC status buffer shared memory name (e.g., "cbSTATUSbuffer") - /// @param spk_name Spike cache buffer shared memory name (e.g., "cbSPKbuffer") - /// @param signal_event_name Signal event name (e.g., "cbSIGNALevent") + /// + /// The seven segment names are synthesized internally from @p layout and + /// @p name_qualifier, whose meaning depends on the layout: + /// - CENTRAL: Central's fixed, well-known names (e.g., "cbCFGbuffer"), with + /// @p name_qualifier appended as the Central *instance* suffix ("" selects + /// the primary instance, "1" selects cbCFGbuffer1, etc.). + /// - NATIVE: per-device names of the form "cbshm__", + /// where @p name_qualifier is the device token (e.g., "hub1"). + /// /// @param mode Operating mode (STANDALONE or CLIENT) - /// @param layout Buffer layout (CENTRAL or NATIVE, default CENTRAL for backward compat) + /// @param layout Buffer layout (CENTRAL or NATIVE) + /// @param name_qualifier Layout-specific naming discriminator: the Central + /// instance suffix for CENTRAL, or the device token for + /// NATIVE + /// @param id Instrument ID (1-based) /// @return Result containing ShmemSession on success, error message on failure - static Result create(cbproto::InstrumentId id, const std::string& cfg_name, const std::string& rec_name, - const std::string& xmt_name, const std::string& xmt_local_name, - const std::string& status_name, const std::string& spk_name, - const std::string& signal_event_name, Mode mode, - ShmemLayout layout = ShmemLayout::CENTRAL); + static Result create(Mode mode, ShmemLayout layout, + const std::string& name_qualifier, cbproto::InstrumentId id); /// @brief Destructor - closes shared memory and releases resources ~ShmemSession(); @@ -94,7 +96,7 @@ class ShmemSession { ShmemSession& operator=(const ShmemSession&) = delete; /// @} - + /////////////////////////////////////////////////////////////////////////// /// @name Status /// @{ @@ -126,10 +128,16 @@ class ShmemSession { /// @{ /// @brief Get instrument active status + /// + /// Always returns true if layout is CENTRAL. + /// /// @return true if instrument is active in shared memory Result isInstrumentActive() const; /// @brief Set instrument active status + /// + /// Does nothing if layout is CENTRAL (instruments assumed to always be active). + /// /// @param active true to mark active, false to mark inactive /// @return Result indicating success or failure Result setInstrumentActive(bool active); diff --git a/src/cbshm/src/central_adapters/v3_11.cpp b/src/cbshm/src/central_adapters/v3_11.cpp index cf363053..5aab7f74 100644 --- a/src/cbshm/src/central_adapters/v3_11.cpp +++ b/src/cbshm/src/central_adapters/v3_11.cpp @@ -65,7 +65,6 @@ void Adapter::fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.idcode = leg.idcode; - cur.idcode = leg.idcode; copyArr(cur.ident, leg.ident); cur.chanbase = leg.chanbase; cur.chancount = leg.chancount; @@ -395,7 +394,7 @@ void Adapter::fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const { fromLegacy(cur.refelecinfo, leg.refelecinfo[instrument_idx]); copyArr(cur.chaninfo, leg.chaninfo, this, &Adapter::fromLegacy); copyArr(cur.asBasis, leg.isSortingOptions.asBasis, this, &Adapter::fromLegacy); - // copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); // TODO: For some reason, this contains memory that's innaccessible + copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); // TODO: Move native isSortingOptions fields into a struct fromLegacy(cur.pktDetect, leg.isSortingOptions.pktDetect); fromLegacy(cur.pktArtifReject, leg.isSortingOptions.pktArtifReject); @@ -899,7 +898,7 @@ void Adapter::toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur void Adapter::toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const { toLegacy(leg.cbpkt_header, cur.cbpkt_header); - copyArr(leg.fPattern, leg.fPattern); + copyArr(leg.fPattern, cur.fPattern); leg.nPeak = cur.nPeak; leg.nValley = cur.nValley; copyArr(leg.wave, cur.wave); diff --git a/src/cbshm/src/central_adapters/v4_0.cpp b/src/cbshm/src/central_adapters/v4_0.cpp index 23bb942b..d0c61b10 100644 --- a/src/cbshm/src/central_adapters/v4_0.cpp +++ b/src/cbshm/src/central_adapters/v4_0.cpp @@ -65,7 +65,6 @@ void Adapter::fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.idcode = leg.idcode; - cur.idcode = leg.idcode; copyArr(cur.ident, leg.ident); cur.chanbase = leg.chanbase; cur.chancount = leg.chancount; @@ -395,7 +394,7 @@ void Adapter::fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const { fromLegacy(cur.refelecinfo, leg.refelecinfo[instrument_idx]); copyArr(cur.chaninfo, leg.chaninfo, this, &Adapter::fromLegacy); copyArr(cur.asBasis, leg.isSortingOptions.asBasis, this, &Adapter::fromLegacy); - // copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); // TODO: For some reason, this contains memory that's innaccessible + copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); // TODO: Move native isSortingOptions fields into a struct fromLegacy(cur.pktDetect, leg.isSortingOptions.pktDetect); fromLegacy(cur.pktArtifReject, leg.isSortingOptions.pktArtifReject); @@ -900,7 +899,7 @@ void Adapter::toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur void Adapter::toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const { toLegacy(leg.cbpkt_header, cur.cbpkt_header); - copyArr(leg.fPattern, leg.fPattern); + copyArr(leg.fPattern, cur.fPattern); leg.nPeak = cur.nPeak; leg.nValley = cur.nValley; copyArr(leg.wave, cur.wave); diff --git a/src/cbshm/src/central_adapters/v4_1.cpp b/src/cbshm/src/central_adapters/v4_1.cpp index 1c82bfbc..f2d53153 100644 --- a/src/cbshm/src/central_adapters/v4_1.cpp +++ b/src/cbshm/src/central_adapters/v4_1.cpp @@ -65,7 +65,6 @@ void Adapter::fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.idcode = leg.idcode; - cur.idcode = leg.idcode; copyArr(cur.ident, leg.ident); cur.chanbase = leg.chanbase; cur.chancount = leg.chancount; @@ -395,7 +394,7 @@ void Adapter::fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const { fromLegacy(cur.refelecinfo, leg.refelecinfo[instrument_idx]); copyArr(cur.chaninfo, leg.chaninfo, this, &Adapter::fromLegacy); copyArr(cur.asBasis, leg.isSortingOptions.asBasis, this, &Adapter::fromLegacy); - // copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); // TODO: For some reason, this contains memory that's innaccessible + copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); // TODO: Move native isSortingOptions fields into a struct fromLegacy(cur.pktDetect, leg.isSortingOptions.pktDetect); fromLegacy(cur.pktArtifReject, leg.isSortingOptions.pktArtifReject); @@ -904,7 +903,7 @@ void Adapter::toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur void Adapter::toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const { toLegacy(leg.cbpkt_header, cur.cbpkt_header); - copyArr(leg.fPattern, leg.fPattern); + copyArr(leg.fPattern, cur.fPattern); leg.nPeak = cur.nPeak; leg.nValley = cur.nValley; copyArr(leg.wave, cur.wave); diff --git a/src/cbshm/src/central_adapters/v4_2.cpp b/src/cbshm/src/central_adapters/v4_2.cpp index 8049511c..0fbe9ef1 100644 --- a/src/cbshm/src/central_adapters/v4_2.cpp +++ b/src/cbshm/src/central_adapters/v4_2.cpp @@ -65,7 +65,6 @@ void Adapter::fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const fromLegacy(cur.cbpkt_header, leg.cbpkt_header); cur.proc = leg.proc; cur.idcode = leg.idcode; - cur.idcode = leg.idcode; copyArr(cur.ident, leg.ident); cur.chanbase = leg.chanbase; cur.chancount = leg.chancount; @@ -395,7 +394,7 @@ void Adapter::fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const { fromLegacy(cur.refelecinfo, leg.refelecinfo[instrument_idx]); copyArr(cur.chaninfo, leg.chaninfo, this, &Adapter::fromLegacy); copyArr(cur.asBasis, leg.isSortingOptions.asBasis, this, &Adapter::fromLegacy); - // copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); // TODO: For some reason, this contains memory that's innaccessible + copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); // TODO: Move native isSortingOptions fields into a struct fromLegacy(cur.pktDetect, leg.isSortingOptions.pktDetect); fromLegacy(cur.pktArtifReject, leg.isSortingOptions.pktArtifReject); @@ -905,7 +904,7 @@ void Adapter::toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur void Adapter::toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const { toLegacy(leg.cbpkt_header, cur.cbpkt_header); - copyArr(leg.fPattern, leg.fPattern); + copyArr(leg.fPattern, cur.fPattern); leg.nPeak = cur.nPeak; leg.nValley = cur.nValley; copyArr(leg.wave, cur.wave); diff --git a/src/cbshm/src/shmem_session.cpp b/src/cbshm/src/shmem_session.cpp index 9e9a4caa..3bff2f73 100644 --- a/src/cbshm/src/shmem_session.cpp +++ b/src/cbshm/src/shmem_session.cpp @@ -95,6 +95,34 @@ inline uint32_t shm_load_relaxed_u32(const uint32_t* p) { #endif } +// The seven shared-memory segment names for a session. +struct SegmentNames { + std::string cfg, rec, xmt, xmt_local, status, spk, signal; +}; + +// Synthesize segment names for the given layout. The meaning of name_qualifier +// depends on the layout: +// +// CENTRAL uses Central's fixed, well-known names. name_qualifier is the Central +// *instance* suffix appended to each base name ("" selects the primary instance +// cbCFGbuffer; "1" selects cbCFGbuffer1, etc.). Instruments within an instance +// are distinguished by index within the buffers, not by name. +// +// NATIVE uses per-device segment names of the form +// "cbshm__", where name_qualifier is the device token +// (e.g. "hub1"), matching the names a CereLink STANDALONE publishes. +inline SegmentNames makeSegmentNames(ShmemLayout layout, const std::string& name_qualifier) { + if (layout == ShmemLayout::CENTRAL) { + const std::string& s = name_qualifier; // instance suffix + return SegmentNames{"cbCFGbuffer" + s, "cbRECbuffer" + s, "XmtGlobal" + s, + "XmtLocal" + s, "cbSTATUSbuffer" + s, "cbSPKbuffer" + s, + "cbSIGNALevent" + s}; + } + auto seg = [&](const char* s) { return "cbshm_" + name_qualifier + "_" + s; }; + return SegmentNames{seg("config"), seg("receive"), seg("xmt_global"), seg("xmt_local"), + seg("status"), seg("spike"), seg("signal")}; +} + } // namespace /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -802,8 +830,14 @@ struct ShmemSession::Impl { // Convert application version to protocol version switch(major_version) { + default: + return Result::ok(CBPROTO_PROTOCOL_CURRENT); + // return Result::error("Unrecognized major version number in version '" + app_version + "'" ); case 7: switch (minor_version) { + default: + return Result::ok(CBPROTO_PROTOCOL_CURRENT); + // return Result::error("Unrecognized minor version number in version '" + app_version + "'"); case 8: return Result::ok(CBPROTO_PROTOCOL_CURRENT); case 7: @@ -814,8 +848,6 @@ struct ShmemSession::Impl { return Result::ok(CBPROTO_PROTOCOL_400); case 0: return Result::ok(CBPROTO_PROTOCOL_311); - default: - return Result::error("Unrecognized minor version number in version '" + app_version + "'"); } break; case 6: @@ -830,8 +862,6 @@ struct ShmemSession::Impl { /* fallthrough */ case 1: return Result::error("Unsupported major version number in version '" + app_version + "'. Please update Central to a newer version"); - default: - return Result::error("Unrecognized major version number in version '" + app_version + "'" ); } #else return Result::error("Compatibility with Central requires Windows"); @@ -863,22 +893,22 @@ ShmemSession::~ShmemSession() = default; ShmemSession::ShmemSession(ShmemSession&& other) noexcept = default; ShmemSession& ShmemSession::operator=(ShmemSession&& other) noexcept = default; -Result ShmemSession::create(cbproto::InstrumentId id, const std::string& cfg_name, const std::string& rec_name, - const std::string& xmt_name, const std::string& xmt_local_name, - const std::string& status_name, const std::string& spk_name, - const std::string& signal_event_name, Mode mode, - ShmemLayout layout) { +Result ShmemSession::create(Mode mode, ShmemLayout layout, + const std::string& name_qualifier, + cbproto::InstrumentId id) { + SegmentNames names = makeSegmentNames(layout, name_qualifier); + ShmemSession session; - session.m_impl->inst = id; - session.m_impl->cfg_name = cfg_name; - session.m_impl->rec_name = rec_name; - session.m_impl->xmt_name = xmt_name; - session.m_impl->xmt_local_name = xmt_local_name; - session.m_impl->status_name = status_name; - session.m_impl->spk_name = spk_name; - session.m_impl->signal_event_name = signal_event_name; + session.m_impl->cfg_name = names.cfg; + session.m_impl->rec_name = names.rec; + session.m_impl->xmt_name = names.xmt; + session.m_impl->xmt_local_name = names.xmt_local; + session.m_impl->status_name = names.status; + session.m_impl->spk_name = names.spk; + session.m_impl->signal_event_name = names.signal; session.m_impl->mode = mode; session.m_impl->layout = layout; + session.m_impl->inst = id; auto result = session.m_impl->open(); if (result.isError()) { From d93a4f517b739273abcc50fbd244452a5aa1b30b Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Thu, 25 Jun 2026 15:21:48 -0600 Subject: [PATCH 39/62] Migrate all tests except test_shmem_session to the new API --- tests/integration/test_sdk_configuration.cpp | 22 ++-- tests/integration/test_sdk_data_reception.cpp | 6 +- tests/unit/test_native_types.cpp | 105 +++++++++--------- tests/unit/test_sdk_session.cpp | 5 +- 4 files changed, 68 insertions(+), 70 deletions(-) diff --git a/tests/integration/test_sdk_configuration.cpp b/tests/integration/test_sdk_configuration.cpp index d80d1860..aeb48a35 100644 --- a/tests/integration/test_sdk_configuration.cpp +++ b/tests/integration/test_sdk_configuration.cpp @@ -95,10 +95,10 @@ TEST_F(SessionLifecycleTest, ProcIdent) { TEST_F(SessionLifecycleTest, SysInfo) { auto result = createNPlaySession(); ASSERT_TRUE(result.isOk()) << result.error(); - auto* sysinfo = result.value().getSysInfo(); - EXPECT_NE(sysinfo, nullptr); - if (sysinfo) { - EXPECT_GT(sysinfo->sysfreq, 0u); + auto sysinfo = result.value().getSysInfo(); + EXPECT_TRUE(sysinfo.isOk()) << sysinfo.error(); + if (sysinfo.isOk()) { + EXPECT_GT(sysinfo.value().sysfreq, 0u); } } @@ -130,8 +130,8 @@ TEST_F(ChannelSampleGroupTest, SetFrontend30kHz) { std::this_thread::sleep_for(std::chrono::milliseconds(500)); // Verify via group info - auto* group_info = session.getGroupInfo(static_cast(SampleRate::SR_30kHz)); - EXPECT_NE(group_info, nullptr); + auto group_info = session.getGroupInfo(static_cast(SampleRate::SR_30kHz)); + EXPECT_TRUE(group_info.isOk()) << group_info.error(); } TEST_F(ChannelSampleGroupTest, SetAndVerifyViaChannelField) { @@ -194,10 +194,10 @@ TEST_F(ChannelInfoTest, GetChanInfo) { auto result = createNPlaySession(); ASSERT_TRUE(result.isOk()) << result.error(); - const cbPKT_CHANINFO* info = result.value().getChanInfo(1); - ASSERT_NE(info, nullptr); + auto info = result.value().getChanInfo(1); + ASSERT_TRUE(info.isOk()) << info.error(); // Channel 1 should be a front-end channel with capabilities - EXPECT_GT(info->chancaps, 0u); + EXPECT_GT(info.value().chancaps, 0u); } TEST_F(ChannelInfoTest, GetChanInfoInvalid) { @@ -326,8 +326,8 @@ TEST_F(FilterInfoTest, GetFilterInfo) { ASSERT_TRUE(result.isOk()) << result.error(); // Filter 0 exists (even if empty) - const cbPKT_FILTINFO* info = result.value().getFilterInfo(0); - // May be nullptr if no filters configured, but should not crash + auto info = result.value().getFilterInfo(0); + // May have error if no filters configured, but should not crash } TEST_F(FilterInfoTest, GetFilterInfoInvalid) { diff --git a/tests/integration/test_sdk_data_reception.cpp b/tests/integration/test_sdk_data_reception.cpp index 151a3f36..927e462d 100644 --- a/tests/integration/test_sdk_data_reception.cpp +++ b/tests/integration/test_sdk_data_reception.cpp @@ -251,9 +251,9 @@ TEST_F(MultiRateTest, TwoRatesSimultaneously) { ASSERT_GE(ids.size(), 4u); for (size_t i = 2; i < 4; ++i) { - const auto* info = session.getChanInfo(ids[i]); - ASSERT_NE(info, nullptr) << "getChanInfo returned null for channel " << ids[i]; - cbPKT_CHANINFO modified = *info; + auto info = session.getChanInfo(ids[i]); + ASSERT_TRUE(info.isOk()) << info.error() << " (getChanInfo failed for channel " << ids[i] << ")"; + cbPKT_CHANINFO modified = info.value(); modified.smpgroup = static_cast(SampleRate::SR_1kHz); // Must set the packet type to SET (not REP) for the device to accept it modified.cbpkt_header.type = cbPKTTYPE_CHANSET; diff --git a/tests/unit/test_native_types.cpp b/tests/unit/test_native_types.cpp index 8a132542..002dc043 100644 --- a/tests/unit/test_native_types.cpp +++ b/tests/unit/test_native_types.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include @@ -37,13 +37,13 @@ TEST(NativeTypesTest, TransmitSlotSize) { } TEST(NativeTypesTest, SpikeCacheConstants) { - EXPECT_EQ(NATIVE_cbPKT_SPKCACHEPKTCNT, CENTRAL_cbPKT_SPKCACHEPKTCNT); + EXPECT_EQ(NATIVE_cbPKT_SPKCACHEPKTCNT, central::cbPKT_SPKCACHEPKTCNT); EXPECT_EQ(NATIVE_cbPKT_SPKCACHELINECNT, NATIVE_NUM_ANALOG_CHANS); EXPECT_EQ(NATIVE_cbPKT_SPKCACHELINECNT, 272u); } TEST(NativeTypesTest, ReceiveBufferLengthMatchesCbproto) { - EXPECT_EQ(NATIVE_cbRECBUFFLEN, cbRECBUFFLEN); + EXPECT_EQ(NATIVE_cbRECBUFFLEN, NATIVE_cbRECBUFFLEN); } /// @} @@ -55,7 +55,7 @@ TEST(NativeTypesTest, ReceiveBufferLengthMatchesCbproto) { TEST(NativeTypesTest, NativeConfigBufferSmallerThanCentral) { // Native config buffer should be significantly smaller than Central's size_t native_size = sizeof(NativeConfigBuffer); - size_t central_size = sizeof(CentralConfigBuffer); + size_t central_size = sizeof(central::cbCFGBUFF); EXPECT_LT(native_size, central_size) << "Native config buffer (" << native_size << " bytes) should be smaller than " @@ -68,7 +68,7 @@ TEST(NativeTypesTest, NativeConfigBufferSmallerThanCentral) { TEST(NativeTypesTest, NativeSpikeBufferSmallerThanCentral) { size_t native_size = sizeof(NativeSpikeBuffer); - size_t central_size = sizeof(CentralSpikeBuffer); + size_t central_size = sizeof(central::cbSPKBUFF); EXPECT_LT(native_size, central_size) << "Native spike buffer (" << native_size << " bytes) should be smaller than " @@ -77,7 +77,7 @@ TEST(NativeTypesTest, NativeSpikeBufferSmallerThanCentral) { TEST(NativeTypesTest, NativeTransmitBufferSmallerThanCentral) { size_t native_size = sizeof(NativeTransmitBuffer); - size_t central_size = sizeof(CentralTransmitBuffer); + size_t central_size = sizeof(central::cbXMTBUFF); EXPECT_LT(native_size, central_size) << "Native transmit buffer (" << native_size << " bytes) should be smaller than " @@ -86,7 +86,7 @@ TEST(NativeTypesTest, NativeTransmitBufferSmallerThanCentral) { TEST(NativeTypesTest, NativeLocalTransmitBufferSmallerThanCentral) { size_t native_size = sizeof(NativeTransmitBufferLocal); - size_t central_size = sizeof(CentralTransmitBufferLocal); + size_t central_size = sizeof(central::cbXMTBUFFLOCAL); EXPECT_LT(native_size, central_size) << "Native local transmit buffer (" << native_size << " bytes) should be smaller than " @@ -174,50 +174,51 @@ TEST(NativeTypesTest, PCStatusLayout) { /// @name CentralLegacyCFGBUFF Tests /// @{ -TEST(CentralLegacyTypesTest, SizeCloseToConfigBuffer) { - // CentralLegacyCFGBUFF and CentralConfigBuffer should be close in size. - // Differences: - // CentralConfigBuffer has instrument_status[4] (+16 bytes), no optiontable/colortable move (neutral) - // CentralLegacyCFGBUFF omits hwndCentral (saves ~8 bytes) and instrument_status (saves 16 bytes) - // isLnc position differs but size is the same - // So the difference should be small (under 1KB) - size_t legacy_size = sizeof(CentralLegacyCFGBUFF); - size_t config_size = sizeof(CentralConfigBuffer); - - // Both should be in the multi-MB range - EXPECT_GT(legacy_size, 1 * 1024 * 1024u) << "Legacy config buffer seems too small: " << legacy_size; - EXPECT_GT(config_size, 1 * 1024 * 1024u) << "Config buffer seems too small: " << config_size; - - // The difference should be small (instrument_status[4] = 16 bytes) - size_t diff = (legacy_size > config_size) ? (legacy_size - config_size) : (config_size - legacy_size); - EXPECT_LT(diff, 1024u) - << "Legacy (" << legacy_size << ") and CereLink (" << config_size - << ") config buffers differ by " << diff << " bytes (expected < 1KB)"; -} - -TEST(CentralLegacyTypesTest, FieldOrderMatchesCentral) { - // Verify that optiontable comes right after sysflags (Central's layout) - // In CereLink's cbConfigBuffer, optiontable is at the END - // Heap-allocate: CentralLegacyCFGBUFF is multi-MB (too large for stack) - auto legacy = std::make_unique(); - std::memset(legacy.get(), 0, sizeof(CentralLegacyCFGBUFF)); - - // Access fields to verify they compile and are accessible - legacy->version = 42; - legacy->sysflags = 1; - legacy->optiontable = {}; - legacy->colortable = {}; - legacy->sysinfo = {}; - legacy->procinfo[0] = {}; - legacy->procinfo[3] = {}; - legacy->bankinfo[0][0] = {}; - legacy->chaninfo[0] = {}; - legacy->chaninfo[CENTRAL_cbMAXCHANS - 1] = {}; - legacy->isLnc[0] = {}; - legacy->isLnc[3] = {}; - legacy->fileinfo = {}; - - EXPECT_EQ(legacy->version, 42u); -} +// TODO: REPLACE WITH EXTENSIVE TESTING OF cbCFGBUFF (and other central-specific types) +// TEST(CentralLegacyTypesTest, SizeCloseToConfigBuffer) { +// // CentralLegacyCFGBUFF and CentralConfigBuffer should be close in size. +// // Differences: +// // CentralConfigBuffer has instrument_status[4] (+16 bytes), no optiontable/colortable move (neutral) +// // CentralLegacyCFGBUFF omits hwndCentral (saves ~8 bytes) and instrument_status (saves 16 bytes) +// // isLnc position differs but size is the same +// // So the difference should be small (under 1KB) +// size_t legacy_size = sizeof(central::cbCFGBUFF); +// size_t config_size = sizeof(CentralConfigBuffer); +// +// // Both should be in the multi-MB range +// EXPECT_GT(legacy_size, 1 * 1024 * 1024u) << "Legacy config buffer seems too small: " << legacy_size; +// EXPECT_GT(config_size, 1 * 1024 * 1024u) << "Config buffer seems too small: " << config_size; +// +// // The difference should be small (instrument_status[4] = 16 bytes) +// size_t diff = (legacy_size > config_size) ? (legacy_size - config_size) : (config_size - legacy_size); +// EXPECT_LT(diff, 1024u) +// << "Legacy (" << legacy_size << ") and CereLink (" << config_size +// << ") config buffers differ by " << diff << " bytes (expected < 1KB)"; +// } +// +// TEST(CentralLegacyTypesTest, FieldOrderMatchesCentral) { +// // Verify that optiontable comes right after sysflags (Central's layout) +// // In CereLink's cbConfigBuffer, optiontable is at the END +// // Heap-allocate: CentralLegacyCFGBUFF is multi-MB (too large for stack) +// auto legacy = std::make_unique(); +// std::memset(legacy.get(), 0, sizeof(CentralLegacyCFGBUFF)); +// +// // Access fields to verify they compile and are accessible +// legacy->version = 42; +// legacy->sysflags = 1; +// legacy->optiontable = {}; +// legacy->colortable = {}; +// legacy->sysinfo = {}; +// legacy->procinfo[0] = {}; +// legacy->procinfo[3] = {}; +// legacy->bankinfo[0][0] = {}; +// legacy->chaninfo[0] = {}; +// legacy->chaninfo[CENTRAL_cbMAXCHANS - 1] = {}; +// legacy->isLnc[0] = {}; +// legacy->isLnc[3] = {}; +// legacy->fileinfo = {}; +// +// EXPECT_EQ(legacy->version, 42u); +// } /// @} diff --git a/tests/unit/test_sdk_session.cpp b/tests/unit/test_sdk_session.cpp index 2cdc92d8..bdf194cc 100644 --- a/tests/unit/test_sdk_session.cpp +++ b/tests/unit/test_sdk_session.cpp @@ -364,10 +364,7 @@ TEST_F(SdkSessionTest, PacketSize_Calculation) { TEST_F(SdkSessionTest, TransmitCallback_RoundTrip) { // Create shared memory session for testing (use short name to avoid length limits) std::string name = "xmt_rt"; - auto shmem_result = cbshm::ShmemSession::create( - name, name + "_r", name + "_x", name + "_xl", - name + "_s", name + "_p", name + "_g", - cbshm::Mode::STANDALONE); + auto shmem_result = cbshm::ShmemSession::create(cbshm::Mode::STANDALONE, cbshm::ShmemLayout::NATIVE, name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(shmem_result.isOk()) << "Failed to create shmem: " << shmem_result.error(); auto shmem = std::move(shmem_result.value()); From 335b1a05ba52eb8a62f536f620f79bbee680aa21 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Thu, 25 Jun 2026 16:24:57 -0600 Subject: [PATCH 40/62] FIX: id/idx discrepencies --- src/cbsdk/src/sdk_session.cpp | 16 ++++++++-------- src/cbshm/include/cbshm/shmem_session.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/cbsdk/src/sdk_session.cpp b/src/cbsdk/src/sdk_session.cpp index d46aba39..71ba720d 100644 --- a/src/cbsdk/src/sdk_session.cpp +++ b/src/cbsdk/src/sdk_session.cpp @@ -300,7 +300,7 @@ struct SdkSession::Impl { // written to shmem (device_config is owned by the receive thread and // we avoid writing to it from other threads). if (shmem_session && chan_id >= 1 && chan_id <= cbMAXCHANS) { - return shmem_session->getChanInfo(chan_id); + return shmem_session->getChanInfo(chan_id - 1); } // Fallback to device_config (no shmem available) if (device_session) @@ -396,7 +396,7 @@ struct SdkSession::Impl { const auto* p = device_session->getChanInfo(chan_id); if (p && p->chan > 0) { ci = *p; valid = true; } } else if (shmem_session) { - auto r = shmem_session->getChanInfo(chan_id); + auto r = shmem_session->getChanInfo(chan_id - 1); if (r.isOk() && r.value().chan > 0) { ci = r.value(); valid = true; } } if (!valid) continue; @@ -413,7 +413,7 @@ struct SdkSession::Impl { ci.label[sizeof(ci.label) - 1] = '\0'; if (shmem_session) { - shmem_session->setChanInfo(chan_id, ci); + shmem_session->setChanInfo(chan_id - 1, ci); } } } @@ -1329,15 +1329,15 @@ uint32_t SdkSession::getGroupChannelList(uint32_t group_id, uint16_t* list, uint // Prefer device_config (updated in updateConfigFromBuffer before the // sendAndWait / SYSREP sync barrier fires). shmem chaninfo may lag // slightly because SDK callbacks run after the sync notification. - const cbPKT_CHANINFO& ci{}; + cbPKT_CHANINFO ci{}; if (m_impl->device_session) { - const auto* res = m_impl->device_session->getChanInfo(chan - 1); + const auto* res = m_impl->device_session->getChanInfo(chan); if (!res) continue; - const auto& ci = *res; + ci = *res; } else { auto res = getChanInfo(chan); if (res.isError()) continue; - const auto& ci = res.value(); + ci = res.value(); } bool in_group; @@ -1360,7 +1360,7 @@ Result SdkSession::getFilterInfo(const uint32_t filter_id) const return Result::ok(config.filtinfo[filter_id]); } if (m_impl->shmem_session) { - return m_impl->shmem_session->getFilterInfo(filter_id); + return m_impl->shmem_session->getFilterInfo(filter_id + 1); } return Result::error("Filter information not available"); } diff --git a/src/cbshm/include/cbshm/shmem_session.h b/src/cbshm/include/cbshm/shmem_session.h index e56ba1b2..04f19443 100644 --- a/src/cbshm/include/cbshm/shmem_session.h +++ b/src/cbshm/include/cbshm/shmem_session.h @@ -189,13 +189,13 @@ class ShmemSession { Result setProcInfo(const cbPKT_PROCINFO& info); /// @brief Set bank information - /// @param bank Bank number (0-based) + /// @param bank Bank number (1-based, as used in cbPKT_BANKINFO) /// @param info cbPKT_BANKINFO structure to write /// @return Result indicating success or failure Result setBankInfo(uint32_t bank, const cbPKT_BANKINFO& info); /// @brief Set filter information - /// @param filter Filter number (0-based) + /// @param filter Filter number (1-based, as used in cbPKT_FILTINFO) /// @param info cbPKT_FILTINFO structure to write /// @return Result indicating success or failure Result setFilterInfo(uint32_t filter, const cbPKT_FILTINFO& info); From 6abaf0736a4602e9aa4dc3d902efe478a80695e3 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Fri, 26 Jun 2026 17:19:32 -0600 Subject: [PATCH 41/62] Alter all pre-existing ShmemSession tests for the new API ShmemSession is now per-instrument, so multi-instrument tests have been temporarily removed. Tests for enumerating active instruments or rejecting 'other' instruments have been removed. Several methods no longer accept an InstrumentId. These changes may be reverted in the future if the per-instrument ShmemSession model is reverted. --- tests/unit/test_shmem_session.cpp | 653 +++++++++--------------------- 1 file changed, 184 insertions(+), 469 deletions(-) diff --git a/tests/unit/test_shmem_session.cpp b/tests/unit/test_shmem_session.cpp index 92ba7abd..35b348e3 100644 --- a/tests/unit/test_shmem_session.cpp +++ b/tests/unit/test_shmem_session.cpp @@ -50,7 +50,7 @@ int ShmemSessionTest::test_counter = 0; /// @{ TEST_F(ShmemSessionTest, CreateStandalone) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()) << "Failed to create standalone session: " << result.error(); auto& session = result.value(); @@ -60,7 +60,7 @@ TEST_F(ShmemSessionTest, CreateStandalone) { TEST_F(ShmemSessionTest, CreateAndDestroy) { { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); EXPECT_TRUE(result.value().isOpen()); } @@ -68,7 +68,7 @@ TEST_F(ShmemSessionTest, CreateAndDestroy) { } TEST_F(ShmemSessionTest, MoveConstruction) { - auto result1 = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result1 = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result1.isOk()); // Move construction @@ -77,8 +77,8 @@ TEST_F(ShmemSessionTest, MoveConstruction) { } TEST_F(ShmemSessionTest, MoveAssignment) { - auto result1 = ShmemSession::create(test_name + "_1", test_name + "_1_rec", test_name + "_1_xmt", test_name + "_1_xmt_local", test_name + "_1_status", test_name + "_1_spk", test_name + "_1_signal", Mode::STANDALONE); - auto result2 = ShmemSession::create(test_name + "_2", test_name + "_2_rec", test_name + "_2_xmt", test_name + "_2_xmt_local", test_name + "_2_status", test_name + "_2_spk", test_name + "_2_signal", Mode::STANDALONE); + auto result1 = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name + "_1", cbproto::InstrumentId::fromOneBased(cbNSP1)); + auto result2 = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name + "_2", cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result1.isOk()); ASSERT_TRUE(result2.isOk()); @@ -94,80 +94,45 @@ TEST_F(ShmemSessionTest, MoveAssignment) { /// @{ TEST_F(ShmemSessionTest, InstrumentStatusInitiallyInactive) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); - ASSERT_TRUE(result.isOk()); - auto& session = result.value(); - // All instruments should be inactive initially for (uint8_t i = 1; i <= cbMAXOPEN; ++i) { - auto id = InstrumentId::fromOneBased(i); - auto active_result = session.isInstrumentActive(id); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, InstrumentId::fromOneBased(i)); + ASSERT_TRUE(result.isOk()); + auto& session = result.value(); + auto active_result = session.isInstrumentActive(); ASSERT_TRUE(active_result.isOk()); EXPECT_FALSE(active_result.value()) << "Instrument " << (int)i << " should be inactive"; } } TEST_F(ShmemSessionTest, SetInstrumentActive) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); // Activate first instrument - auto id1 = InstrumentId::fromOneBased(cbNSP1); - auto set_result = session.setInstrumentActive(id1, true); + auto set_result = session.setInstrumentActive(true); ASSERT_TRUE(set_result.isOk()); // Verify it's active - auto active_result = session.isInstrumentActive(id1); + auto active_result = session.isInstrumentActive(); ASSERT_TRUE(active_result.isOk()); EXPECT_TRUE(active_result.value()); // Other instruments should still be inactive - auto id2 = InstrumentId::fromOneBased(cbNSP2); - auto active_result2 = session.isInstrumentActive(id2); + auto active_result2 = session.isInstrumentActive(); ASSERT_TRUE(active_result2.isOk()); EXPECT_FALSE(active_result2.value()); } -TEST_F(ShmemSessionTest, GetFirstActiveInstrument) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); - ASSERT_TRUE(result.isOk()); - auto& session = result.value(); - - // No active instruments initially - auto first_result = session.getFirstActiveInstrument(); - EXPECT_TRUE(first_result.isError()); - EXPECT_NE(first_result.error().find("No active"), std::string::npos); - - // Activate third instrument - auto id3 = InstrumentId::fromOneBased(cbNSP3); - ASSERT_TRUE(session.setInstrumentActive(id3, true).isOk()); - - // Should return third instrument (index 2, 1-based = 3) - first_result = session.getFirstActiveInstrument(); - ASSERT_TRUE(first_result.isOk()); - EXPECT_EQ(first_result.value().toOneBased(), cbNSP3); -} - -TEST_F(ShmemSessionTest, MultipleActiveInstruments) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); - ASSERT_TRUE(result.isOk()); - auto& session = result.value(); - - // Activate instruments 1 and 3 - ASSERT_TRUE(session.setInstrumentActive(InstrumentId::fromOneBased(cbNSP1), true).isOk()); - ASSERT_TRUE(session.setInstrumentActive(InstrumentId::fromOneBased(cbNSP3), true).isOk()); - - // First active should be cbNSP1 - auto first_result = session.getFirstActiveInstrument(); - ASSERT_TRUE(first_result.isOk()); - EXPECT_EQ(first_result.value().toOneBased(), cbNSP1); - - // Verify both are active - EXPECT_TRUE(session.isInstrumentActive(InstrumentId::fromOneBased(cbNSP1)).value()); - EXPECT_TRUE(session.isInstrumentActive(InstrumentId::fromOneBased(cbNSP3)).value()); - EXPECT_FALSE(session.isInstrumentActive(InstrumentId::fromOneBased(cbNSP2)).value()); -} +// TODO: getFirstActiveInstrument() and multi-instrument-per-session tracking were +// removed with the move to per-instrument ShmemSession instances. A ShmemSession +// now represents a single instrument, so "first active instrument" discovery and +// activating multiple instruments through one session no longer apply. These tests +// should be reworked at the layer that now enumerates instruments across sessions. +// +// TEST_F(ShmemSessionTest, GetFirstActiveInstrument) { ... } +// TEST_F(ShmemSessionTest, MultipleActiveInstruments) { ... } /// @} @@ -176,102 +141,56 @@ TEST_F(ShmemSessionTest, MultipleActiveInstruments) { /// @{ TEST_F(ShmemSessionTest, SetGetProcInfo_Instrument0) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); - // Set PROCINFO for instrument 0 (cbNSP1) + // Set PROCINFO for this session's instrument (cbNSP1) cbPKT_PROCINFO info; std::memset(&info, 0, sizeof(info)); info.proc = 1; info.chancount = 256; - auto id = InstrumentId::fromPacketField(0); - ASSERT_TRUE(session.setProcInfo(id, info).isOk()); - ASSERT_TRUE(session.setInstrumentActive(id, true).isOk()); + ASSERT_TRUE(session.setProcInfo(info).isOk()); + ASSERT_TRUE(session.setInstrumentActive(true).isOk()); - // THE KEY FIX: Should be stored at index 0 (instrument 0) - auto get_result = session.getProcInfo(id); + auto get_result = session.getProcInfo(); ASSERT_TRUE(get_result.isOk()); EXPECT_EQ(get_result.value().proc, 1); EXPECT_EQ(get_result.value().chancount, 256); // Instrument should be marked active - auto active_result = session.isInstrumentActive(id); + auto active_result = session.isInstrumentActive(); ASSERT_TRUE(active_result.isOk()); EXPECT_TRUE(active_result.value()); } -TEST_F(ShmemSessionTest, SetGetProcInfo_Instrument2) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); - ASSERT_TRUE(result.isOk()); - auto& session = result.value(); - - // Set PROCINFO for instrument 2 (cbNSP3) - cbPKT_PROCINFO info; - std::memset(&info, 0, sizeof(info)); - info.proc = 3; - info.chancount = 128; - - auto id = InstrumentId::fromPacketField(2); - ASSERT_TRUE(session.setProcInfo(id, info).isOk()); - - // THE KEY FIX: Should be stored at index 2, NOT index 0! - auto get_result = session.getProcInfo(id); - ASSERT_TRUE(get_result.isOk()); - EXPECT_EQ(get_result.value().proc, 3); - EXPECT_EQ(get_result.value().chancount, 128); - - // Verify it's NOT stored at index 0 - auto id0 = InstrumentId::fromPacketField(0); - auto get_result0 = session.getProcInfo(id0); - ASSERT_TRUE(get_result0.isOk()); - EXPECT_NE(get_result0.value().proc, 3); // Should not have this data -} - -TEST_F(ShmemSessionTest, SetGetProcInfo_MultipleInstruments) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); - ASSERT_TRUE(result.isOk()); - auto& session = result.value(); - - // Set PROCINFO for instruments 0, 1, and 3 - for (uint8_t inst : {0, 1, 3}) { - cbPKT_PROCINFO info; - std::memset(&info, 0, sizeof(info)); - info.proc = inst + 1; - info.chancount = 100 + inst; - - auto id = InstrumentId::fromPacketField(inst); - ASSERT_TRUE(session.setProcInfo(id, info).isOk()); - } - - // Verify each instrument has correct data at correct index - for (uint8_t inst : {0, 1, 3}) { - auto id = InstrumentId::fromPacketField(inst); - auto get_result = session.getProcInfo(id); - ASSERT_TRUE(get_result.isOk()); - EXPECT_EQ(get_result.value().proc, inst + 1); - EXPECT_EQ(get_result.value().chancount, 100 + inst); - } -} +// TODO: These tested the old single-session, multi-instrument indexing model +// ("THE KEY FIX" of routing by packet.instrument into procinfo[index]). With +// per-instrument ShmemSession instances a session owns exactly one instrument's +// config slot, so cross-instrument isolation within one session no longer exists. +// Equivalent coverage now lives in SetGetProcInfo_Instrument0 (per-instrument +// round-trip) and the CENTRAL per-instrument tests. +// +// TEST_F(ShmemSessionTest, SetGetProcInfo_Instrument2) { ... } +// TEST_F(ShmemSessionTest, SetGetProcInfo_MultipleInstruments) { ... } TEST_F(ShmemSessionTest, SetGetBankInfo) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); - // Set BANKINFO for instrument 1 (cbNSP2), bank 3 + // Set BANKINFO for bank 3 cbPKT_BANKINFO info; std::memset(&info, 0, sizeof(info)); info.proc = 2; info.bank = 3; info.chancount = 32; - auto id = InstrumentId::fromPacketField(1); - ASSERT_TRUE(session.setBankInfo(id, 3, info).isOk()); + ASSERT_TRUE(session.setBankInfo(3, info).isOk()); // Retrieve and verify - auto get_result = session.getBankInfo(id, 3); + auto get_result = session.getBankInfo(3); ASSERT_TRUE(get_result.isOk()); EXPECT_EQ(get_result.value().proc, 2); EXPECT_EQ(get_result.value().bank, 3); @@ -279,22 +198,21 @@ TEST_F(ShmemSessionTest, SetGetBankInfo) { } TEST_F(ShmemSessionTest, SetGetFilterInfo) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); - // Set FILTINFO for instrument 0 (cbNSP1), filter 5 + // Set FILTINFO for filter 5 cbPKT_FILTINFO info; std::memset(&info, 0, sizeof(info)); info.proc = 1; info.filt = 5; info.hpfreq = 250000; // 250 Hz in millihertz - auto id = InstrumentId::fromPacketField(0); - ASSERT_TRUE(session.setFilterInfo(id, 5, info).isOk()); + ASSERT_TRUE(session.setFilterInfo(5, info).isOk()); // Retrieve and verify - auto get_result = session.getFilterInfo(id, 5); + auto get_result = session.getFilterInfo(5); ASSERT_TRUE(get_result.isOk()); EXPECT_EQ(get_result.value().proc, 1); EXPECT_EQ(get_result.value().filt, 5); @@ -308,20 +226,19 @@ TEST_F(ShmemSessionTest, SetGetFilterInfo) { /// @{ TEST_F(ShmemSessionTest, GetProcInfo_NotFound) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); // Try to get PROCINFO before storing anything - auto id = InstrumentId::fromOneBased(cbNSP1); - auto get_result = session.getProcInfo(id); + auto get_result = session.getProcInfo(); // Should succeed but return zeroed data ASSERT_TRUE(get_result.isOk()); EXPECT_EQ(get_result.value().proc, 0); } TEST_F(ShmemSessionTest, SetAndGetProcInfo) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -332,12 +249,11 @@ TEST_F(ShmemSessionTest, SetAndGetProcInfo) { info.chancount = 512; info.bankcount = 24; - auto id = InstrumentId::fromOneBased(cbNSP2); - auto set_result = session.setProcInfo(id, info); + auto set_result = session.setProcInfo(info); ASSERT_TRUE(set_result.isOk()); // Retrieve and verify - auto get_result = session.getProcInfo(id); + auto get_result = session.getProcInfo(); ASSERT_TRUE(get_result.isOk()); EXPECT_EQ(get_result.value().proc, 2); EXPECT_EQ(get_result.value().chancount, 512); @@ -345,16 +261,13 @@ TEST_F(ShmemSessionTest, SetAndGetProcInfo) { } TEST_F(ShmemSessionTest, InvalidInstrumentId) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); - ASSERT_TRUE(result.isOk()); - auto& session = result.value(); - - // Try to use invalid instrument ID (0 is invalid, 1-4 are valid) + // The instrument ID is now fixed at session creation, so an invalid ID is + // rejected by create() rather than by individual accessors. auto invalid_id = InstrumentId::fromOneBased(0); EXPECT_FALSE(invalid_id.isValid()); - auto get_result = session.getProcInfo(invalid_id); - EXPECT_TRUE(get_result.isError()); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, invalid_id); + EXPECT_TRUE(result.isError()); } /// @} @@ -367,18 +280,18 @@ TEST_F(ShmemSessionTest, OperationsOnClosedSession) { // Create a session in a scope std::string name = test_name; { - auto result = ShmemSession::create(name, name + "_rec", name + "_xmt", name + "_xmt_local", name + "_status", name + "_spk", name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); } // Session is now closed // Try to create a new session with same name should work - auto result2 = ShmemSession::create(name, name + "_rec", name + "_xmt", name + "_xmt_local", name + "_status", name + "_spk", name + "_signal", Mode::STANDALONE); + auto result2 = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result2.isOk()); } TEST_F(ShmemSessionTest, StorePacket_InvalidInstrument) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -409,7 +322,7 @@ TEST_F(ShmemSessionTest, StorePacket_InvalidInstrument) { /// @{ TEST_F(ShmemSessionTest, StorePacket_ADAPTFILTINFO) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -436,7 +349,7 @@ TEST_F(ShmemSessionTest, StorePacket_ADAPTFILTINFO) { } TEST_F(ShmemSessionTest, StorePacket_REFELECFILTINFO) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -458,7 +371,7 @@ TEST_F(ShmemSessionTest, StorePacket_REFELECFILTINFO) { } TEST_F(ShmemSessionTest, StorePacket_SS_STATUS) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -479,7 +392,7 @@ TEST_F(ShmemSessionTest, StorePacket_SS_STATUS) { } TEST_F(ShmemSessionTest, StorePacket_SS_DETECT) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -500,7 +413,7 @@ TEST_F(ShmemSessionTest, StorePacket_SS_DETECT) { } TEST_F(ShmemSessionTest, StorePacket_SS_ARTIF_REJECT) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -521,7 +434,7 @@ TEST_F(ShmemSessionTest, StorePacket_SS_ARTIF_REJECT) { } TEST_F(ShmemSessionTest, StorePacket_SS_NOISE_BOUNDARY) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -555,7 +468,7 @@ TEST_F(ShmemSessionTest, StorePacket_SS_NOISE_BOUNDARY) { } TEST_F(ShmemSessionTest, StorePacket_SS_STATISTICS) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -576,7 +489,7 @@ TEST_F(ShmemSessionTest, StorePacket_SS_STATISTICS) { } TEST_F(ShmemSessionTest, StorePacket_SS_MODEL) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -614,7 +527,7 @@ TEST_F(ShmemSessionTest, StorePacket_SS_MODEL) { } TEST_F(ShmemSessionTest, StorePacket_FS_BASIS) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -647,7 +560,7 @@ TEST_F(ShmemSessionTest, StorePacket_FS_BASIS) { } TEST_F(ShmemSessionTest, StorePacket_LNC) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -669,7 +582,7 @@ TEST_F(ShmemSessionTest, StorePacket_LNC) { } TEST_F(ShmemSessionTest, StorePacket_FILECFG) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -703,7 +616,7 @@ TEST_F(ShmemSessionTest, StorePacket_FILECFG) { } TEST_F(ShmemSessionTest, StorePacket_NTRODEINFO) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -737,7 +650,7 @@ TEST_F(ShmemSessionTest, StorePacket_NTRODEINFO) { } TEST_F(ShmemSessionTest, StorePacket_WAVEFORM) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -775,7 +688,7 @@ TEST_F(ShmemSessionTest, StorePacket_WAVEFORM) { } TEST_F(ShmemSessionTest, StorePacket_NPLAY) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -799,7 +712,7 @@ TEST_F(ShmemSessionTest, StorePacket_NPLAY) { } TEST_F(ShmemSessionTest, StorePacket_NM_VideoSource) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -834,7 +747,7 @@ TEST_F(ShmemSessionTest, StorePacket_NM_VideoSource) { } TEST_F(ShmemSessionTest, StorePacket_NM_TrackableObject) { - auto result = ShmemSession::create(test_name, test_name + "_rec", test_name + "_xmt", test_name + "_xmt_local", test_name + "_status", test_name + "_spk", test_name + "_signal", Mode::STANDALONE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); @@ -873,10 +786,7 @@ class NativeShmemSessionTest : public ::testing::Test { // Helper to create a native STANDALONE session Result createNativeSession() { - return ShmemSession::create( - test_name + "_cfg", test_name + "_rec", test_name + "_xmt", - test_name + "_xmt_local", test_name + "_status", test_name + "_spk", - test_name + "_signal", Mode::STANDALONE, ShmemLayout::NATIVE); + return ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); } std::string test_name; @@ -902,8 +812,9 @@ TEST_F(NativeShmemSessionTest, NativeConfigBufferAccessor) { // Native layout should return native config buffer EXPECT_NE(session.getNativeConfigBuffer(), nullptr); - // Central accessor should return nullptr for native layout - EXPECT_EQ(session.getConfigBuffer(), nullptr); + // CENTRAL accessor should return an error for the native layout + auto buf = std::make_unique(); + EXPECT_TRUE(session.getLegacyConfigBuffer(*buf).isError()); } TEST_F(NativeShmemSessionTest, CreateAndDestroy) { @@ -915,42 +826,27 @@ TEST_F(NativeShmemSessionTest, CreateAndDestroy) { // Session destroyed, shared memory released } -TEST_F(NativeShmemSessionTest, SingleInstrumentOnly) { +// TODO: A ShmemSession is now per-instrument and carries no notion of rejecting +// "other" instruments or enumerating active ones. setInstrumentActive()/ +// isInstrumentActive() operate on the session's own instrument (see InstrumentToggle +// below), and getFirstActiveInstrument() was removed. Rework instrument enumeration +// at the layer that manages the set of sessions. +// +// TEST_F(NativeShmemSessionTest, SingleInstrumentOnly) { ... } +// TEST_F(NativeShmemSessionTest, GetFirstActiveInstrument) { ... } + +TEST_F(NativeShmemSessionTest, InstrumentToggle) { auto result = createNativeSession(); ASSERT_TRUE(result.isOk()) << result.error(); auto& session = result.value(); - // Instrument 1 (index 0) should work - auto id1 = InstrumentId::fromOneBased(1); - auto set_result = session.setInstrumentActive(id1, true); + // The session's own instrument can be toggled active/inactive. + auto set_result = session.setInstrumentActive(true); ASSERT_TRUE(set_result.isOk()); - auto active_result = session.isInstrumentActive(id1); + auto active_result = session.isInstrumentActive(); ASSERT_TRUE(active_result.isOk()); EXPECT_TRUE(active_result.value()); - - // Instrument 2 (index 1) should fail in native mode - auto id2 = InstrumentId::fromOneBased(2); - auto set_result2 = session.setInstrumentActive(id2, true); - EXPECT_TRUE(set_result2.isError()) << "Native mode should reject instrument index > 0"; -} - -TEST_F(NativeShmemSessionTest, GetFirstActiveInstrument) { - auto result = createNativeSession(); - ASSERT_TRUE(result.isOk()) << result.error(); - auto& session = result.value(); - - // No active instruments initially - auto first_result = session.getFirstActiveInstrument(); - EXPECT_TRUE(first_result.isError()); - - // Activate the only instrument - auto id = InstrumentId::fromOneBased(1); - ASSERT_TRUE(session.setInstrumentActive(id, true).isOk()); - - first_result = session.getFirstActiveInstrument(); - ASSERT_TRUE(first_result.isOk()); - EXPECT_EQ(first_result.value().toOneBased(), 1); } TEST_F(NativeShmemSessionTest, SetAndGetProcInfo) { @@ -964,30 +860,20 @@ TEST_F(NativeShmemSessionTest, SetAndGetProcInfo) { info.chancount = 284; info.bankcount = 16; - auto id = InstrumentId::fromOneBased(1); - ASSERT_TRUE(session.setProcInfo(id, info).isOk()); + ASSERT_TRUE(session.setProcInfo(info).isOk()); - auto get_result = session.getProcInfo(id); + auto get_result = session.getProcInfo(); ASSERT_TRUE(get_result.isOk()); EXPECT_EQ(get_result.value().proc, 1); EXPECT_EQ(get_result.value().chancount, 284); EXPECT_EQ(get_result.value().bankcount, 16); } -TEST_F(NativeShmemSessionTest, SetAndGetProcInfo_RejectMultiInstrument) { - auto result = createNativeSession(); - ASSERT_TRUE(result.isOk()) << result.error(); - auto& session = result.value(); - - cbPKT_PROCINFO info; - std::memset(&info, 0, sizeof(info)); - info.proc = 2; - - // Setting procinfo for instrument 2 should fail - auto id2 = InstrumentId::fromOneBased(2); - auto set_result = session.setProcInfo(id2, info); - EXPECT_TRUE(set_result.isError()); -} +// TODO: setProcInfo() no longer takes an instrument ID — a session writes to its +// own instrument's single procinfo slot — so there is no per-call instrument to +// reject. Multi-instrument rejection, if still desired, belongs at session creation. +// +// TEST_F(NativeShmemSessionTest, SetAndGetProcInfo_RejectMultiInstrument) { ... } TEST_F(NativeShmemSessionTest, SetAndGetBankInfo) { auto result = createNativeSession(); @@ -1000,10 +886,9 @@ TEST_F(NativeShmemSessionTest, SetAndGetBankInfo) { info.bank = 3; info.chancount = 32; - auto id = InstrumentId::fromOneBased(1); - ASSERT_TRUE(session.setBankInfo(id, 3, info).isOk()); + ASSERT_TRUE(session.setBankInfo(3, info).isOk()); - auto get_result = session.getBankInfo(id, 3); + auto get_result = session.getBankInfo(3); ASSERT_TRUE(get_result.isOk()); EXPECT_EQ(get_result.value().proc, 1); EXPECT_EQ(get_result.value().bank, 3); @@ -1021,10 +906,9 @@ TEST_F(NativeShmemSessionTest, SetAndGetFilterInfo) { info.filt = 5; info.hpfreq = 250000; - auto id = InstrumentId::fromOneBased(1); - ASSERT_TRUE(session.setFilterInfo(id, 5, info).isOk()); + ASSERT_TRUE(session.setFilterInfo(5, info).isOk()); - auto get_result = session.getFilterInfo(id, 5); + auto get_result = session.getFilterInfo(5); ASSERT_TRUE(get_result.isOk()); EXPECT_EQ(get_result.value().filt, 5); EXPECT_EQ(get_result.value().hpfreq, 250000); @@ -1143,18 +1027,12 @@ TEST_F(NativeShmemSessionTest, NspStatus) { ASSERT_TRUE(result.isOk()) << result.error(); auto& session = result.value(); - auto id = InstrumentId::fromOneBased(1); + // Set NSP status for this session's instrument + ASSERT_TRUE(session.setNspStatus(NativeNSPStatus::NSP_FOUND).isOk()); - // Set NSP status - ASSERT_TRUE(session.setNspStatus(id, NSPStatus::NSP_FOUND).isOk()); - - auto get_result = session.getNspStatus(id); + auto get_result = session.getNspStatus(); ASSERT_TRUE(get_result.isOk()); - EXPECT_EQ(get_result.value(), NSPStatus::NSP_FOUND); - - // Instrument 2 should fail - auto id2 = InstrumentId::fromOneBased(2); - EXPECT_TRUE(session.setNspStatus(id2, NSPStatus::NSP_FOUND).isError()); + EXPECT_EQ(get_result.value(), NativeNSPStatus::NSP_FOUND); } TEST_F(NativeShmemSessionTest, GeminiSystem) { @@ -1270,7 +1148,7 @@ TEST_F(NativeShmemSessionTest, NumTotalChans) { /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @name CENTRAL_COMPAT ShmemSession Tests +/// @name CENTRAL ShmemSession Tests /// @{ class CentralCompatShmemSessionTest : public ::testing::Test { @@ -1279,12 +1157,9 @@ class CentralCompatShmemSessionTest : public ::testing::Test { test_name = "test_compat_" + std::to_string(test_counter++); } - // Helper to create a CENTRAL_COMPAT STANDALONE session (for testing) + // Helper to create a CENTRAL STANDALONE session (for testing) Result createCompatSession() { - return ShmemSession::create( - test_name + "_cfg", test_name + "_rec", test_name + "_xmt", - test_name + "_xmt_local", test_name + "_status", test_name + "_spk", - test_name + "_signal", Mode::STANDALONE, ShmemLayout::CENTRAL_COMPAT); + return ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); } std::string test_name; @@ -1300,7 +1175,7 @@ TEST_F(CentralCompatShmemSessionTest, CreateCompatStandalone) { auto& session = result.value(); EXPECT_TRUE(session.isOpen()); EXPECT_EQ(session.getMode(), Mode::STANDALONE); - EXPECT_EQ(session.getLayout(), ShmemLayout::CENTRAL_COMPAT); + EXPECT_EQ(session.getLayout(), ShmemLayout::CENTRAL); } TEST_F(CentralCompatShmemSessionTest, LegacyConfigBufferAccessor) { @@ -1308,11 +1183,10 @@ TEST_F(CentralCompatShmemSessionTest, LegacyConfigBufferAccessor) { ASSERT_TRUE(result.isOk()) << result.error(); auto& session = result.value(); - // CENTRAL_COMPAT should return legacy config buffer - EXPECT_NE(session.getLegacyConfigBuffer(), nullptr); - // Central accessor should return nullptr for compat layout - EXPECT_EQ(session.getConfigBuffer(), nullptr); - // Native accessor should also return nullptr + // CENTRAL should provide a translated copy of the legacy config buffer + auto buf = std::make_unique(); + EXPECT_TRUE(session.getLegacyConfigBuffer(*buf).isOk()); + // Native accessor should return nullptr for the CENTRAL layout EXPECT_EQ(session.getNativeConfigBuffer(), nullptr); } @@ -1321,13 +1195,11 @@ TEST_F(CentralCompatShmemSessionTest, IsInstrumentActive_AlwaysTrue) { ASSERT_TRUE(result.isOk()) << result.error(); auto& session = result.value(); - // In CENTRAL_COMPAT mode, all instruments report as active - for (uint8_t i = 1; i <= cbMAXOPEN; ++i) { - auto id = InstrumentId::fromOneBased(i); - auto active_result = session.isInstrumentActive(id); - ASSERT_TRUE(active_result.isOk()); - EXPECT_TRUE(active_result.value()) << "Instrument " << (int)i << " should be active in compat mode"; - } + // In CENTRAL mode the session's instrument always reports as active + // (Central's layout has no instrument_status field). + auto active_result = session.isInstrumentActive(); + ASSERT_TRUE(active_result.isOk()); + EXPECT_TRUE(active_result.value()) << "Instrument should be active in compat mode"; } TEST_F(CentralCompatShmemSessionTest, SetInstrumentActive_ReturnsError) { @@ -1336,24 +1208,20 @@ TEST_F(CentralCompatShmemSessionTest, SetInstrumentActive_ReturnsError) { auto& session = result.value(); // Setting instrument status should fail (read-only in compat mode) - auto id = InstrumentId::fromOneBased(1); - auto set_result = session.setInstrumentActive(id, true); + auto set_result = session.setInstrumentActive(true); EXPECT_TRUE(set_result.isError()); } -TEST_F(CentralCompatShmemSessionTest, GetFirstActiveInstrument) { - auto result = createCompatSession(); - ASSERT_TRUE(result.isOk()) << result.error(); - auto& session = result.value(); - - // Should always return instrument 0 (first) - auto first_result = session.getFirstActiveInstrument(); - ASSERT_TRUE(first_result.isOk()); - EXPECT_EQ(first_result.value().toIndex(), 0); -} +// TODO: getFirstActiveInstrument() was removed; a CENTRAL session is bound to a +// single instrument at creation. Instrument enumeration now happens above the +// ShmemSession layer. +// +// TEST_F(CentralCompatShmemSessionTest, GetFirstActiveInstrument) { ... } TEST_F(CentralCompatShmemSessionTest, SetAndGetProcInfo) { - auto result = createCompatSession(); + // A CENTRAL session targets a single instrument; create one for instrument 2. + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, + test_name + "_cfg", InstrumentId::fromOneBased(2)); ASSERT_TRUE(result.isOk()) << result.error(); auto& session = result.value(); @@ -1363,13 +1231,11 @@ TEST_F(CentralCompatShmemSessionTest, SetAndGetProcInfo) { info.chancount = 512; info.bankcount = 24; - // Set procinfo for instrument 2 (index 1) - auto id = InstrumentId::fromOneBased(2); - auto set_result = session.setProcInfo(id, info); + auto set_result = session.setProcInfo(info); ASSERT_TRUE(set_result.isOk()); // Retrieve and verify - auto get_result = session.getProcInfo(id); + auto get_result = session.getProcInfo(); ASSERT_TRUE(get_result.isOk()); EXPECT_EQ(get_result.value().proc, 2); EXPECT_EQ(get_result.value().chancount, 512); @@ -1387,10 +1253,9 @@ TEST_F(CentralCompatShmemSessionTest, SetAndGetBankInfo) { info.bank = 5; info.chancount = 32; - auto id = InstrumentId::fromOneBased(1); - ASSERT_TRUE(session.setBankInfo(id, 5, info).isOk()); + ASSERT_TRUE(session.setBankInfo(5, info).isOk()); - auto get_result = session.getBankInfo(id, 5); + auto get_result = session.getBankInfo(5); ASSERT_TRUE(get_result.isOk()); EXPECT_EQ(get_result.value().proc, 1); EXPECT_EQ(get_result.value().bank, 5); @@ -1408,10 +1273,9 @@ TEST_F(CentralCompatShmemSessionTest, SetAndGetFilterInfo) { info.filt = 10; info.hpfreq = 300000; - auto id = InstrumentId::fromOneBased(1); - ASSERT_TRUE(session.setFilterInfo(id, 10, info).isOk()); + ASSERT_TRUE(session.setFilterInfo(10, info).isOk()); - auto get_result = session.getFilterInfo(id, 10); + auto get_result = session.getFilterInfo(10); ASSERT_TRUE(get_result.isOk()); EXPECT_EQ(get_result.value().filt, 10); EXPECT_EQ(get_result.value().hpfreq, 300000); @@ -1437,28 +1301,21 @@ TEST_F(CentralCompatShmemSessionTest, SetAndGetChanInfo) { EXPECT_STREQ(get_result.value().label, "elec100"); } -TEST_F(CentralCompatShmemSessionTest, InstrumentFilter_DefaultNoFilter) { - auto result = createCompatSession(); - ASSERT_TRUE(result.isOk()) << result.error(); - auto& session = result.value(); - - EXPECT_EQ(session.getInstrumentFilter(), -1); -} - -TEST_F(CentralCompatShmemSessionTest, InstrumentFilter_SetAndGet) { - auto result = createCompatSession(); - ASSERT_TRUE(result.isOk()) << result.error(); - auto& session = result.value(); - - session.setInstrumentFilter(2); - EXPECT_EQ(session.getInstrumentFilter(), 2); - - session.setInstrumentFilter(-1); - EXPECT_EQ(session.getInstrumentFilter(), -1); -} - -TEST_F(CentralCompatShmemSessionTest, InstrumentFilter_FiltersReceiveBuffer) { - auto result = createCompatSession(); +// TODO: The explicit setInstrumentFilter()/getInstrumentFilter() API was removed. +// readReceiveBuffer() now implicitly returns only packets for the session's own +// instrument (the instrument fixed at create()), so there is no separate filter to +// get/set and no "no filter" mode. The implicit filtering is covered by +// InstrumentFilter_ReturnsOwnInstrument below. +// +// TEST_F(CentralCompatShmemSessionTest, InstrumentFilter_DefaultNoFilter) { ... } +// TEST_F(CentralCompatShmemSessionTest, InstrumentFilter_SetAndGet) { ... } +// TEST_F(CentralCompatShmemSessionTest, InstrumentFilter_NoFilter_ReturnsAll) { ... } + +TEST_F(CentralCompatShmemSessionTest, InstrumentFilter_ReturnsOwnInstrument) { + // A session bound to instrument 2 should only see instrument-2 packets when + // reading the (shared) receive buffer. + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, + test_name + "_cfg", InstrumentId::fromIndex(2)); ASSERT_TRUE(result.isOk()) << result.error(); auto& session = result.value(); @@ -1482,10 +1339,7 @@ TEST_F(CentralCompatShmemSessionTest, InstrumentFilter_FiltersReceiveBuffer) { ASSERT_TRUE(session.storePacket(pkt).isOk()); } - // Set filter to instrument 2 only - session.setInstrumentFilter(2); - - // Read packets - should only get the one from instrument 2 + // Read packets - should only get the one from this session's instrument (2) cbPKT_GENERIC read_pkts[10]; size_t packets_read = 0; auto read_result = session.readReceiveBuffer(read_pkts, 10, packets_read); @@ -1495,35 +1349,6 @@ TEST_F(CentralCompatShmemSessionTest, InstrumentFilter_FiltersReceiveBuffer) { EXPECT_EQ(read_pkts[0].data_u32[0], 0xAA02u); } -TEST_F(CentralCompatShmemSessionTest, InstrumentFilter_NoFilter_ReturnsAll) { - auto result = createCompatSession(); - ASSERT_TRUE(result.isOk()) << result.error(); - auto& session = result.value(); - - // Store packets from different instruments with realistic timestamps - uint32_t dlen = 4; - - for (uint8_t inst = 0; inst < 3; ++inst) { - cbPKT_GENERIC pkt; - std::memset(&pkt, 0, sizeof(pkt)); - pkt.cbpkt_header.time = 2000000000ULL + inst * 33333ULL; // Realistic nanosecond timestamps - pkt.cbpkt_header.chid = 1; - pkt.cbpkt_header.instrument = inst; - pkt.cbpkt_header.type = 0x01; - pkt.cbpkt_header.dlen = dlen; - pkt.data_u32[0] = 0xBB00 + inst; - - ASSERT_TRUE(session.storePacket(pkt).isOk()); - } - - // No filter set (default -1) - should get all packets - cbPKT_GENERIC read_pkts[10]; - size_t packets_read = 0; - auto read_result = session.readReceiveBuffer(read_pkts, 10, packets_read); - ASSERT_TRUE(read_result.isOk()) << read_result.error(); - EXPECT_EQ(packets_read, 3u); -} - TEST_F(CentralCompatShmemSessionTest, TransmitQueueRoundTrip) { auto result = createCompatSession(); ASSERT_TRUE(result.isOk()) << result.error(); @@ -1562,10 +1387,7 @@ class CentralCompatProtocolTest : public ::testing::Test { } Result createCompatSession() { - return ShmemSession::create( - test_name + "_cfg", test_name + "_rec", test_name + "_xmt", - test_name + "_xmt_local", test_name + "_status", test_name + "_spk", - test_name + "_signal", Mode::STANDALONE, ShmemLayout::CENTRAL_COMPAT); + return ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); } std::string test_name; @@ -1592,13 +1414,15 @@ TEST_F(CentralCompatProtocolTest, ReadCurrentFormat_WithRealisticTimestamps) { EXPECT_EQ(session.getCompatProtocolVersion(), CBPROTO_PROTOCOL_CURRENT); - // Store packets (current format, written by storePacket) + // Store packets (current format, written by storePacket). The session is bound + // to instrument 0, and readReceiveBuffer only returns that instrument's packets, + // so store all three as instrument 0. for (uint8_t i = 0; i < 3; ++i) { cbPKT_GENERIC pkt; std::memset(&pkt, 0, sizeof(pkt)); pkt.cbpkt_header.time = 5000000000ULL + i * 33333ULL; pkt.cbpkt_header.chid = 1; - pkt.cbpkt_header.instrument = i; + pkt.cbpkt_header.instrument = 0; pkt.cbpkt_header.type = 0x01; pkt.cbpkt_header.dlen = 4; pkt.data_u32[0] = 0xCC00 + i; @@ -1614,93 +1438,28 @@ TEST_F(CentralCompatProtocolTest, ReadCurrentFormat_WithRealisticTimestamps) { EXPECT_EQ(packets_read, 3u); for (size_t i = 0; i < packets_read; ++i) { - EXPECT_EQ(read_pkts[i].cbpkt_header.instrument, i); + EXPECT_EQ(read_pkts[i].cbpkt_header.instrument, 0); EXPECT_EQ(read_pkts[i].data_u32[0], 0xCC00u + i); EXPECT_EQ(read_pkts[i].cbpkt_header.dlen, 4u); } } -/// @brief Test version detection: 3.11 -TEST_F(CentralCompatProtocolTest, DetectProtocol_311) { - auto writer_result = createCompatSession(); - ASSERT_TRUE(writer_result.isOk()) << writer_result.error(); - auto& writer = writer_result.value(); - - // Set version to 3.11 (major=3, minor=11) - auto* cfg = writer.getLegacyConfigBuffer(); - ASSERT_NE(cfg, nullptr); - cfg->procinfo[0].version = (3 << 16) | 11; - - std::string name = test_name; - auto reader_result = ShmemSession::create( - name + "_cfg", name + "_rec", name + "_xmt", - name + "_xmt_local", name + "_status", name + "_spk", - name + "_signal", Mode::CLIENT, ShmemLayout::CENTRAL_COMPAT); - ASSERT_TRUE(reader_result.isOk()) << reader_result.error(); - EXPECT_EQ(reader_result.value().getCompatProtocolVersion(), CBPROTO_PROTOCOL_311); -} - -/// @brief Test version detection: 4.0 -TEST_F(CentralCompatProtocolTest, DetectProtocol_400) { - // Create standalone, set version, then open CLIENT to pick it up - auto writer_result = createCompatSession(); - ASSERT_TRUE(writer_result.isOk()) << writer_result.error(); - auto& writer = writer_result.value(); - - auto* cfg = writer.getLegacyConfigBuffer(); - ASSERT_NE(cfg, nullptr); - cfg->procinfo[0].version = (4 << 16) | 0; // major=4, minor=0 - - std::string name = test_name; - auto reader_result = ShmemSession::create( - name + "_cfg", name + "_rec", name + "_xmt", - name + "_xmt_local", name + "_status", name + "_spk", - name + "_signal", Mode::CLIENT, ShmemLayout::CENTRAL_COMPAT); - ASSERT_TRUE(reader_result.isOk()) << reader_result.error(); - EXPECT_EQ(reader_result.value().getCompatProtocolVersion(), CBPROTO_PROTOCOL_400); -} - -/// @brief Test version detection: 4.1 -TEST_F(CentralCompatProtocolTest, DetectProtocol_410) { - auto writer_result = createCompatSession(); - ASSERT_TRUE(writer_result.isOk()) << writer_result.error(); - auto& writer = writer_result.value(); - - auto* cfg = writer.getLegacyConfigBuffer(); - ASSERT_NE(cfg, nullptr); - cfg->procinfo[0].version = (4 << 16) | 1; // major=4, minor=1 - - std::string name = test_name; - auto reader_result = ShmemSession::create( - name + "_cfg", name + "_rec", name + "_xmt", - name + "_xmt_local", name + "_status", name + "_spk", - name + "_signal", Mode::CLIENT, ShmemLayout::CENTRAL_COMPAT); - ASSERT_TRUE(reader_result.isOk()) << reader_result.error(); - EXPECT_EQ(reader_result.value().getCompatProtocolVersion(), CBPROTO_PROTOCOL_410); -} - -/// @brief Test version detection: 4.2 (current) -TEST_F(CentralCompatProtocolTest, DetectProtocol_Current_42) { - auto writer_result = createCompatSession(); - ASSERT_TRUE(writer_result.isOk()) << writer_result.error(); - auto& writer = writer_result.value(); - - auto* cfg = writer.getLegacyConfigBuffer(); - ASSERT_NE(cfg, nullptr); - cfg->procinfo[0].version = (4 << 16) | 2; // major=4, minor=2 - - std::string name = test_name; - auto reader_result = ShmemSession::create( - name + "_cfg", name + "_rec", name + "_xmt", - name + "_xmt_local", name + "_status", name + "_spk", - name + "_signal", Mode::CLIENT, ShmemLayout::CENTRAL_COMPAT); - ASSERT_TRUE(reader_result.isOk()) << reader_result.error(); - EXPECT_EQ(reader_result.value().getCompatProtocolVersion(), CBPROTO_PROTOCOL_CURRENT); -} +// TODO: Protocol-version detection no longer reads procinfo[0].version from a +// writable legacy config buffer (that pointer accessor was removed). It is now +// inferred from Central.exe's file version, which requires Windows and a running +// Central, so these CLIENT+CENTRAL detection tests can't be exercised here. They +// should be reworked as Windows-only integration tests against a real Central. +// +// TEST_F(CentralCompatProtocolTest, DetectProtocol_311) { ... } +// TEST_F(CentralCompatProtocolTest, DetectProtocol_400) { ... } +// TEST_F(CentralCompatProtocolTest, DetectProtocol_410) { ... } +// TEST_F(CentralCompatProtocolTest, DetectProtocol_Current_42) { ... } -/// @brief Test readReceiveBuffer with instrument filter and current-format packets +/// @brief Test readReceiveBuffer's implicit per-instrument filtering with current-format packets TEST_F(CentralCompatProtocolTest, InstrumentFilterWithCurrentProtocol) { - auto result = createCompatSession(); + // Bind the session to instrument 3; readReceiveBuffer returns only its packets. + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, + test_name + "_cfg", InstrumentId::fromIndex(3)); ASSERT_TRUE(result.isOk()) << result.error(); auto& session = result.value(); @@ -1720,9 +1479,6 @@ TEST_F(CentralCompatProtocolTest, InstrumentFilterWithCurrentProtocol) { ASSERT_TRUE(session.storePacket(pkt).isOk()); } - // Filter for instrument 3 only - session.setInstrumentFilter(3); - cbPKT_GENERIC read_pkts[10]; size_t packets_read = 0; auto read_result = session.readReceiveBuffer(read_pkts, 10, packets_read); @@ -1767,10 +1523,7 @@ TEST_F(CentralCompatProtocolTest, TransmitRoundTrip_CurrentProtocol) { /// @brief Non-compat layout always detects CURRENT protocol TEST_F(CentralCompatProtocolTest, NativeLayout_AlwaysCurrent) { std::string name = test_name; - auto result = ShmemSession::create( - name + "_cfg", name + "_rec", name + "_xmt", - name + "_xmt_local", name + "_status", name + "_spk", - name + "_signal", Mode::STANDALONE, ShmemLayout::NATIVE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()) << result.error(); EXPECT_EQ(result.value().getCompatProtocolVersion(), CBPROTO_PROTOCOL_CURRENT); } @@ -1778,10 +1531,7 @@ TEST_F(CentralCompatProtocolTest, NativeLayout_AlwaysCurrent) { /// @brief CENTRAL layout always detects CURRENT protocol TEST_F(CentralCompatProtocolTest, CentralLayout_AlwaysCurrent) { std::string name = test_name; - auto result = ShmemSession::create( - name + "_cfg", name + "_rec", name + "_xmt", - name + "_xmt_local", name + "_status", name + "_spk", - name + "_signal", Mode::STANDALONE, ShmemLayout::CENTRAL); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()) << result.error(); EXPECT_EQ(result.value().getCompatProtocolVersion(), CBPROTO_PROTOCOL_CURRENT); } @@ -1805,10 +1555,7 @@ class OwnerLivenessTest : public ::testing::Test { int OwnerLivenessTest::test_counter = 0; TEST_F(OwnerLivenessTest, StandaloneWritesOwnerPid) { - auto result = ShmemSession::create( - test_name + "_cfg", test_name + "_rec", test_name + "_xmt", - test_name + "_xmt_local", test_name + "_status", test_name + "_spk", - test_name + "_signal", Mode::STANDALONE, ShmemLayout::NATIVE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()) << result.error(); auto* cfg = result.value().getNativeConfigBuffer(); @@ -1821,10 +1568,7 @@ TEST_F(OwnerLivenessTest, StandaloneWritesOwnerPid) { } TEST_F(OwnerLivenessTest, StandaloneAlwaysReturnsTrue) { - auto result = ShmemSession::create( - test_name + "_cfg", test_name + "_rec", test_name + "_xmt", - test_name + "_xmt_local", test_name + "_status", test_name + "_spk", - test_name + "_signal", Mode::STANDALONE, ShmemLayout::NATIVE); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()) << result.error(); // isOwnerAlive() is only meaningful for CLIENT — STANDALONE always returns true @@ -1833,17 +1577,11 @@ TEST_F(OwnerLivenessTest, StandaloneAlwaysReturnsTrue) { TEST_F(OwnerLivenessTest, ClientDetectsLiveOwner) { // Create STANDALONE (sets owner_pid to current process) - auto standalone = ShmemSession::create( - test_name + "_cfg", test_name + "_rec", test_name + "_xmt", - test_name + "_xmt_local", test_name + "_status", test_name + "_spk", - test_name + "_signal", Mode::STANDALONE, ShmemLayout::NATIVE); + auto standalone = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(standalone.isOk()) << standalone.error(); // Create CLIENT on same segments - auto client = ShmemSession::create( - test_name + "_cfg", test_name + "_rec", test_name + "_xmt", - test_name + "_xmt_local", test_name + "_status", test_name + "_spk", - test_name + "_signal", Mode::CLIENT, ShmemLayout::NATIVE); + auto client = ShmemSession::create(Mode::CLIENT, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(client.isOk()) << client.error(); // Owner (this process) is alive @@ -1852,10 +1590,7 @@ TEST_F(OwnerLivenessTest, ClientDetectsLiveOwner) { TEST_F(OwnerLivenessTest, ClientDetectsDeadOwner) { // Create STANDALONE, then set a fake dead PID - auto standalone = ShmemSession::create( - test_name + "_cfg", test_name + "_rec", test_name + "_xmt", - test_name + "_xmt_local", test_name + "_status", test_name + "_spk", - test_name + "_signal", Mode::STANDALONE, ShmemLayout::NATIVE); + auto standalone = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(standalone.isOk()) << standalone.error(); // Overwrite owner_pid with a PID that (almost certainly) doesn't exist @@ -1864,10 +1599,7 @@ TEST_F(OwnerLivenessTest, ClientDetectsDeadOwner) { cfg->owner_pid = 4000000000u; // Well above any real PID // Create CLIENT on same segments - auto client = ShmemSession::create( - test_name + "_cfg", test_name + "_rec", test_name + "_xmt", - test_name + "_xmt_local", test_name + "_status", test_name + "_spk", - test_name + "_signal", Mode::CLIENT, ShmemLayout::NATIVE); + auto client = ShmemSession::create(Mode::CLIENT, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(client.isOk()) << client.error(); // Owner PID doesn't exist — should detect as dead @@ -1876,10 +1608,7 @@ TEST_F(OwnerLivenessTest, ClientDetectsDeadOwner) { TEST_F(OwnerLivenessTest, ClientTreatsZeroPidAsAlive) { // Create STANDALONE, then clear owner_pid to simulate pre-liveness segments - auto standalone = ShmemSession::create( - test_name + "_cfg", test_name + "_rec", test_name + "_xmt", - test_name + "_xmt_local", test_name + "_status", test_name + "_spk", - test_name + "_signal", Mode::STANDALONE, ShmemLayout::NATIVE); + auto standalone = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(standalone.isOk()) << standalone.error(); auto* cfg = standalone.value().getNativeConfigBuffer(); @@ -1887,33 +1616,19 @@ TEST_F(OwnerLivenessTest, ClientTreatsZeroPidAsAlive) { cfg->owner_pid = 0; // Create CLIENT on same segments - auto client = ShmemSession::create( - test_name + "_cfg", test_name + "_rec", test_name + "_xmt", - test_name + "_xmt_local", test_name + "_status", test_name + "_spk", - test_name + "_signal", Mode::CLIENT, ShmemLayout::NATIVE); + auto client = ShmemSession::create(Mode::CLIENT, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(client.isOk()) << client.error(); // PID 0 = unknown — assume alive (backward compat) EXPECT_TRUE(client.value().isOwnerAlive()); } -TEST_F(OwnerLivenessTest, CentralCompatAlwaysReturnsTrue) { - // Liveness check only applies to NATIVE layout - auto standalone = ShmemSession::create( - test_name + "_cfg", test_name + "_rec", test_name + "_xmt", - test_name + "_xmt_local", test_name + "_status", test_name + "_spk", - test_name + "_signal", Mode::STANDALONE, ShmemLayout::CENTRAL); - ASSERT_TRUE(standalone.isOk()) << standalone.error(); - - auto client = ShmemSession::create( - test_name + "_cfg", test_name + "_rec", test_name + "_xmt", - test_name + "_xmt_local", test_name + "_status", test_name + "_spk", - test_name + "_signal", Mode::CLIENT, ShmemLayout::CENTRAL); - ASSERT_TRUE(client.isOk()) << client.error(); - - // Non-NATIVE layout always returns true (no PID field) - EXPECT_TRUE(client.value().isOwnerAlive()); -} +// TODO: Opening a CLIENT + CENTRAL session triggers Central protocol-version +// detection, which inspects Central.exe's file version and therefore requires +// Windows with a running Central. This can't be exercised on a non-Windows build, +// so this liveness test should be reworked as a Windows-only integration test. +// +// TEST_F(OwnerLivenessTest, CentralCompatAlwaysReturnsTrue) { ... } /// @} From 98f9eccc0c38427d034e68209c5c0a8c9a0a7708 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Tue, 30 Jun 2026 12:45:59 -0600 Subject: [PATCH 42/62] FIX: 7.7.x & 7.8.x Central use both cbproto and cbhwlib constants cbMAXPROCS and cbNUM_FE_CHANS differ between cbproto and cbhwlib. This difference only matters for Central 7.7.x and 7.8.x because these versions are where Central switched to cbproto types instead of locally defined packet types. --- src/cbshm/CMakeLists.txt | 9 +- .../include/cbshm/central_adapters/base.h | 2 +- .../cbshm/central_adapters/{v4_0.h => v7_0.h} | 14 +- .../cbshm/central_adapters/{v4_1.h => v7_5.h} | 14 +- .../cbshm/central_adapters/{v4_2.h => v7_6.h} | 14 +- .../central_adapters/{v3_11.h => v7_7.h} | 14 +- .../include/cbshm/central_adapters/v7_8.h | 190 +++ .../cbshm/central_types/{v3_11.h => v7_0.h} | 12 +- .../cbshm/central_types/{v4_0.h => v7_5.h} | 12 +- .../cbshm/central_types/{v4_1.h => v7_6.h} | 12 +- src/cbshm/include/cbshm/central_types/v7_7.h | 910 ++++++++++++++ .../cbshm/central_types/{v4_2.h => v7_8.h} | 307 +++-- .../central_adapters/{v3_11.cpp => v7_0.cpp} | 10 +- .../central_adapters/{v4_0.cpp => v7_5.cpp} | 10 +- .../central_adapters/{v4_1.cpp => v7_6.cpp} | 10 +- .../central_adapters/{v4_2.cpp => v7_7.cpp} | 10 +- src/cbshm/src/central_adapters/v7_8.cpp | 1117 +++++++++++++++++ src/cbshm/src/shmem_session.cpp | 108 +- 18 files changed, 2522 insertions(+), 253 deletions(-) rename src/cbshm/include/cbshm/central_adapters/{v4_0.h => v7_0.h} (97%) rename src/cbshm/include/cbshm/central_adapters/{v4_1.h => v7_5.h} (97%) rename src/cbshm/include/cbshm/central_adapters/{v4_2.h => v7_6.h} (97%) rename src/cbshm/include/cbshm/central_adapters/{v3_11.h => v7_7.h} (97%) create mode 100644 src/cbshm/include/cbshm/central_adapters/v7_8.h rename src/cbshm/include/cbshm/central_types/{v3_11.h => v7_0.h} (99%) rename src/cbshm/include/cbshm/central_types/{v4_0.h => v7_5.h} (99%) rename src/cbshm/include/cbshm/central_types/{v4_1.h => v7_6.h} (99%) create mode 100644 src/cbshm/include/cbshm/central_types/v7_7.h rename src/cbshm/include/cbshm/central_types/{v4_2.h => v7_8.h} (89%) rename src/cbshm/src/central_adapters/{v3_11.cpp => v7_0.cpp} (99%) rename src/cbshm/src/central_adapters/{v4_0.cpp => v7_5.cpp} (99%) rename src/cbshm/src/central_adapters/{v4_1.cpp => v7_6.cpp} (99%) rename src/cbshm/src/central_adapters/{v4_2.cpp => v7_7.cpp} (99%) create mode 100644 src/cbshm/src/central_adapters/v7_8.cpp diff --git a/src/cbshm/CMakeLists.txt b/src/cbshm/CMakeLists.txt index e18185c3..9b218869 100644 --- a/src/cbshm/CMakeLists.txt +++ b/src/cbshm/CMakeLists.txt @@ -9,10 +9,11 @@ project(cbshm # Library sources set(CBSHMEM_SOURCES src/shmem_session.cpp - src/central_adapters/v4_2.cpp - src/central_adapters/v4_1.cpp - src/central_adapters/v4_0.cpp - src/central_adapters/v3_11.cpp + src/central_adapters/v7_8.cpp + src/central_adapters/v7_7.cpp + src/central_adapters/v7_6.cpp + src/central_adapters/v7_5.cpp + src/central_adapters/v7_0.cpp ) # Build as STATIC library diff --git a/src/cbshm/include/cbshm/central_adapters/base.h b/src/cbshm/include/cbshm/central_adapters/base.h index eb9729de..e8d8d37f 100644 --- a/src/cbshm/include/cbshm/central_adapters/base.h +++ b/src/cbshm/include/cbshm/central_adapters/base.h @@ -1,4 +1,4 @@ - +/////////////////////////////////////////////////////////////////////////////////////////////////// /// @file base.h /// @author Caden Shmookler /// @date 2026-05-22 diff --git a/src/cbshm/include/cbshm/central_adapters/v4_0.h b/src/cbshm/include/cbshm/central_adapters/v7_0.h similarity index 97% rename from src/cbshm/include/cbshm/central_adapters/v4_0.h rename to src/cbshm/include/cbshm/central_adapters/v7_0.h index ed60ba4c..665520c1 100644 --- a/src/cbshm/include/cbshm/central_adapters/v4_0.h +++ b/src/cbshm/include/cbshm/central_adapters/v7_0.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file v4_0.h +/// @file v7_0.h /// @author Caden Shmookler /// @date 2026-05-22 /// @@ -7,15 +7,15 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifndef CBSHM_CENTRAL_ADAPTERS_V4_0_H -#define CBSHM_CENTRAL_ADAPTERS_V4_0_H +#ifndef CBSHM_CENTRAL_ADAPTERS_V7_0_H +#define CBSHM_CENTRAL_ADAPTERS_V7_0_H #include -#include +#include namespace cbshm { -namespace central_v4_0 { +namespace central_v7_0 { /// /// @brief Adapter that provides information for fetching pointers to Central's shared memory @@ -183,8 +183,8 @@ class Adapter : public CentralAdapterBase { cbutil::Result setGeminiSystem(bool is_gemini) const override; }; -} // namespace central_v4_0 +} // namespace central_v7_0 } // namespace cbshm -#endif // CBSHM_CENTRAL_ADAPTERS_V4_0_H +#endif // CBSHM_CENTRAL_ADAPTERS_V7_0_H diff --git a/src/cbshm/include/cbshm/central_adapters/v4_1.h b/src/cbshm/include/cbshm/central_adapters/v7_5.h similarity index 97% rename from src/cbshm/include/cbshm/central_adapters/v4_1.h rename to src/cbshm/include/cbshm/central_adapters/v7_5.h index 736871aa..954edc94 100644 --- a/src/cbshm/include/cbshm/central_adapters/v4_1.h +++ b/src/cbshm/include/cbshm/central_adapters/v7_5.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file v4_1.h +/// @file v7_5.h /// @author Caden Shmookler /// @date 2026-05-22 /// @@ -7,15 +7,15 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifndef CBSHM_CENTRAL_ADAPTERS_V4_1_H -#define CBSHM_CENTRAL_ADAPTERS_V4_1_H +#ifndef CBSHM_CENTRAL_ADAPTERS_V7_5_H +#define CBSHM_CENTRAL_ADAPTERS_V7_5_H #include -#include +#include namespace cbshm { -namespace central_v4_1 { +namespace central_v7_5 { /// /// @brief Adapter that provides information for fetching pointers to Central's shared memory @@ -183,8 +183,8 @@ class Adapter : public CentralAdapterBase { cbutil::Result setGeminiSystem(bool is_gemini) const override; }; -} // namespace central_v4_1 +} // namespace central_v7_5 } // namespace cbshm -#endif // CBSHM_CENTRAL_ADAPTERS_V4_1_H +#endif // CBSHM_CENTRAL_ADAPTERS_V7_5_H diff --git a/src/cbshm/include/cbshm/central_adapters/v4_2.h b/src/cbshm/include/cbshm/central_adapters/v7_6.h similarity index 97% rename from src/cbshm/include/cbshm/central_adapters/v4_2.h rename to src/cbshm/include/cbshm/central_adapters/v7_6.h index 005deba3..b1089963 100644 --- a/src/cbshm/include/cbshm/central_adapters/v4_2.h +++ b/src/cbshm/include/cbshm/central_adapters/v7_6.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file v4_2.h +/// @file v7_6.h /// @author Caden Shmookler /// @date 2026-05-22 /// @@ -7,15 +7,15 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifndef CBSHM_CENTRAL_ADAPTERS_V4_2_H -#define CBSHM_CENTRAL_ADAPTERS_V4_2_H +#ifndef CBSHM_CENTRAL_ADAPTERS_V7_6_H +#define CBSHM_CENTRAL_ADAPTERS_V7_6_H #include -#include +#include namespace cbshm { -namespace central_v4_2 { +namespace central_v7_6 { /// /// @brief Adapter that provides information for fetching pointers to Central's shared memory @@ -183,8 +183,8 @@ class Adapter : public CentralAdapterBase { cbutil::Result setGeminiSystem(bool is_gemini) const override; }; -} // namespace central_v4_2 +} // namespace central_v7_6 } // namespace cbshm -#endif // CBSHM_CENTRAL_ADAPTERS_V4_2_H +#endif // CBSHM_CENTRAL_ADAPTERS_V7_6_H diff --git a/src/cbshm/include/cbshm/central_adapters/v3_11.h b/src/cbshm/include/cbshm/central_adapters/v7_7.h similarity index 97% rename from src/cbshm/include/cbshm/central_adapters/v3_11.h rename to src/cbshm/include/cbshm/central_adapters/v7_7.h index 90fc040e..9de9ec5a 100644 --- a/src/cbshm/include/cbshm/central_adapters/v3_11.h +++ b/src/cbshm/include/cbshm/central_adapters/v7_7.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file v3_11.h +/// @file v7_7.h /// @author Caden Shmookler /// @date 2026-05-22 /// @@ -7,15 +7,15 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifndef CBSHM_CENTRAL_ADAPTERS_V3_11_H -#define CBSHM_CENTRAL_ADAPTERS_V3_11_H +#ifndef CBSHM_CENTRAL_ADAPTERS_V7_7_H +#define CBSHM_CENTRAL_ADAPTERS_V7_7_H #include -#include +#include namespace cbshm { -namespace central_v3_11 { +namespace central_v7_7 { /// /// @brief Adapter that provides information for fetching pointers to Central's shared memory @@ -183,8 +183,8 @@ class Adapter : public CentralAdapterBase { cbutil::Result setGeminiSystem(bool is_gemini) const override; }; -} // namespace central_v3_11 +} // namespace central_v7_7 } // namespace cbshm -#endif // CBSHM_CENTRAL_ADAPTERS_V3_11_H +#endif // CBSHM_CENTRAL_ADAPTERS_V7_7_H diff --git a/src/cbshm/include/cbshm/central_adapters/v7_8.h b/src/cbshm/include/cbshm/central_adapters/v7_8.h new file mode 100644 index 00000000..5e549758 --- /dev/null +++ b/src/cbshm/include/cbshm/central_adapters/v7_8.h @@ -0,0 +1,190 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v7_8.h +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Adapter for Central-compatible shared memory access +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef CBSHM_CENTRAL_ADAPTERS_V7_8_H +#define CBSHM_CENTRAL_ADAPTERS_V7_8_H + +#include +#include + +namespace cbshm { + +namespace central_v7_8 { + +/// +/// @brief Adapter that provides information for fetching pointers to Central's shared memory +/// +class BootstrapAdapter : public ::cbshm::CentralBootstrapAdapterBase { +public: + // Buffer sizes + size_t getConfigBufferSize() const override; + size_t getReceiveBufferSize() const override; + size_t getTransmitBufferSize() const override; + size_t getTransmitBufferLocalSize() const override; + size_t getStatusBufferSize() const override; + size_t getSpikeBufferSize() const override; + size_t getReceiveBufferLen() const override; +}; + +/// +/// @brief Adapter for Central-compatible shared memory access +/// +class Adapter : public CentralAdapterBase { +private: + uint8_t instrument_idx; + cbCFGBUFF* cfg; + cbRECBUFF* rec; + cbXMTBUFF* xmt; + cbXMTBUFFLOCAL* xmt_local; + cbPcStatus* status; + cbSPKBUFF* spike; + + void fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const; + void fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const; + void fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const; + void fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const; + void fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const; + void fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const; + void fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const; + void fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const; + void fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const; + void fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const; + void fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const; + void fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const; + void fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const; + void fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const; + void fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const; + void fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const; + void fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const; + void fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const; + void fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const; + void fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const; + void fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const; + void fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const; + void fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const; + void fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const; + void fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const; + void fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const; + void fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const; + void fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const; + void fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const; + void fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const; + void fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const; + void fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const; + void fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const; + void fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const; + void fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const; + void fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const; + void fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const; + void fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const; + void fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const; + void fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const; + + void toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const; + void toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const; + void toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const; + void toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const; + void toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const; + void toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const; + void toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const; + void toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const; + void toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const; + void toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const; + void toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const; + void toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const; + void toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const; + void toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const; + void toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const; + void toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const; + void toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const; + void toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const; + void toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const; + void toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const; + void toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const; + void toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const; + void toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const; + void toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const; + void toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const; + void toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const; + void toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const; + void toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const; + void toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const; + void toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const; + void toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const; + void toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const; + void toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const; + void toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const; + void toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const; + void toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const; + +public: + Adapter( + uint8_t instrument_idx, + void* cfg_ptr, + void* rec_ptr, + void* xmt_ptr, + void* xmt_local_ptr, + void* status_ptr, + void* spike_ptr + ); + ~Adapter() = default; + + // Max instrument count + uint32_t getMaxProcs() const override; + + // Receive buffer access + uint32_t& getRecReceived() override; + uint64_t getRecLasttime() override; + void setRecLasttime(uint64_t lasttime) override; + uint32_t& getRecHeadwrapPtr() override; + uint32_t& getRecHeadindexPtr() override; + uint32_t* getRecBufferPtr() override; + + // Transmit buffer access + uint32_t& getXmtTransmittedPtr() override; + uint32_t& getXmtHeadindexPtr() override; + uint32_t& getXmtTailindexPtr() override; + uint32_t& getXmtLastValidIndexPtr() override; + uint32_t& getXmtBufferlenPtr() override; + uint32_t* getXmtBufferPtr() override; + + uint32_t& getLocalXmtTransmittedPtr() override; + uint32_t& getLocalXmtHeadindexPtr() override; + uint32_t& getLocalXmtTailindexPtr() override; + uint32_t& getLocalXmtLastValidIndexPtr() override; + uint32_t& getLocalXmtBufferlenPtr() override; + uint32_t* getLocalXmtBufferPtr() override; + + /// Config read operations + cbutil::Result getProcInfo(::cbPKT_PROCINFO& buf) const override; + cbutil::Result getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const override; + cbutil::Result getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const override; + cbutil::Result getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const override; + cbutil::Result getSysInfo(::cbPKT_SYSINFO& buf) const override; + cbutil::Result getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const override; + cbutil::Result getConfigBuffer(NativeConfigBuffer& buf) const override; + cbutil::Result getPcStatus(NativePCStatus& buf) const override; + cbutil::Result getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const override; + + /// Config write operations + cbutil::Result setProcInfo(const ::cbPKT_PROCINFO& info) override; + cbutil::Result setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) override; + cbutil::Result setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) override; + cbutil::Result setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) override; + cbutil::Result setSysInfo(const ::cbPKT_SYSINFO& info) override; + cbutil::Result setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) override; + cbutil::Result setNspStatus(const NativeNSPStatus& status) const override; + cbutil::Result setGeminiSystem(bool is_gemini) const override; +}; + +} // namespace central_v7_8 + +} // namespace cbshm + +#endif // CBSHM_CENTRAL_ADAPTERS_V7_8_H diff --git a/src/cbshm/include/cbshm/central_types/v3_11.h b/src/cbshm/include/cbshm/central_types/v7_0.h similarity index 99% rename from src/cbshm/include/cbshm/central_types/v3_11.h rename to src/cbshm/include/cbshm/central_types/v7_0.h index 030f8ec4..e5278866 100644 --- a/src/cbshm/include/cbshm/central_types/v3_11.h +++ b/src/cbshm/include/cbshm/central_types/v7_0.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file v3_11.h +/// @file v7_0.h /// @author Caden Shmookler /// @date 2026-05-18 /// @@ -12,8 +12,8 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifndef CBSHM_CENTRAL_TYPES_V3_11_H -#define CBSHM_CENTRAL_TYPES_V3_11_H +#ifndef CBSHM_CENTRAL_TYPES_V7_0_H +#define CBSHM_CENTRAL_TYPES_V7_0_H #include @@ -22,7 +22,7 @@ namespace cbshm { -namespace central_v3_11 { +namespace central_v7_0 { /////////////////////////////////////////////////////////////////////////////////////////////////// /// @name Protocol Version @@ -840,10 +840,10 @@ struct cbRECBUFF { uint32_t buffer[cbRECBUFFLEN]; ///< Packet buffer }; -} // namespace central_v3_11 +} // namespace central_v7_0 } // namespace cbshm #pragma pack(pop) -#endif // CBSHMEM_CENTRAL_TYPES_V3_11_H +#endif // CBSHMEM_CENTRAL_TYPES_V7_0_H diff --git a/src/cbshm/include/cbshm/central_types/v4_0.h b/src/cbshm/include/cbshm/central_types/v7_5.h similarity index 99% rename from src/cbshm/include/cbshm/central_types/v4_0.h rename to src/cbshm/include/cbshm/central_types/v7_5.h index b734e940..962dd408 100644 --- a/src/cbshm/include/cbshm/central_types/v4_0.h +++ b/src/cbshm/include/cbshm/central_types/v7_5.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file v4_0.h +/// @file v7_5.h /// @author Caden Shmookler /// @date 2026-05-15 /// @@ -12,8 +12,8 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifndef CBSHM_CENTRAL_TYPES_V4_0_H -#define CBSHM_CENTRAL_TYPES_V4_0_H +#ifndef CBSHM_CENTRAL_TYPES_V7_5_H +#define CBSHM_CENTRAL_TYPES_V7_5_H #include @@ -22,7 +22,7 @@ namespace cbshm { -namespace central_v4_0 { +namespace central_v7_5 { /////////////////////////////////////////////////////////////////////////////////////////////////// /// @name Protocol Version @@ -842,10 +842,10 @@ struct cbRECBUFF { uint32_t buffer[cbRECBUFFLEN]; ///< Packet buffer }; -} // namespace central_v4_0 +} // namespace central_v7_5 } // namespace cbshm #pragma pack(pop) -#endif // CBSHMEM_CENTRAL_TYPES_V4_0_H +#endif // CBSHMEM_CENTRAL_TYPES_V7_5_H diff --git a/src/cbshm/include/cbshm/central_types/v4_1.h b/src/cbshm/include/cbshm/central_types/v7_6.h similarity index 99% rename from src/cbshm/include/cbshm/central_types/v4_1.h rename to src/cbshm/include/cbshm/central_types/v7_6.h index 07aaa536..38536f04 100644 --- a/src/cbshm/include/cbshm/central_types/v4_1.h +++ b/src/cbshm/include/cbshm/central_types/v7_6.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file v4_1.h +/// @file v7_6.h /// @author Caden Shmookler /// @date 2026-05-15 /// @@ -12,8 +12,8 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifndef CBSHM_CENTRAL_TYPES_V4_1_H -#define CBSHM_CENTRAL_TYPES_V4_1_H +#ifndef CBSHM_CENTRAL_TYPES_V7_6_H +#define CBSHM_CENTRAL_TYPES_V7_6_H #include @@ -22,7 +22,7 @@ namespace cbshm { -namespace central_v4_1 { +namespace central_v7_6 { /////////////////////////////////////////////////////////////////////////////////////////////////// /// @name Protocol Version @@ -846,10 +846,10 @@ struct cbRECBUFF { uint32_t buffer[cbRECBUFFLEN]; ///< Packet buffer }; -} // namespace central_v4_1 +} // namespace central_v7_6 } // namespace cbshm #pragma pack(pop) -#endif // CBSHMEM_CENTRAL_TYPES_V4_1_H +#endif // CBSHMEM_CENTRAL_TYPES_V7_6_H diff --git a/src/cbshm/include/cbshm/central_types/v7_7.h b/src/cbshm/include/cbshm/central_types/v7_7.h new file mode 100644 index 00000000..b1c331ac --- /dev/null +++ b/src/cbshm/include/cbshm/central_types/v7_7.h @@ -0,0 +1,910 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v7_7.h +/// @author Caden Shmookler +/// @date 2026-06-22 +/// +/// @brief Central-compatible shared memory structure definitions +/// +/// This file defines the shared memory structures using Central's constants to +/// ensure compatibility with Central when it creates shared memory. +/// +/// CRITICAL: These structures MUST match Central's cbhwlib.h exactly! +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef CBSHM_CENTRAL_TYPES_V7_7_H +#define CBSHM_CENTRAL_TYPES_V7_7_H + +#include + +// Ensure tight packing for shared memory structures +#pragma pack(push, 1) + +namespace cbshm { + +namespace central_v7_7 { + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Protocol Version +/// @{ + +constexpr uint32_t cbVERSION_MAJOR = 4; +constexpr uint32_t cbVERSION_MINOR = 1; + +/// @} + +namespace wire { + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name cbproto Constants +/// @{ + +constexpr uint32_t cbMAXPROCS = 1; ///< Maximum supported NSPs +constexpr uint32_t cbNUM_FE_CHANS = 256; ///< Maximum supported front-end channels +constexpr uint32_t cbMAXGROUPS = 8; ///< Sample rate groups +constexpr uint32_t cbMAXFILTS = 32; ///< Digital filters +constexpr uint32_t cbMAXVIDEOSOURCE = 1; ///< Maximum number of video sources +constexpr uint32_t cbMAXTRACKOBJ = 20; ///< Maximum number of trackable objects +constexpr uint32_t cbMAXHOOPS = 4; ///< Maximum number of hoops for spike sorting +constexpr uint32_t cbMAXSITES = 4; ///< Maximum number of electrodes in an n-trode group +constexpr uint32_t cbMAXSITEPLOTS = ((cbMAXSITES - 1) * cbMAXSITES / 2); ///< Combination of 2 out of n +constexpr uint32_t cbMAXUNITS = 5; ///< Maximum number of sorted units per channel +constexpr uint32_t cbMAX_PNTS = 128; ///< Maximum spike waveform points +constexpr uint32_t cbMAX_AOUT_TRIGGER = 5; ///< Maximum number of per-channel (analog output, or digital output) triggers + +// Channel counts +constexpr uint32_t cbNUM_ANAIN_CHANS = 16 * cbMAXPROCS; +constexpr uint32_t cbNUM_ANALOG_CHANS = cbNUM_FE_CHANS + cbNUM_ANAIN_CHANS; +constexpr uint32_t cbNUM_ANAOUT_CHANS = 4 * cbMAXPROCS; +constexpr uint32_t cbNUM_AUDOUT_CHANS = 2 * cbMAXPROCS; +constexpr uint32_t cbNUM_ANALOGOUT_CHANS = cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS; +constexpr uint32_t cbNUM_DIGIN_CHANS = 1 * cbMAXPROCS; +constexpr uint32_t cbNUM_SERIAL_CHANS = 1 * cbMAXPROCS; +constexpr uint32_t cbNUM_DIGOUT_CHANS = 4 * cbMAXPROCS; + +// Total channels +constexpr uint32_t cbMAXCHANS = (cbNUM_ANALOG_CHANS + cbNUM_ANALOGOUT_CHANS + + cbNUM_DIGIN_CHANS + cbNUM_SERIAL_CHANS + + cbNUM_DIGOUT_CHANS); + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name String Length Constants +/// @{ + +constexpr uint32_t cbLEN_STR_UNIT = 8; ///< Length of unit string +constexpr uint32_t cbLEN_STR_LABEL = 16; ///< Length of label string +constexpr uint32_t cbLEN_STR_FILT_LABEL = 16; ///< Length of filter label string +constexpr uint32_t cbLEN_STR_IDENT = 64; ///< Length of identity string +constexpr uint32_t cbLEN_STR_COMMENT = 256; ///< Length of comment string +constexpr uint32_t cbMAX_COMMENT = 128; ///< Maximum comment length (must be multiple of 4) + +/// @} + +} // namespace wire + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Data Packet Structures +/// @{ + +typedef uint64_t PROCTIME; + +/// @brief Cerebus packet header data structure +typedef struct { + PROCTIME time; ///< System clock timestamp + uint16_t chid; ///< Channel identifier + uint16_t type; ///< Packet type + uint16_t dlen; ///< Length of data field in 32-bit chunks + uint8_t instrument; ///< Instrument number (0-based in packet, despite cbNSP1=1!) + uint8_t reserved; ///< Reserved for future use +} cbPKT_HEADER; + +constexpr uint32_t cbPKT_MAX_SIZE = 1024; ///< Maximum packet size in bytes +constexpr uint32_t cbPKT_HEADER_SIZE = sizeof(cbPKT_HEADER); ///< Packet header size in bytes + +/// @brief PKT Set:0x92 Rep:0x12 - System info +/// +/// Contains system information including the runlevel +typedef struct { + cbPKT_HEADER cbpkt_header; ///< Packet header + + uint32_t sysfreq; ///< System sampling clock frequency in Hz + uint32_t spikelen; ///< The length of the spike events + uint32_t spikepre; ///< Spike pre-trigger samples + uint32_t resetque; ///< The channel for the reset to que on + uint32_t runlevel; ///< System runlevel + uint32_t runflags; ///< Lock recording after reset +} cbPKT_SYSINFO; + +/// @brief PKT Set:N/A Rep:0x21 - Info about the processor +/// +/// Includes information about the counts of various features of the processor +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< index of the bank + uint32_t idcode; ///< manufacturer part and rom ID code of the Signal Processor + char ident[wire::cbLEN_STR_IDENT]; ///< ID string with the equipment name of the Signal Processor + uint32_t chanbase; ///< lowest channel number of channel id range claimed by this processor + uint32_t chancount; ///< number of channel identifiers claimed by this processor + uint32_t bankcount; ///< number of signal banks supported by the processor + uint32_t groupcount; ///< number of sample groups supported by the processor + uint32_t filtcount; ///< number of digital filters supported by the processor + uint32_t sortcount; ///< number of channels supported for spike sorting (reserved for future) + uint32_t unitcount; ///< number of supported units for spike sorting (reserved for future) + uint32_t hoopcount; ///< number of supported units for spike sorting (reserved for future) + uint32_t reserved; ///< reserved for future use, set to 0 + uint32_t version; ///< current version of libraries +} cbPKT_PROCINFO; + +/// @brief PKT Set:N/A Rep:0x22 - Information about the banks in the processor +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< the address of the processor on which the bank resides + uint32_t bank; ///< the address of the bank reported by the packet + uint32_t idcode; ///< manufacturer part and rom ID code of the module addressed to this bank + char ident[wire::cbLEN_STR_IDENT]; ///< ID string with the equipment name of the Signal Bank hardware module + char label[wire::cbLEN_STR_LABEL]; ///< Label on the instrument for the signal bank, eg "Analog In" + uint32_t chanbase; ///< lowest channel number of channel id range claimed by this bank + uint32_t chancount; ///< number of channel identifiers claimed by this bank +} cbPKT_BANKINFO; + +/// @brief PKT Set:0xB0 Rep:0x30 - Sample Group (GROUP) Information Packets +/// +/// Contains information including the name and list of channels for each sample group. The cbPKT_GROUP packet transmits +/// the data for each group based on the list contained here. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< processor number + uint32_t group; ///< group number + char label[wire::cbLEN_STR_LABEL]; ///< sampling group label + uint32_t period; ///< sampling period for the group + uint32_t length; ///< number of channels in the list + uint16_t list[wire::cbNUM_ANALOG_CHANS]; ///< variable length list. The max size is the total number of analog channels +} cbPKT_GROUPINFO; + +/// @brief PKT Set:0xA3 Rep:0x23 - Filter Information Packet +/// +/// Describes the filters contained in the NSP including the filter coefficients +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t proc; ///< + uint32_t filt; ///< + char label[wire::cbLEN_STR_FILT_LABEL]; // name of the filter + uint32_t hpfreq; ///< high-pass corner frequency in milliHertz + uint32_t hporder; ///< high-pass filter order + uint32_t hptype; ///< high-pass filter type + uint32_t lpfreq; ///< low-pass frequency in milliHertz + uint32_t lporder; ///< low-pass filter order + uint32_t lptype; ///< low-pass filter type + ///< These are for sending the NSP filter info, otherwise the NSP has this stuff in NSPDefaults.c + double gain; ///< filter gain + double sos1a1; ///< filter coefficient + double sos1a2; ///< filter coefficient + double sos1b1; ///< filter coefficient + double sos1b2; ///< filter coefficient + double sos2a1; ///< filter coefficient + double sos2a2; ///< filter coefficient + double sos2b1; ///< filter coefficient + double sos2b2; ///< filter coefficient +} cbPKT_FILTINFO; + +/// @brief PKT Set:0xA5 Rep:0x25 - Adaptive filtering +/// +/// This sets the parameters for the adaptive filtering. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< Ignored + + uint32_t nMode; ///< 0=disabled, 1=filter continuous & spikes, 2=filter spikes + float dLearningRate; ///< speed at which adaptation happens. Very small. e.g. 5e-12 + uint32_t nRefChan1; ///< The first reference channel (1 based). + uint32_t nRefChan2; ///< The second reference channel (1 based). + +} cbPKT_ADAPTFILTINFO; + +/// @brief PKT Set:0xA6 Rep:0x26 - Reference Electrode Information. +/// +/// This configures a channel to be referenced by another channel. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< Ignored + + uint32_t nMode; ///< 0=disabled, 1=filter continuous & spikes, 2=filter spikes + uint32_t nRefChan; ///< The reference channel (1 based). +} cbPKT_REFELECFILTINFO; + +/// @brief Scaling structure +/// +/// Structure used in cbPKT_CHANINFO +typedef struct { + int16_t digmin; ///< digital value that cooresponds with the anamin value + int16_t digmax; ///< digital value that cooresponds with the anamax value + int32_t anamin; ///< the minimum analog value present in the signal + int32_t anamax; ///< the maximum analog value present in the signal + int32_t anagain; ///< the gain applied to the default analog values to get the analog values + char anaunit[wire::cbLEN_STR_UNIT]; ///< the unit for the analog signal (eg, "uV" or "MPa") +} cbSCALING; + +/// @brief Filter description structure +/// +/// Filter description used in cbPKT_CHANINFO +typedef struct { + char label[wire::cbLEN_STR_FILT_LABEL]; + uint32_t hpfreq; ///< high-pass corner frequency in milliHertz + uint32_t hporder; ///< high-pass filter order + uint32_t hptype; ///< high-pass filter type + uint32_t lpfreq; ///< low-pass frequency in milliHertz + uint32_t lporder; ///< low-pass filter order + uint32_t lptype; ///< low-pass filter type +} cbFILTDESC; + +/// @brief Manual Unit Mapping structure +/// +/// Defines an ellipsoid for sorting. Used in cbPKT_CHANINFO and cbPKT_NTRODEINFO +typedef struct { + int16_t nOverride; ///< override to unit if in ellipsoid + int16_t afOrigin[3]; ///< ellipsoid origin + int16_t afShape[3][3]; ///< ellipsoid shape + int16_t aPhi; ///< + uint32_t bValid; ///< is this unit in use at this time? + ///< BOOL implemented as uint32_t - for structure alignment at paragraph boundary +} cbMANUALUNITMAPPING; + +/// @brief Hoop definition structure +/// +/// Defines the hoop used for sorting. There can be up to 5 hoops per unit. Used in cbPKT_CHANINFO +typedef struct { + uint16_t valid; ///< 0=undefined, 1 for valid + int16_t time; ///< time offset into spike window + int16_t min; ///< minimum value for the hoop window + int16_t max; ///< maximum value for the hoop window +} cbHOOP; + +/// @brief PKT Set:0xCx Rep:0x4x - Channel Information +/// +/// This contains the details for each channel within the system. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< actual channel id of the channel being configured + uint32_t proc; ///< the address of the processor on which the channel resides + uint32_t bank; ///< the address of the bank on which the channel resides + uint32_t term; ///< the terminal number of the channel within it's bank + uint32_t chancaps; ///< general channel capablities (given by cbCHAN_* flags) + uint32_t doutcaps; ///< digital output capablities (composed of cbDOUT_* flags) + uint32_t dinpcaps; ///< digital input capablities (composed of cbDINP_* flags) + uint32_t aoutcaps; ///< analog output capablities (composed of cbAOUT_* flags) + uint32_t ainpcaps; ///< analog input capablities (composed of cbAINP_* flags) + uint32_t spkcaps; ///< spike processing capabilities + cbSCALING physcalin; ///< physical channel scaling information + cbFILTDESC phyfiltin; ///< physical channel filter definition + cbSCALING physcalout; ///< physical channel scaling information + cbFILTDESC phyfiltout; ///< physical channel filter definition + char label[wire::cbLEN_STR_LABEL]; ///< Label of the channel (null terminated if <16 characters) + uint32_t userflags; ///< User flags for the channel state + int32_t position[4]; ///< reserved for future position information + cbSCALING scalin; ///< user-defined scaling information for AINP + cbSCALING scalout; ///< user-defined scaling information for AOUT + uint32_t doutopts; ///< digital output options (composed of cbDOUT_* flags) + uint32_t dinpopts; ///< digital input options (composed of cbDINP_* flags) + uint32_t aoutopts; ///< analog output options + uint32_t eopchar; ///< digital input capablities (given by cbDINP_* flags) + union { + struct { // separate system channel to instrument specific channel number + uint16_t moninst; ///< instrument of channel to monitor + uint16_t monchan; ///< channel to monitor + int32_t outvalue; ///< output value + }; + struct { // used for digout timed output + uint16_t lowsamples; ///< number of samples to set low for timed output + uint16_t highsamples; ///< number of samples to set high for timed output + int32_t offset; ///< number of samples to offset the transitions for timed output + }; + }; + uint8_t trigtype; ///< trigger type (see cbDOUT_TRIGGER_*) + uint8_t reserved[2]; ///< 2 bytes reserved + uint8_t triginst; ///< instrument of the trigger channel + uint16_t trigchan; ///< trigger channel + uint16_t trigval; ///< trigger value + uint32_t ainpopts; ///< analog input options (composed of cbAINP* flags) + uint32_t lncrate; ///< line noise cancellation filter adaptation rate + uint32_t smpfilter; ///< continuous-time pathway filter id + uint32_t smpgroup; ///< continuous-time pathway sample group + int32_t smpdispmin; ///< continuous-time pathway display factor + int32_t smpdispmax; ///< continuous-time pathway display factor + uint32_t spkfilter; ///< spike pathway filter id + int32_t spkdispmax; ///< spike pathway display factor + int32_t lncdispmax; ///< Line Noise pathway display factor + uint32_t spkopts; ///< spike processing options + int32_t spkthrlevel; ///< spike threshold level + int32_t spkthrlimit; ///< + uint32_t spkgroup; ///< NTrodeGroup this electrode belongs to - 0 is single unit, non-0 indicates a multi-trode grouping + int16_t amplrejpos; ///< Amplitude rejection positive value + int16_t amplrejneg; ///< Amplitude rejection negative value + uint32_t refelecchan; ///< Software reference electrode channel + cbMANUALUNITMAPPING unitmapping[wire::cbMAXUNITS]; ///< manual unit mapping + cbHOOP spkhoops[wire::cbMAXUNITS][wire::cbMAXHOOPS]; ///< spike hoop sorting set +} cbPKT_CHANINFO; + +/// @brief PKT Set:0xDB Rep:0x5B - Feature Space Basis +/// +/// This packet holds the calculated basis of the feature space from NSP to Central +/// Or it has the previous basis retrieved and transmitted by central to NSP +typedef struct +{ + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< 1-based channel number + uint32_t mode; ///< cbBASIS_CHANGE, cbUNDO_BASIS_CHANGE, cbREDO_BASIS_CHANGE, cbINVALIDATE_BASIS ... + uint32_t fs; ///< Feature space: cbAUTOALG_PCA + /// basis must be the last item in the structure because it can be variable length to a max of cbMAX_PNTS + float basis[wire::cbMAX_PNTS][3]; ///< Room for all possible points collected +} cbPKT_FS_BASIS; + +/// @brief PKT Set:0xD1 Rep:0x51 - Get the spike sorting model for a single channel (Histogram Peak Count) +/// +/// The system replys with the model of a specific channel. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< actual channel id of the channel being configured (0 based) + uint32_t unit_number; ///< unit label (0 based, 0 is noise cluster) + uint32_t valid; ///< 1 = valid unit, 0 = not a unit, in other words just deleted when NSP -> PC + uint32_t inverted; ///< 0 = not inverted, 1 = inverted + + // Block statistics (change from block to block) + int32_t num_samples; ///< non-zero value means that the block stats are valid + float mu_x[2]; + float Sigma_x[2][2]; + float determinant_Sigma_x; + ///// Only needed if we are using a Bayesian classification model + float Sigma_x_inv[2][2]; + float log_determinant_Sigma_x; + ///// + float subcluster_spread_factor_numerator; + float subcluster_spread_factor_denominator; + float mu_e; + float sigma_e_squared; +} cbPKT_SS_MODELSET; + +/// @brief PKT Set:0xD2 Rep:0x52 - Auto threshold parameters +/// +/// Set the auto threshold parameters +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + float fThreshold; ///< current detection threshold + float fMultiplier; ///< multiplier +} cbPKT_SS_DETECT; + +/// @brief PKT Set:0xD3 Rep:0x53 - Artifact reject +/// +/// Sets the artifact rejection parameters. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t nMaxSimulChans; ///< how many channels can fire exactly at the same time??? + uint32_t nRefractoryCount; ///< for how many samples (30 kHz) is a neuron refractory, so can't re-trigger +} cbPKT_SS_ARTIF_REJECT; + +/// @brief PKT Set:0xD4 Rep:0x54 - Noise boundary +/// +/// Sets the noise boundary parameters +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t chan; ///< which channel we belong to + float afc[3]; ///< the center of the ellipsoid + float afS[3][3]; ///< an array of the axes for the ellipsoid +} cbPKT_SS_NOISE_BOUNDARY; + +/// @brief PKT Set:0xD5 Rep:0x55 - Spike sourting statistics (Histogram peak count) +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t nUpdateSpikes; ///< update rate in spike counts + + uint32_t nAutoalg; ///< sorting algorithm (0=none 1=spread, 2=hist_corr_maj, 3=hist_peak_count_maj, 4=hist_peak_count_maj_fisher, 5=pca, 6=hoops) + uint32_t nMode; ///< cbAUTOALG_MODE_SETTING, + + float fMinClusterPairSpreadFactor; ///< larger number = more apt to combine 2 clusters into 1 + float fMaxSubclusterSpreadFactor; ///< larger number = less apt to split because of 2 clusers + + float fMinClusterHistCorrMajMeasure; ///< larger number = more apt to split 1 cluster into 2 + float fMaxClusterPairHistCorrMajMeasure; ///< larger number = less apt to combine 2 clusters into 1 + + float fClusterHistValleyPercentage; ///< larger number = less apt to split nearby clusters + float fClusterHistClosePeakPercentage; ///< larger number = less apt to split nearby clusters + float fClusterHistMinPeakPercentage; ///< larger number = less apt to split separated clusters + + uint32_t nWaveBasisSize; ///< number of wave to collect to calculate the basis, + ///< must be greater than spike length + uint32_t nWaveSampleSize; ///< number of samples sorted with the same basis before re-calculating the basis + ///< 0=manual re-calculation + ///< nWaveBasisSize * nWaveSampleSize is the number of waves/spikes to run against + ///< the same PCA basis before next +} cbPKT_SS_STATISTICS; + +/// @brief Adaptive Control structure +typedef struct { + uint32_t nMode; ///< 0-do not adapt at all, 1-always adapt, 2-adapt if timer not timed out + float fTimeOutMinutes; ///< how many minutes until time out + float fElapsedMinutes; ///< the amount of time that has elapsed +} cbAdaptControl; + +/// @brief PKT Set:0xD7 Rep:0x57 - Spike sorting status (Histogram peak count) +/// +/// This packet contains the status of the automatic spike sorting. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + cbAdaptControl cntlUnitStats; ///< + cbAdaptControl cntlNumUnits; ///< +} cbPKT_SS_STATUS; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Spike sorting configuration +/// +/// Groups all spike-sorting related configuration packets together. +typedef struct { + cbPKT_FS_BASIS asBasis[wire::cbMAXCHANS]; ///< PCA basis values per channel + cbPKT_SS_MODELSET asSortModel[wire::cbMAXCHANS][wire::cbMAXUNITS + 2]; ///< Sorting models/rules per channel + + //////// These are spike sorting options + cbPKT_SS_DETECT pktDetect; ///< Detection parameters + cbPKT_SS_ARTIF_REJECT pktArtifReject; ///< Artifact rejection parameters + cbPKT_SS_NOISE_BOUNDARY pktNoiseBoundary[wire::cbMAXCHANS]; ///< Noise boundaries per channel + cbPKT_SS_STATISTICS pktStatistics; ///< Spike statistics + cbPKT_SS_STATUS pktStatus; ///< Spike sorting status +} cbSPIKE_SORTING; + +/// @brief PKT Set:0xA7 Rep:0x27 - N-Trode information packets +/// +/// Sets information about an N-Trode. The user can change the name, number of sites, sites (channels) +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t ntrode; ///< ntrode with which we are working (1-based) + char label[wire::cbLEN_STR_LABEL]; ///< Label of the Ntrode (null terminated if < 16 characters) + cbMANUALUNITMAPPING ellipses[wire::cbMAXSITEPLOTS][wire::cbMAXUNITS]; ///< unit mapping + uint16_t nSite; ///< number channels in this NTrode ( 0 <= nSite <= cbMAXSITES) + uint16_t fs; ///< NTrode feature space cbNTRODEINFO_FS_* + uint16_t nChan[wire::cbMAXSITES]; ///< group of channels in this NTrode +} cbPKT_NTRODEINFO; + +constexpr uint32_t cbMAX_WAVEFORM_PHASES = ((cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - 24) / 4); ///< Maximum number of phases in a waveform + +/// @brief Analog output waveform data +/// +/// Contains the parameters to define a waveform for Analog Output channels +typedef struct +{ + int16_t offset; ///< DC offset + union { + struct { + uint16_t sineFrequency; ///< sine wave Hz + int16_t sineAmplitude; ///< sine amplitude + }; + struct { + uint16_t seq; ///< Wave sequence number (for file playback) + uint16_t seqTotal; ///< total number of sequences + uint16_t phases; ///< Number of valid phases in this wave (maximum is cbMAX_WAVEFORM_PHASES) + uint16_t duration[cbMAX_WAVEFORM_PHASES]; ///< array of durations for each phase + int16_t amplitude[cbMAX_WAVEFORM_PHASES]; ///< array of amplitude for each phase + }; + }; +} cbWaveformData; + +/// @brief PKT Set:0xB3 Rep:0x33 - AOUT waveform +/// +/// This sets a user defined waveform for one or multiple Analog & Audio Output channels. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint16_t chan; ///< which analog output/audio output channel (1-based, will equal chan from GetDoutCaps) + + /// Each file may contain multiple sequences. + /// Each sequence consists of phases + /// Each phase is defined by amplitude and duration + + /// Waveform parameter information + uint16_t mode; ///< Can be any of cbWAVEFORM_MODE_* + uint32_t repeats; ///< Number of repeats (0 means forever) + uint8_t trig; ///< Can be any of cbWAVEFORM_TRIGGER_* + uint8_t trigInst; ///< Instrument the trigChan belongs + uint16_t trigChan; ///< Depends on trig: + /// for cbWAVEFORM_TRIGGER_DINP* 1-based trigChan (1-16) is digin1, (17-32) is digin2, ... + /// for cbWAVEFORM_TRIGGER_SPIKEUNIT 1-based trigChan (1-156) is channel number + /// for cbWAVEFORM_TRIGGER_COMMENTCOLOR trigChan is A->B in A->B->G->R + uint16_t trigValue; ///< Trigger value (spike unit, G-R comment color, ...) + uint8_t trigNum; ///< trigger number (0-based) (can be up to cbMAX_AOUT_TRIGGER-1) + uint8_t active; ///< status of trigger + cbWaveformData wave; ///< Actual waveform data +} cbPKT_AOUT_WAVEFORM; + +/// @brief PKT Set:0xA8 Rep:0x28 - Line Noise Cancellation +/// +/// This packet holds the Line Noise Cancellation parameters +typedef struct +{ + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t lncFreq; ///< Nominal line noise frequency to be canceled (in Hz) + uint32_t lncRefChan; ///< Reference channel for lnc synch (1-based) + uint32_t lncGlobalMode; ///< reserved +} cbPKT_LNC; + +constexpr uint32_t cbNPLAY_FNAME_LEN = (cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - 40); ///< length of the file name (with terminating null) + +/// @brief PKT Set:0xDC Rep:0x5C - nPlay configuration packet +/// +/// Sent on restart together with config packet +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + union { + PROCTIME ftime; ///< the total time of the file. + PROCTIME opt; ///< optional value + }; + PROCTIME stime; ///< start time + PROCTIME etime; ///< stime < end time < ftime + PROCTIME val; ///< Used for current time to traverse, file index, file version, ... + uint16_t mode; ///< cbNPLAY_MODE_* command to nPlay + uint16_t flags; ///< cbNPLAY_FLAG_* status of nPlay + float speed; ///< positive means fast forward, negative means rewind, 0 means go as fast as you can. + char fname[cbNPLAY_FNAME_LEN]; ///< This is a String with the file name. +} cbPKT_NPLAY; + +/// @brief NeuroMotive video source +typedef struct { + char name[wire::cbLEN_STR_LABEL]; ///< filename of the video file + float fps; ///< nominal record fps +} cbVIDEOSOURCE; + +/// @brief Track object structure for NeuroMotive +typedef struct { + char name[wire::cbLEN_STR_LABEL]; ///< name of the object + uint16_t type; ///< trackable type (cbTRACKOBJ_TYPE_*) + uint16_t pointCount; ///< maximum number of points +} cbTRACKOBJ; + +/// @brief PKT Set:0xE1 Rep:0x61 - File configuration packet +/// +/// File recording can be started or stopped externally using this packet. It also contains a timeout mechanism to notify +/// if file isn't still recording. +typedef struct { + cbPKT_HEADER cbpkt_header; ///< packet header + + uint32_t options; ///< cbFILECFG_OPT_* + uint32_t duration; + uint32_t recording; ///< If cbFILECFG_OPT_NONE this option starts/stops recording remotely + uint32_t extctrl; ///< If cbFILECFG_OPT_REC this is split number (0 for non-TOC) + ///< If cbFILECFG_OPT_STOP this is error code (0 means no error) + + char username[wire::cbLEN_STR_COMMENT]; ///< name of computer issuing the packet + union { + char filename[wire::cbLEN_STR_COMMENT]; ///< filename to record to + char datetime[wire::cbLEN_STR_COMMENT]; ///< + }; + char comment[wire::cbLEN_STR_COMMENT]; ///< comment to include in the file +} cbPKT_FILECFG; + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Data packet - Spike waveform data +/// +/// Detected spikes are sent through this packet. The spike waveform may or may not be sent depending +/// on the dlen contained in the header. The waveform can be anywhere from 30 samples to 128 samples +/// based on user configuration. The default spike length is 48 samples. cbpkt_header.chid is the +/// channel number of the spike. cbpkt_header.type is the sorted unit number (0=unsorted, 255=noise). +typedef struct { + cbPKT_HEADER cbpkt_header; ///< in the header for this packet, the type is used as the unit number + + float fPattern[3]; ///< values of the pattern space (Normal uses only 2, PCA uses third) + int16_t nPeak; ///< highest datapoint of the waveform + int16_t nValley; ///< lowest datapoint of the waveform + + int16_t wave[wire::cbMAX_PNTS]; ///< datapoints of each sample of the waveform. Room for all possible points collected + ///< wave must be the last item in the structure because it can be variable length to a max of cbMAX_PNTS +} cbPKT_SPK; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Unit Selection +/// +/// Packet which says that these channels are now selected +typedef struct +{ + cbPKT_HEADER cbpkt_header; ///< packet header + + int32_t lastchan; ///< Which channel was clicked last. + uint16_t abyUnitSelections[(cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - sizeof(int32_t))]; ///< one for each channel, channels are 0 based here, shows units selected +} cbPKT_UNIT_SELECTION; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Central Constants +/// @{ + +constexpr uint32_t cbMAXPROCS = 3; ///< Maximum supported NSPs +constexpr uint32_t cbNUM_FE_CHANS = 512; ///< Maximum supported front-end channels +constexpr uint32_t cbMAXGROUPS = 8; ///< Sample rate groups +constexpr uint32_t cbMAXFILTS = 32; ///< Digital filters +constexpr uint32_t cbMAXVIDEOSOURCE = 1; ///< Maximum number of video sources +constexpr uint32_t cbMAXTRACKOBJ = 20; ///< Maximum number of trackable objects +constexpr uint32_t cbMAXHOOPS = 4; ///< Maximum number of hoops for spike sorting +constexpr uint32_t cbMAXSITES = 4; ///< Maximum number of electrodes in an n-trode group +constexpr uint32_t cbMAXSITEPLOTS = ((cbMAXSITES - 1) * cbMAXSITES / 2); ///< Combination of 2 out of n +constexpr uint32_t cbMAXUNITS = 5; ///< Maximum number of sorted units per channel +constexpr uint32_t cbMAX_PNTS = 128; ///< Maximum spike waveform points +constexpr uint32_t cbMAX_AOUT_TRIGGER = 5; ///< Maximum number of per-channel (analog output, or digital output) triggers + +// Channel counts +constexpr uint32_t cbNUM_ANAIN_CHANS = 16 * cbMAXPROCS; +constexpr uint32_t cbNUM_ANALOG_CHANS = cbNUM_FE_CHANS + cbNUM_ANAIN_CHANS; +constexpr uint32_t cbNUM_ANAOUT_CHANS = 4 * cbMAXPROCS; +constexpr uint32_t cbNUM_AUDOUT_CHANS = 2 * cbMAXPROCS; +constexpr uint32_t cbNUM_ANALOGOUT_CHANS = cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS; +constexpr uint32_t cbNUM_DIGIN_CHANS = 1 * cbMAXPROCS; +constexpr uint32_t cbNUM_SERIAL_CHANS = 1 * cbMAXPROCS; +constexpr uint32_t cbNUM_DIGOUT_CHANS = 4 * cbMAXPROCS; + +// Total channels +constexpr uint32_t cbMAXCHANS = (cbNUM_ANALOG_CHANS + cbNUM_ANALOGOUT_CHANS + + cbNUM_DIGIN_CHANS + cbNUM_SERIAL_CHANS + + cbNUM_DIGOUT_CHANS); + +// Bank definitions +constexpr uint32_t cbCHAN_PER_BANK = 32; +constexpr uint32_t cbNUM_FE_BANKS = cbNUM_FE_CHANS / cbCHAN_PER_BANK; +constexpr uint32_t cbNUM_ANAIN_BANKS = 1; +constexpr uint32_t cbNUM_ANAOUT_BANKS = 1; +constexpr uint32_t cbNUM_AUDOUT_BANKS = 1; +constexpr uint32_t cbNUM_DIGIN_BANKS = 1; +constexpr uint32_t cbNUM_SERIAL_BANKS = 1; +constexpr uint32_t cbNUM_DIGOUT_BANKS = 1; + +constexpr uint32_t cbMAXBANKS = (cbNUM_FE_BANKS + cbNUM_ANAIN_BANKS + + cbNUM_ANAOUT_BANKS + cbNUM_AUDOUT_BANKS + + cbNUM_DIGIN_BANKS + cbNUM_SERIAL_BANKS + + cbNUM_DIGOUT_BANKS); + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Buffer Size Constants (must be defined before structures) +/// @{ + +/// Max UDP packet size (from Central) +constexpr uint32_t cbCER_UDP_SIZE_MAX = 58080; + +/// Transmit buffer sizes (Central-compatible) +constexpr uint32_t cbXMT_GLOBAL_BUFFLEN = ((cbCER_UDP_SIZE_MAX / 4) * 5000 + 2); ///< Room for 5000 packet-sized slots +constexpr uint32_t cbXMT_LOCAL_BUFFLEN = ((cbCER_UDP_SIZE_MAX / 4) * 2000 + 2); ///< Room for 2000 packet-sized slots + +/// N-Trode count (Central uses cbNUM_FE_CHANS / 2, not cbNUM_ANALOG_CHANS / 2) +constexpr uint32_t cbMAXNTRODES = cbNUM_FE_CHANS / 2; ///< = 384 + +/// Analog output gain channels (Central's multi-instrument count) +constexpr uint32_t AOUT_NUM_GAIN_CHANS = cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS; ///< = 24 + +/// Spike cache constants +constexpr uint32_t cbPKT_SPKCACHEPKTCNT = 400; ///< Packets per channel cache +constexpr uint32_t cbPKT_SPKCACHELINECNT = cbMAXCHANS; ///< One cache per channel (Central uses cbMAXCHANS, not cbNUM_ANALOG_CHANS) + +/// Receive buffer size +constexpr uint32_t cbRECBUFFLEN = cbNUM_FE_CHANS * 65536 * 4; + +/// @} + +/// @brief Option table for Central application +/// +/// Used for configuration options in Central +typedef struct { + float fRMSAutoThresholdDistance; ///< multiplier to use for autothresholding when using RMS to guess noise + uint32_t reserved[31]; ///< Reserved for future use +} cbOPTIONTABLE; + +/// @brief Color table for Central application +/// +/// Used for display configuration in Central +typedef struct { + uint32_t winrsvd[48]; ///< Reserved for Windows + uint32_t dispback; ///< Display background color + uint32_t dispgridmaj; ///< Display major grid color + uint32_t dispgridmin; ///< Display minor grid color + uint32_t disptext; ///< Display text color + uint32_t dispwave; ///< Display waveform color + uint32_t dispwavewarn; ///< Display waveform warning color + uint32_t dispwaveclip; ///< Display waveform clipping color + uint32_t dispthresh; ///< Display threshold color + uint32_t dispmultunit; ///< Display multi-unit color + uint32_t dispunit[16]; ///< Display unit colors (0 = unclassified) + uint32_t dispnoise; ///< Display noise color + uint32_t dispchansel[3]; ///< Display channel selection colors + uint32_t disptemp[5]; ///< Display temporary colors + uint32_t disprsvd[14]; ///< Reserved display colors +} cbCOLORTABLE; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Central's actual binary layout +/// +/// This struct matches Central's cbCFGBUFF field order EXACTLY (from cbhwlib.h). +/// It is NOT the same as CereLink's cbConfigBuffer (which reorders fields and adds +/// instrument_status). This struct is used in CENTRAL mode to read Central's shared +/// memory as a CLIENT. +/// +/// Key differences from CereLink's cbConfigBuffer: +/// - optiontable/colortable: 3rd/4th fields here (after sysflags), last fields in CereLink +/// - instrument_status: absent here (Central has no such concept) +/// - isLnc: after isWaveform here, before chaninfo in CereLink +/// - hwndCentral: omitted (at end, variable size, not needed) +/// +struct cbCFGBUFF { + uint32_t version; + uint32_t sysflags; + cbOPTIONTABLE optiontable; + cbCOLORTABLE colortable; + cbPKT_SYSINFO sysinfo; + cbPKT_PROCINFO procinfo[cbMAXPROCS]; + cbPKT_BANKINFO bankinfo[cbMAXPROCS][cbMAXBANKS]; + cbPKT_GROUPINFO groupinfo[cbMAXPROCS][cbMAXGROUPS]; + cbPKT_FILTINFO filtinfo[cbMAXPROCS][cbMAXFILTS]; + cbPKT_ADAPTFILTINFO adaptinfo[cbMAXPROCS]; + cbPKT_REFELECFILTINFO refelecinfo[cbMAXPROCS]; + cbPKT_CHANINFO chaninfo[cbMAXCHANS]; + cbSPIKE_SORTING isSortingOptions; + cbPKT_NTRODEINFO isNTrodeInfo[cbMAXNTRODES]; + cbPKT_AOUT_WAVEFORM isWaveform[AOUT_NUM_GAIN_CHANS][cbMAX_AOUT_TRIGGER]; + cbPKT_LNC isLnc[cbMAXPROCS]; + cbPKT_NPLAY isNPlay; + cbVIDEOSOURCE isVideoSource[cbMAXVIDEOSOURCE]; + cbTRACKOBJ isTrackObj[cbMAXTRACKOBJ]; + cbPKT_FILECFG fileinfo; + // hwndCentral omitted (at end, variable size, not needed by CereLink) +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Transmit buffer for outgoing packets (Global - sent to device) +/// +/// Ring buffer for packets waiting to be transmitted to device via UDP. +/// Buffer stores raw packet data as uint32_t words (Central's format). +/// +/// This is stored in a separate shared memory segment (not embedded in config buffer) +/// to match Central's architecture. +/// +struct cbXMTBUFF { + uint32_t transmitted; ///< How many packets have been sent + uint32_t headindex; ///< First empty position (write index) + uint32_t tailindex; ///< One past last emptied position (read index) + uint32_t last_valid_index; ///< Greatest valid starting index + uint32_t bufferlen; ///< Number of indices in buffer + uint32_t buffer[cbXMT_GLOBAL_BUFFLEN]; ///< Ring buffer for packet data +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Local transmit buffer (IPC-only packets) +/// +/// Smaller than Global buffer, used for cbSendLoopbackPacket() - packets meant only for +/// local processes, not sent to device. +/// +struct cbXMTBUFFLOCAL { + uint32_t transmitted; ///< How many packets have been sent + uint32_t headindex; ///< First empty position (write index) + uint32_t tailindex; ///< One past last emptied position (read index) + uint32_t last_valid_index; ///< Greatest valid starting index + uint32_t bufferlen; ///< Number of indices in buffer + uint32_t buffer[cbXMT_LOCAL_BUFFLEN]; ///< Ring buffer for packet data +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Spike cache buffer +/// +/// Caches recent spike packets for each channel to allow quick access without +/// scanning the entire receive buffer. +/// +struct cbSPKCACHE { + uint32_t chid; ///< Channel ID + uint32_t pktcnt; ///< Number of packets that can be saved + uint32_t pktsize; ///< Size of individual packet + uint32_t head; ///< Where to place next packet (circular) + uint32_t valid; ///< How many packets since last config + cbPKT_SPK spkpkt[cbPKT_SPKCACHEPKTCNT]; ///< Circular buffer of cached spikes +}; + +struct cbSPKBUFF { + uint32_t flags; ///< Status flags + uint32_t chidmax; ///< Maximum channel ID + uint32_t linesize; ///< Size of each cache line + uint32_t spkcount; ///< Total spike count + cbSPKCACHE cache[cbPKT_SPKCACHELINECNT]; ///< Per-channel spike caches +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Instrument status flags (bit field) +/// +/// Used to track which instruments are active in shared memory +/// +enum class InstrumentStatus : uint32_t { + INACTIVE = 0x00000000, ///< Instrument slot is not in use + ACTIVE = 0x00000001, ///< Instrument is active and has data +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief PC Status buffer (flattened from cbPcStatus class) +/// +/// IMPROVEMENT: Flattened to C struct for ABI stability and cross-compiler compatibility. +/// Central uses a C++ class which is fragile across different build environments. +/// +enum class NSPStatus : uint32_t { + NSP_INIT = 0, + NSP_NOIPADDR = 1, + NSP_NOREPLY = 2, + NSP_FOUND = 3, + NSP_INVALID = 4 +}; + +/// @brief App workspace entry (matches Central's APP_WORKSPACE from Launching.h) +/// +/// Central uses `enLaunchView` (C++ enum, sizeof(int) = 4 bytes) for the application field. +/// We use uint32_t for ABI compatibility. +/// +constexpr uint32_t cbMAXAPPWORKSPACES = 10; + +struct APP_WORKSPACE { + uint32_t m_nWorkspace; ///< Workspace number (1-based) + uint32_t m_nApplication; ///< Application index (enLaunchView in Central, uint32_t for ABI compat) + uint32_t m_nChannel; ///< Channel number displayed (1-based) + uint32_t m_nLeft; + uint32_t m_nTop; + uint32_t m_nRight; + uint32_t m_nBottom; +}; + +struct cbPcStatus { + // Public data + cbPKT_UNIT_SELECTION isSelection[cbMAXPROCS]; ///< Unit selection per instrument + + // Status fields (was private in cbPcStatus) + int32_t m_iBlockRecording; ///< Recording block counter + uint32_t m_nPCStatusFlags; ///< PC status flags + uint32_t m_nNumFEChans; ///< Number of FE channels + uint32_t m_nNumAnainChans; ///< Number of analog input channels + uint32_t m_nNumAnalogChans; ///< Number of analog channels + uint32_t m_nNumAoutChans; ///< Number of analog output channels + uint32_t m_nNumAudioChans; ///< Number of audio channels + uint32_t m_nNumAnalogoutChans; ///< Number of analog output channels + uint32_t m_nNumDiginChans; ///< Number of digital input channels + uint32_t m_nNumSerialChans; ///< Number of serial channels + uint32_t m_nNumDigoutChans; ///< Number of digital output channels + uint32_t m_nNumTotalChans; ///< Total channel count + NSPStatus m_nNspStatus[cbMAXPROCS]; ///< NSP status per instrument + uint32_t m_nNumNTrodesPerInstrument[cbMAXPROCS];///< NTrode count per instrument + uint32_t m_nGeminiSystem; ///< Gemini system flag + APP_WORKSPACE m_icAppWorkspace[cbMAXAPPWORKSPACES]; ///< App workspace config +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Receive buffer for incoming packets (simplified for Phase 2) +/// +struct cbRECBUFF { + uint32_t received; ///< Number of packets received + PROCTIME lasttime; ///< Last timestamp + uint32_t headwrap; ///< Head wrap counter + uint32_t headindex; ///< Current head index + uint32_t buffer[cbRECBUFFLEN]; ///< Packet buffer +}; + +} // namespace central_v7_7 + +} // namespace cbshm + +#pragma pack(pop) + +#endif // CBSHMEM_CENTRAL_TYPES_V7_7_H diff --git a/src/cbshm/include/cbshm/central_types/v4_2.h b/src/cbshm/include/cbshm/central_types/v7_8.h similarity index 89% rename from src/cbshm/include/cbshm/central_types/v4_2.h rename to src/cbshm/include/cbshm/central_types/v7_8.h index 4088cb05..1062b73e 100644 --- a/src/cbshm/include/cbshm/central_types/v4_2.h +++ b/src/cbshm/include/cbshm/central_types/v7_8.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file v4_2.h +/// @file v7_8.h /// @author Caden Shmookler /// @date 2026-05-15 /// @@ -12,8 +12,8 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#ifndef CBSHM_CENTRAL_TYPES_V4_2_H -#define CBSHM_CENTRAL_TYPES_V4_2_H +#ifndef CBSHM_CENTRAL_TYPES_V7_8_H +#define CBSHM_CENTRAL_TYPES_V7_8_H #include @@ -22,7 +22,7 @@ namespace cbshm { -namespace central_v4_2 { +namespace central_v7_8 { /////////////////////////////////////////////////////////////////////////////////////////////////// /// @name Protocol Version @@ -33,13 +33,14 @@ constexpr uint32_t cbVERSION_MINOR = 2; /// @} +namespace wire { + /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @name Central Constants +/// @name cbproto Constants /// @{ -// These MUST match Central's constants -constexpr uint32_t cbMAXPROCS = 4; ///< Central supports up to 4 NSPs -constexpr uint32_t cbNUM_FE_CHANS = 768; ///< Central supports 768 FE channels +constexpr uint32_t cbMAXPROCS = 1; ///< Maximum supported NSPs +constexpr uint32_t cbNUM_FE_CHANS = 256; ///< Maximum supported front-end channels constexpr uint32_t cbMAXGROUPS = 8; ///< Sample rate groups constexpr uint32_t cbMAXFILTS = 32; ///< Digital filters constexpr uint32_t cbMAXVIDEOSOURCE = 1; ///< Maximum number of video sources @@ -66,47 +67,6 @@ constexpr uint32_t cbMAXCHANS = (cbNUM_ANALOG_CHANS + cbNUM_ANALOGOUT_CHANS + cbNUM_DIGIN_CHANS + cbNUM_SERIAL_CHANS + cbNUM_DIGOUT_CHANS); -// Bank definitions -constexpr uint32_t cbCHAN_PER_BANK = 32; -constexpr uint32_t cbNUM_FE_BANKS = cbNUM_FE_CHANS / cbCHAN_PER_BANK; -constexpr uint32_t cbNUM_ANAIN_BANKS = 1; -constexpr uint32_t cbNUM_ANAOUT_BANKS = 1; -constexpr uint32_t cbNUM_AUDOUT_BANKS = 1; -constexpr uint32_t cbNUM_DIGIN_BANKS = 1; -constexpr uint32_t cbNUM_SERIAL_BANKS = 1; -constexpr uint32_t cbNUM_DIGOUT_BANKS = 1; - -constexpr uint32_t cbMAXBANKS = (cbNUM_FE_BANKS + cbNUM_ANAIN_BANKS + - cbNUM_ANAOUT_BANKS + cbNUM_AUDOUT_BANKS + - cbNUM_DIGIN_BANKS + cbNUM_SERIAL_BANKS + - cbNUM_DIGOUT_BANKS); - -/// @} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @name Buffer Size Constants (must be defined before structures) -/// @{ - -/// Max UDP packet size (from Central) -constexpr uint32_t cbCER_UDP_SIZE_MAX = 58080; - -/// Transmit buffer sizes (Central-compatible) -constexpr uint32_t cbXMT_GLOBAL_BUFFLEN = ((cbCER_UDP_SIZE_MAX / 4) * 5000 + 2); ///< Room for 5000 packet-sized slots -constexpr uint32_t cbXMT_LOCAL_BUFFLEN = ((cbCER_UDP_SIZE_MAX / 4) * 2000 + 2); ///< Room for 2000 packet-sized slots - -/// N-Trode count (Central uses cbNUM_FE_CHANS / 2, not cbNUM_ANALOG_CHANS / 2) -constexpr uint32_t cbMAXNTRODES = cbNUM_FE_CHANS / 2; ///< = 384 - -/// Analog output gain channels (Central's multi-instrument count) -constexpr uint32_t AOUT_NUM_GAIN_CHANS = cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS; ///< = 24 - -/// Spike cache constants -constexpr uint32_t cbPKT_SPKCACHEPKTCNT = 400; ///< Packets per channel cache -constexpr uint32_t cbPKT_SPKCACHELINECNT = cbMAXCHANS; ///< One cache per channel (Central uses cbMAXCHANS, not cbNUM_ANALOG_CHANS) - -/// Receive buffer size -constexpr uint32_t cbRECBUFFLEN = cbNUM_FE_CHANS * 65536 * 4 - 1; - /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -122,8 +82,10 @@ constexpr uint32_t cbMAX_COMMENT = 128; ///< Maximum comment length (must be /// @} +} // namespace wire + /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @name Central config buffer subtypes +/// @name Data Packet Structures /// @{ typedef uint64_t PROCTIME; @@ -141,35 +103,6 @@ typedef struct { constexpr uint32_t cbPKT_MAX_SIZE = 1024; ///< Maximum packet size in bytes constexpr uint32_t cbPKT_HEADER_SIZE = sizeof(cbPKT_HEADER); ///< Packet header size in bytes -/// @brief Option table for Central application -/// -/// Used for configuration options in Central -typedef struct { - float fRMSAutoThresholdDistance; ///< multiplier to use for autothresholding when using RMS to guess noise - uint32_t reserved[31]; ///< Reserved for future use -} cbOPTIONTABLE; - -/// @brief Color table for Central application -/// -/// Used for display configuration in Central -typedef struct { - uint32_t winrsvd[48]; ///< Reserved for Windows - uint32_t dispback; ///< Display background color - uint32_t dispgridmaj; ///< Display major grid color - uint32_t dispgridmin; ///< Display minor grid color - uint32_t disptext; ///< Display text color - uint32_t dispwave; ///< Display waveform color - uint32_t dispwavewarn; ///< Display waveform warning color - uint32_t dispwaveclip; ///< Display waveform clipping color - uint32_t dispthresh; ///< Display threshold color - uint32_t dispmultunit; ///< Display multi-unit color - uint32_t dispunit[16]; ///< Display unit colors (0 = unclassified) - uint32_t dispnoise; ///< Display noise color - uint32_t dispchansel[3]; ///< Display channel selection colors - uint32_t disptemp[5]; ///< Display temporary colors - uint32_t disprsvd[14]; ///< Reserved display colors -} cbCOLORTABLE; - /// @brief PKT Set:0x92 Rep:0x12 - System info /// /// Contains system information including the runlevel @@ -192,7 +125,7 @@ typedef struct { uint32_t proc; ///< index of the bank uint32_t idcode; ///< manufacturer part and rom ID code of the Signal Processor - char ident[cbLEN_STR_IDENT]; ///< ID string with the equipment name of the Signal Processor + char ident[wire::cbLEN_STR_IDENT]; ///< ID string with the equipment name of the Signal Processor uint32_t chanbase; ///< lowest channel number of channel id range claimed by this processor uint32_t chancount; ///< number of channel identifiers claimed by this processor uint32_t bankcount; ///< number of signal banks supported by the processor @@ -212,8 +145,8 @@ typedef struct { uint32_t proc; ///< the address of the processor on which the bank resides uint32_t bank; ///< the address of the bank reported by the packet uint32_t idcode; ///< manufacturer part and rom ID code of the module addressed to this bank - char ident[cbLEN_STR_IDENT]; ///< ID string with the equipment name of the Signal Bank hardware module - char label[cbLEN_STR_LABEL]; ///< Label on the instrument for the signal bank, eg "Analog In" + char ident[wire::cbLEN_STR_IDENT]; ///< ID string with the equipment name of the Signal Bank hardware module + char label[wire::cbLEN_STR_LABEL]; ///< Label on the instrument for the signal bank, eg "Analog In" uint32_t chanbase; ///< lowest channel number of channel id range claimed by this bank uint32_t chancount; ///< number of channel identifiers claimed by this bank } cbPKT_BANKINFO; @@ -227,10 +160,10 @@ typedef struct { uint32_t proc; ///< processor number uint32_t group; ///< group number - char label[cbLEN_STR_LABEL]; ///< sampling group label + char label[wire::cbLEN_STR_LABEL]; ///< sampling group label uint32_t period; ///< sampling period for the group uint32_t length; ///< number of channels in the list - uint16_t list[cbNUM_ANALOG_CHANS]; ///< variable length list. The max size is the total number of analog channels + uint16_t list[wire::cbNUM_ANALOG_CHANS]; ///< variable length list. The max size is the total number of analog channels } cbPKT_GROUPINFO; /// @brief PKT Set:0xA3 Rep:0x23 - Filter Information Packet @@ -241,7 +174,7 @@ typedef struct { uint32_t proc; ///< uint32_t filt; ///< - char label[cbLEN_STR_FILT_LABEL]; // name of the filter + char label[wire::cbLEN_STR_FILT_LABEL]; // name of the filter uint32_t hpfreq; ///< high-pass corner frequency in milliHertz uint32_t hporder; ///< high-pass filter order uint32_t hptype; ///< high-pass filter type @@ -296,14 +229,14 @@ typedef struct { int32_t anamin; ///< the minimum analog value present in the signal int32_t anamax; ///< the maximum analog value present in the signal int32_t anagain; ///< the gain applied to the default analog values to get the analog values - char anaunit[cbLEN_STR_UNIT]; ///< the unit for the analog signal (eg, "uV" or "MPa") + char anaunit[wire::cbLEN_STR_UNIT]; ///< the unit for the analog signal (eg, "uV" or "MPa") } cbSCALING; /// @brief Filter description structure /// /// Filter description used in cbPKT_CHANINFO typedef struct { - char label[cbLEN_STR_FILT_LABEL]; + char label[wire::cbLEN_STR_FILT_LABEL]; uint32_t hpfreq; ///< high-pass corner frequency in milliHertz uint32_t hporder; ///< high-pass filter order uint32_t hptype; ///< high-pass filter type @@ -354,7 +287,7 @@ typedef struct { cbFILTDESC phyfiltin; ///< physical channel filter definition cbSCALING physcalout; ///< physical channel scaling information cbFILTDESC phyfiltout; ///< physical channel filter definition - char label[cbLEN_STR_LABEL]; ///< Label of the channel (null terminated if <16 characters) + char label[wire::cbLEN_STR_LABEL]; ///< Label of the channel (null terminated if <16 characters) uint32_t userflags; ///< User flags for the channel state int32_t position[4]; ///< reserved for future position information cbSCALING scalin; ///< user-defined scaling information for AINP @@ -396,8 +329,8 @@ typedef struct { int16_t amplrejpos; ///< Amplitude rejection positive value int16_t amplrejneg; ///< Amplitude rejection negative value uint32_t refelecchan; ///< Software reference electrode channel - cbMANUALUNITMAPPING unitmapping[cbMAXUNITS]; ///< manual unit mapping - cbHOOP spkhoops[cbMAXUNITS][cbMAXHOOPS]; ///< spike hoop sorting set + cbMANUALUNITMAPPING unitmapping[wire::cbMAXUNITS]; ///< manual unit mapping + cbHOOP spkhoops[wire::cbMAXUNITS][wire::cbMAXHOOPS]; ///< spike hoop sorting set } cbPKT_CHANINFO; /// @brief PKT Set:0xDB Rep:0x5B - Feature Space Basis @@ -412,7 +345,7 @@ typedef struct uint32_t mode; ///< cbBASIS_CHANGE, cbUNDO_BASIS_CHANGE, cbREDO_BASIS_CHANGE, cbINVALIDATE_BASIS ... uint32_t fs; ///< Feature space: cbAUTOALG_PCA /// basis must be the last item in the structure because it can be variable length to a max of cbMAX_PNTS - float basis[cbMAX_PNTS][3]; ///< Room for all possible points collected + float basis[wire::cbMAX_PNTS][3]; ///< Room for all possible points collected } cbPKT_FS_BASIS; /// @brief PKT Set:0xD1 Rep:0x51 - Get the spike sorting model for a single channel (Histogram Peak Count) @@ -521,13 +454,13 @@ typedef struct { /// /// Groups all spike-sorting related configuration packets together. typedef struct { - cbPKT_FS_BASIS asBasis[cbMAXCHANS]; ///< PCA basis values per channel - cbPKT_SS_MODELSET asSortModel[cbMAXCHANS][cbMAXUNITS + 2]; ///< Sorting models/rules per channel + cbPKT_FS_BASIS asBasis[wire::cbMAXCHANS]; ///< PCA basis values per channel + cbPKT_SS_MODELSET asSortModel[wire::cbMAXCHANS][wire::cbMAXUNITS + 2]; ///< Sorting models/rules per channel //////// These are spike sorting options cbPKT_SS_DETECT pktDetect; ///< Detection parameters cbPKT_SS_ARTIF_REJECT pktArtifReject; ///< Artifact rejection parameters - cbPKT_SS_NOISE_BOUNDARY pktNoiseBoundary[cbMAXCHANS]; ///< Noise boundaries per channel + cbPKT_SS_NOISE_BOUNDARY pktNoiseBoundary[wire::cbMAXCHANS]; ///< Noise boundaries per channel cbPKT_SS_STATISTICS pktStatistics; ///< Spike statistics cbPKT_SS_STATUS pktStatus; ///< Spike sorting status } cbSPIKE_SORTING; @@ -539,11 +472,11 @@ typedef struct { cbPKT_HEADER cbpkt_header; ///< packet header uint32_t ntrode; ///< ntrode with which we are working (1-based) - char label[cbLEN_STR_LABEL]; ///< Label of the Ntrode (null terminated if < 16 characters) - cbMANUALUNITMAPPING ellipses[cbMAXSITEPLOTS][cbMAXUNITS]; ///< unit mapping + char label[wire::cbLEN_STR_LABEL]; ///< Label of the Ntrode (null terminated if < 16 characters) + cbMANUALUNITMAPPING ellipses[wire::cbMAXSITEPLOTS][wire::cbMAXUNITS]; ///< unit mapping uint16_t nSite; ///< number channels in this NTrode ( 0 <= nSite <= cbMAXSITES) uint16_t fs; ///< NTrode feature space cbNTRODEINFO_FS_* - uint16_t nChan[cbMAXSITES]; ///< group of channels in this NTrode + uint16_t nChan[wire::cbMAXSITES]; ///< group of channels in this NTrode } cbPKT_NTRODEINFO; constexpr uint32_t cbMAX_WAVEFORM_PHASES = ((cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - 24) / 4); ///< Maximum number of phases in a waveform @@ -631,13 +564,13 @@ typedef struct { /// @brief NeuroMotive video source typedef struct { - char name[cbLEN_STR_LABEL]; ///< filename of the video file + char name[wire::cbLEN_STR_LABEL]; ///< filename of the video file float fps; ///< nominal record fps } cbVIDEOSOURCE; /// @brief Track object structure for NeuroMotive typedef struct { - char name[cbLEN_STR_LABEL]; ///< name of the object + char name[wire::cbLEN_STR_LABEL]; ///< name of the object uint16_t type; ///< trackable type (cbTRACKOBJ_TYPE_*) uint16_t pointCount; ///< maximum number of points } cbTRACKOBJ; @@ -655,16 +588,150 @@ typedef struct { uint32_t extctrl; ///< If cbFILECFG_OPT_REC this is split number (0 for non-TOC) ///< If cbFILECFG_OPT_STOP this is error code (0 means no error) - char username[cbLEN_STR_COMMENT]; ///< name of computer issuing the packet + char username[wire::cbLEN_STR_COMMENT]; ///< name of computer issuing the packet union { - char filename[cbLEN_STR_COMMENT]; ///< filename to record to - char datetime[cbLEN_STR_COMMENT]; ///< + char filename[wire::cbLEN_STR_COMMENT]; ///< filename to record to + char datetime[wire::cbLEN_STR_COMMENT]; ///< }; - char comment[cbLEN_STR_COMMENT]; ///< comment to include in the file + char comment[wire::cbLEN_STR_COMMENT]; ///< comment to include in the file } cbPKT_FILECFG; /// @} +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Data packet - Spike waveform data +/// +/// Detected spikes are sent through this packet. The spike waveform may or may not be sent depending +/// on the dlen contained in the header. The waveform can be anywhere from 30 samples to 128 samples +/// based on user configuration. The default spike length is 48 samples. cbpkt_header.chid is the +/// channel number of the spike. cbpkt_header.type is the sorted unit number (0=unsorted, 255=noise). +typedef struct { + cbPKT_HEADER cbpkt_header; ///< in the header for this packet, the type is used as the unit number + + float fPattern[3]; ///< values of the pattern space (Normal uses only 2, PCA uses third) + int16_t nPeak; ///< highest datapoint of the waveform + int16_t nValley; ///< lowest datapoint of the waveform + + int16_t wave[wire::cbMAX_PNTS]; ///< datapoints of each sample of the waveform. Room for all possible points collected + ///< wave must be the last item in the structure because it can be variable length to a max of cbMAX_PNTS +} cbPKT_SPK; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Unit Selection +/// +/// Packet which says that these channels are now selected +typedef struct +{ + cbPKT_HEADER cbpkt_header; ///< packet header + + int32_t lastchan; ///< Which channel was clicked last. + uint16_t abyUnitSelections[(cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - sizeof(int32_t))]; ///< one for each channel, channels are 0 based here, shows units selected +} cbPKT_UNIT_SELECTION; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Central Constants +/// @{ + +constexpr uint32_t cbMAXPROCS = 4; ///< Maximum supported NSPs +constexpr uint32_t cbNUM_FE_CHANS = 768; ///< Maximum supported front-end channels +constexpr uint32_t cbMAXGROUPS = 8; ///< Sample rate groups +constexpr uint32_t cbMAXFILTS = 32; ///< Digital filters +constexpr uint32_t cbMAXVIDEOSOURCE = 1; ///< Maximum number of video sources +constexpr uint32_t cbMAXTRACKOBJ = 20; ///< Maximum number of trackable objects +constexpr uint32_t cbMAXHOOPS = 4; ///< Maximum number of hoops for spike sorting +constexpr uint32_t cbMAXSITES = 4; ///< Maximum number of electrodes in an n-trode group +constexpr uint32_t cbMAXSITEPLOTS = ((cbMAXSITES - 1) * cbMAXSITES / 2); ///< Combination of 2 out of n +constexpr uint32_t cbMAXUNITS = 5; ///< Maximum number of sorted units per channel +constexpr uint32_t cbMAX_PNTS = 128; ///< Maximum spike waveform points +constexpr uint32_t cbMAX_AOUT_TRIGGER = 5; ///< Maximum number of per-channel (analog output, or digital output) triggers + +// Channel counts +constexpr uint32_t cbNUM_ANAIN_CHANS = 16 * cbMAXPROCS; +constexpr uint32_t cbNUM_ANALOG_CHANS = cbNUM_FE_CHANS + cbNUM_ANAIN_CHANS; +constexpr uint32_t cbNUM_ANAOUT_CHANS = 4 * cbMAXPROCS; +constexpr uint32_t cbNUM_AUDOUT_CHANS = 2 * cbMAXPROCS; +constexpr uint32_t cbNUM_ANALOGOUT_CHANS = cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS; +constexpr uint32_t cbNUM_DIGIN_CHANS = 1 * cbMAXPROCS; +constexpr uint32_t cbNUM_SERIAL_CHANS = 1 * cbMAXPROCS; +constexpr uint32_t cbNUM_DIGOUT_CHANS = 4 * cbMAXPROCS; + +// Total channels +constexpr uint32_t cbMAXCHANS = (cbNUM_ANALOG_CHANS + cbNUM_ANALOGOUT_CHANS + + cbNUM_DIGIN_CHANS + cbNUM_SERIAL_CHANS + + cbNUM_DIGOUT_CHANS); + +// Bank definitions +constexpr uint32_t cbCHAN_PER_BANK = 32; +constexpr uint32_t cbNUM_FE_BANKS = cbNUM_FE_CHANS / cbCHAN_PER_BANK; +constexpr uint32_t cbNUM_ANAIN_BANKS = 1; +constexpr uint32_t cbNUM_ANAOUT_BANKS = 1; +constexpr uint32_t cbNUM_AUDOUT_BANKS = 1; +constexpr uint32_t cbNUM_DIGIN_BANKS = 1; +constexpr uint32_t cbNUM_SERIAL_BANKS = 1; +constexpr uint32_t cbNUM_DIGOUT_BANKS = 1; + +constexpr uint32_t cbMAXBANKS = (cbNUM_FE_BANKS + cbNUM_ANAIN_BANKS + + cbNUM_ANAOUT_BANKS + cbNUM_AUDOUT_BANKS + + cbNUM_DIGIN_BANKS + cbNUM_SERIAL_BANKS + + cbNUM_DIGOUT_BANKS); + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Buffer Size Constants (must be defined before structures) +/// @{ + +/// Max UDP packet size (from Central) +constexpr uint32_t cbCER_UDP_SIZE_MAX = 58080; + +/// Transmit buffer sizes (Central-compatible) +constexpr uint32_t cbXMT_GLOBAL_BUFFLEN = ((cbCER_UDP_SIZE_MAX / 4) * 5000 + 2); ///< Room for 5000 packet-sized slots +constexpr uint32_t cbXMT_LOCAL_BUFFLEN = ((cbCER_UDP_SIZE_MAX / 4) * 2000 + 2); ///< Room for 2000 packet-sized slots + +/// N-Trode count (Central uses cbNUM_FE_CHANS / 2, not cbNUM_ANALOG_CHANS / 2) +constexpr uint32_t cbMAXNTRODES = cbNUM_FE_CHANS / 2; ///< = 384 + +/// Analog output gain channels (Central's multi-instrument count) +constexpr uint32_t AOUT_NUM_GAIN_CHANS = cbNUM_ANAOUT_CHANS + cbNUM_AUDOUT_CHANS; ///< = 24 + +/// Spike cache constants +constexpr uint32_t cbPKT_SPKCACHEPKTCNT = 400; ///< Packets per channel cache +constexpr uint32_t cbPKT_SPKCACHELINECNT = cbMAXCHANS; ///< One cache per channel (Central uses cbMAXCHANS, not cbNUM_ANALOG_CHANS) + +/// Receive buffer size +constexpr uint32_t cbRECBUFFLEN = cbNUM_FE_CHANS * 65536 * 4 - 1; + +/// @} + +/// @brief Option table for Central application +/// +/// Used for configuration options in Central +typedef struct { + float fRMSAutoThresholdDistance; ///< multiplier to use for autothresholding when using RMS to guess noise + uint32_t reserved[31]; ///< Reserved for future use +} cbOPTIONTABLE; + +/// @brief Color table for Central application +/// +/// Used for display configuration in Central +typedef struct { + uint32_t winrsvd[48]; ///< Reserved for Windows + uint32_t dispback; ///< Display background color + uint32_t dispgridmaj; ///< Display major grid color + uint32_t dispgridmin; ///< Display minor grid color + uint32_t disptext; ///< Display text color + uint32_t dispwave; ///< Display waveform color + uint32_t dispwavewarn; ///< Display waveform warning color + uint32_t dispwaveclip; ///< Display waveform clipping color + uint32_t dispthresh; ///< Display threshold color + uint32_t dispmultunit; ///< Display multi-unit color + uint32_t dispunit[16]; ///< Display unit colors (0 = unclassified) + uint32_t dispnoise; ///< Display noise color + uint32_t dispchansel[3]; ///< Display channel selection colors + uint32_t disptemp[5]; ///< Display temporary colors + uint32_t disprsvd[14]; ///< Reserved display colors +} cbCOLORTABLE; + /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Central's actual binary layout /// @@ -736,24 +803,6 @@ struct cbXMTBUFFLOCAL { uint32_t buffer[cbXMT_LOCAL_BUFFLEN]; ///< Ring buffer for packet data }; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Data packet - Spike waveform data -/// -/// Detected spikes are sent through this packet. The spike waveform may or may not be sent depending -/// on the dlen contained in the header. The waveform can be anywhere from 30 samples to 128 samples -/// based on user configuration. The default spike length is 48 samples. cbpkt_header.chid is the -/// channel number of the spike. cbpkt_header.type is the sorted unit number (0=unsorted, 255=noise). -typedef struct { - cbPKT_HEADER cbpkt_header; ///< in the header for this packet, the type is used as the unit number - - float fPattern[3]; ///< values of the pattern space (Normal uses only 2, PCA uses third) - int16_t nPeak; ///< highest datapoint of the waveform - int16_t nValley; ///< lowest datapoint of the waveform - - int16_t wave[cbMAX_PNTS]; ///< datapoints of each sample of the waveform. Room for all possible points collected - ///< wave must be the last item in the structure because it can be variable length to a max of cbMAX_PNTS -} cbPKT_SPK; - /////////////////////////////////////////////////////////////////////////////////////////////////// /// @brief Spike cache buffer /// @@ -818,18 +867,6 @@ struct APP_WORKSPACE { uint32_t m_nBottom; }; -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @brief Unit Selection -/// -/// Packet which says that these channels are now selected -typedef struct -{ - cbPKT_HEADER cbpkt_header; ///< packet header - - int32_t lastchan; ///< Which channel was clicked last. - uint16_t abyUnitSelections[(cbPKT_MAX_SIZE - cbPKT_HEADER_SIZE - sizeof(int32_t))]; ///< one for each channel, channels are 0 based here, shows units selected -} cbPKT_UNIT_SELECTION; - struct cbPcStatus { // Public data cbPKT_UNIT_SELECTION isSelection[cbMAXPROCS]; ///< Unit selection per instrument @@ -864,10 +901,10 @@ struct cbRECBUFF { uint32_t buffer[cbRECBUFFLEN]; ///< Packet buffer }; -} // namespace central_v4_2 +} // namespace central_v7_8 } // namespace cbshm #pragma pack(pop) -#endif // CBSHMEM_CENTRAL_TYPES_V4_2_H +#endif // CBSHMEM_CENTRAL_TYPES_V7_8_H diff --git a/src/cbshm/src/central_adapters/v3_11.cpp b/src/cbshm/src/central_adapters/v7_0.cpp similarity index 99% rename from src/cbshm/src/central_adapters/v3_11.cpp rename to src/cbshm/src/central_adapters/v7_0.cpp index 5aab7f74..1cbb89f2 100644 --- a/src/cbshm/src/central_adapters/v3_11.cpp +++ b/src/cbshm/src/central_adapters/v7_0.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file v3_11.cpp +/// @file v7_0.cpp /// @author Caden Shmookler /// @date 2026-05-22 /// @@ -7,12 +7,12 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#include -#include +#include +#include namespace cbshm { -namespace central_v3_11 { +namespace central_v7_0 { size_t BootstrapAdapter::getConfigBufferSize() const { return sizeof(cbCFGBUFF); @@ -1104,6 +1104,6 @@ cbutil::Result Adapter::setGeminiSystem(bool is_gemini) const { return cbutil::Result::error("Central v3.11 does not recognize Gemini systems"); } -} // namespace central_v3_11 +} // namespace central_v7_0 } // namespace cbshm diff --git a/src/cbshm/src/central_adapters/v4_0.cpp b/src/cbshm/src/central_adapters/v7_5.cpp similarity index 99% rename from src/cbshm/src/central_adapters/v4_0.cpp rename to src/cbshm/src/central_adapters/v7_5.cpp index d0c61b10..4f2512d2 100644 --- a/src/cbshm/src/central_adapters/v4_0.cpp +++ b/src/cbshm/src/central_adapters/v7_5.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file v4_0.cpp +/// @file v7_5.cpp /// @author Caden Shmookler /// @date 2026-05-22 /// @@ -7,12 +7,12 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#include -#include +#include +#include namespace cbshm { -namespace central_v4_0 { +namespace central_v7_5 { size_t BootstrapAdapter::getConfigBufferSize() const { return sizeof(cbCFGBUFF); @@ -1107,6 +1107,6 @@ cbutil::Result Adapter::setGeminiSystem(bool is_gemini) const { return cbutil::Result::ok(); } -} // namespace central_v4_0 +} // namespace central_v7_5 } // namespace cbshm diff --git a/src/cbshm/src/central_adapters/v4_1.cpp b/src/cbshm/src/central_adapters/v7_6.cpp similarity index 99% rename from src/cbshm/src/central_adapters/v4_1.cpp rename to src/cbshm/src/central_adapters/v7_6.cpp index f2d53153..9caecac4 100644 --- a/src/cbshm/src/central_adapters/v4_1.cpp +++ b/src/cbshm/src/central_adapters/v7_6.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file v4_1.cpp +/// @file v7_6.cpp /// @author Caden Shmookler /// @date 2026-05-22 /// @@ -7,12 +7,12 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#include -#include +#include +#include namespace cbshm { -namespace central_v4_1 { +namespace central_v7_6 { size_t BootstrapAdapter::getConfigBufferSize() const { return sizeof(cbCFGBUFF); @@ -1111,6 +1111,6 @@ cbutil::Result Adapter::setGeminiSystem(bool is_gemini) const { return cbutil::Result::ok(); } -} // namespace central_v4_1 +} // namespace central_v7_6 } // namespace cbshm diff --git a/src/cbshm/src/central_adapters/v4_2.cpp b/src/cbshm/src/central_adapters/v7_7.cpp similarity index 99% rename from src/cbshm/src/central_adapters/v4_2.cpp rename to src/cbshm/src/central_adapters/v7_7.cpp index 0fbe9ef1..cd045f9d 100644 --- a/src/cbshm/src/central_adapters/v4_2.cpp +++ b/src/cbshm/src/central_adapters/v7_7.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// -/// @file v4_2.cpp +/// @file v7_7.cpp /// @author Caden Shmookler /// @date 2026-05-22 /// @@ -7,12 +7,12 @@ /// /////////////////////////////////////////////////////////////////////////////////////////////////// -#include -#include +#include +#include namespace cbshm { -namespace central_v4_2 { +namespace central_v7_7 { size_t BootstrapAdapter::getConfigBufferSize() const { return sizeof(cbCFGBUFF); @@ -1112,6 +1112,6 @@ cbutil::Result Adapter::setGeminiSystem(bool is_gemini) const { return cbutil::Result::ok(); } -} // namespace central_v4_2 +} // namespace central_v7_7 } // namespace cbshm diff --git a/src/cbshm/src/central_adapters/v7_8.cpp b/src/cbshm/src/central_adapters/v7_8.cpp new file mode 100644 index 00000000..35b3dd57 --- /dev/null +++ b/src/cbshm/src/central_adapters/v7_8.cpp @@ -0,0 +1,1117 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v7_8.cpp +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Central adapter implementation +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include + +namespace cbshm { + +namespace central_v7_8 { + +size_t BootstrapAdapter::getConfigBufferSize() const { + return sizeof(cbCFGBUFF); +} + +size_t BootstrapAdapter::getReceiveBufferSize() const { + return sizeof(cbRECBUFF); +} + +size_t BootstrapAdapter::getTransmitBufferSize() const { + return sizeof(cbXMTBUFF); +} + +size_t BootstrapAdapter::getTransmitBufferLocalSize() const { + return sizeof(cbXMTBUFFLOCAL); +} + +size_t BootstrapAdapter::getStatusBufferSize() const { + return sizeof(cbPcStatus); +} + +size_t BootstrapAdapter::getSpikeBufferSize() const { + return sizeof(cbSPKBUFF); +} + +size_t BootstrapAdapter::getReceiveBufferLen() const { + return sizeof(cbRECBUFFLEN); +} + +void Adapter::fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const { + cur.time = leg.time; + cur.chid = leg.chid; + cur.type = leg.type; + cur.dlen = leg.dlen; + cur.instrument = leg.instrument; + cur.reserved = leg.reserved; +} + +void Adapter::fromLegacy(::cbPKT_SYSINFO& cur, const cbPKT_SYSINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.sysfreq = leg.sysfreq; + cur.spikelen = leg.spikelen; + cur.spikepre = leg.spikepre; + cur.resetque = leg.resetque; + cur.runlevel = leg.runlevel; + cur.runflags = leg.runflags; +} + +void Adapter::fromLegacy(::cbPKT_PROCINFO& cur, const cbPKT_PROCINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.proc = leg.proc; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; + cur.bankcount = leg.bankcount; + cur.groupcount = leg.groupcount; + cur.filtcount = leg.filtcount; + cur.sortcount = leg.sortcount; + cur.unitcount = leg.unitcount; + cur.hoopcount = leg.hoopcount; + cur.reserved = leg.reserved; + cur.version = leg.version; +} + +void Adapter::fromLegacy(::cbPKT_BANKINFO& cur, const cbPKT_BANKINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.idcode = leg.idcode; + copyArr(cur.ident, leg.ident); + copyArr(cur.label, leg.label); + cur.chanbase = leg.chanbase; + cur.chancount = leg.chancount; +} + +void Adapter::fromLegacy(::cbPKT_GROUPINFO& cur, const cbPKT_GROUPINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.proc = leg.proc; + cur.group = leg.group; + copyArr(cur.label, leg.label); + cur.period = leg.period; + cur.length = leg.length; + copyArr(cur.list, leg.list); +} + +void Adapter::fromLegacy(::cbPKT_FILTINFO& cur, const cbPKT_FILTINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.proc = leg.proc; + cur.filt = leg.filt; + copyArr(cur.label, leg.label); + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; + cur.gain = leg.gain; + cur.sos1a1 = leg.sos1a1; + cur.sos1a2 = leg.sos1a2; + cur.sos1b1 = leg.sos1b1; + cur.sos1b2 = leg.sos1b2; + cur.sos2a1 = leg.sos2a1; + cur.sos2a2 = leg.sos2a2; + cur.sos2b1 = leg.sos2b1; + cur.sos2b2 = leg.sos2b2; +} + +void Adapter::fromLegacy(::cbPKT_ADAPTFILTINFO& cur, const cbPKT_ADAPTFILTINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.dLearningRate = leg.dLearningRate; + cur.nRefChan1 = leg.nRefChan1; + cur.nRefChan2 = leg.nRefChan2; +} + +void Adapter::fromLegacy(::cbPKT_REFELECFILTINFO& cur, const cbPKT_REFELECFILTINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.chan = leg.chan; + cur.nMode = leg.nMode; + cur.nRefChan = leg.nRefChan; +} + +void Adapter::fromLegacy(::cbSCALING& cur, const cbSCALING& leg) const { + cur.digmin = leg.digmin; + cur.digmax = leg.digmax; + cur.anamin = leg.anamin; + cur.anamax = leg.anamax; + cur.anagain = leg.anagain; + copyArr(cur.anaunit, leg.anaunit); +} + +void Adapter::fromLegacy(::cbFILTDESC& cur, const cbFILTDESC& leg) const { + cur.hpfreq = leg.hpfreq; + cur.hporder = leg.hporder; + cur.hptype = leg.hptype; + cur.lpfreq = leg.lpfreq; + cur.lporder = leg.lporder; + cur.lptype = leg.lptype; +} + +void Adapter::fromLegacy(::cbMANUALUNITMAPPING& cur, const cbMANUALUNITMAPPING& leg) const { + cur.nOverride = leg.nOverride; + copyArr(cur.afOrigin, leg.afOrigin); + copyArr2D(cur.afShape, leg.afShape); + cur.aPhi = leg.aPhi; + cur.bValid = leg.bValid; +} + +void Adapter::fromLegacy(::cbHOOP& cur, const cbHOOP& leg) const { + cur.valid = leg.valid; + cur.time = leg.time; + cur.min = leg.min; + cur.max = leg.max; +} + +void Adapter::fromLegacy(::cbPKT_CHANINFO& cur, const cbPKT_CHANINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.chan = leg.chan; + cur.proc = leg.proc; + cur.bank = leg.bank; + cur.term = leg.term; + cur.chancaps = leg.chancaps; + cur.doutcaps = leg.doutcaps; + cur.dinpcaps = leg.dinpcaps; + cur.aoutcaps = leg.aoutcaps; + cur.ainpcaps = leg.ainpcaps; + cur.spkcaps = leg.spkcaps; + fromLegacy(cur.physcalin, leg.physcalin); + fromLegacy(cur.phyfiltin, leg.phyfiltin); + fromLegacy(cur.physcalout, leg.physcalout); + fromLegacy(cur.phyfiltout, leg.phyfiltout); + copyArr(cur.label, leg.label); + cur.userflags = leg.userflags; + copyArr(cur.position, leg.position); + fromLegacy(cur.scalin, leg.scalin); + fromLegacy(cur.scalout, leg.scalout); + cur.doutopts = leg.doutopts; + cur.dinpopts = leg.dinpopts; + cur.aoutopts = leg.aoutopts; + cur.eopchar = leg.eopchar; + cur.moninst = leg.moninst; // aka lowsamples + cur.monchan = leg.monchan; // aka highsamples + cur.outvalue = leg.outvalue; // aka offset + cur.trigtype = leg.trigtype; + copyArr(cur.reserved, leg.reserved); + cur.triginst = leg.triginst; + cur.trigchan = leg.trigchan; + cur.trigval = leg.trigval; + cur.ainpopts = leg.ainpopts; + cur.lncrate = leg.lncrate; + cur.smpfilter = leg.smpfilter; + cur.smpgroup = leg.smpgroup; + cur.smpdispmin = leg.smpdispmin; + cur.smpdispmax = leg.smpdispmax; + cur.spkfilter = leg.spkfilter; + cur.spkdispmax = leg.spkdispmax; + cur.lncdispmax = leg.lncdispmax; + cur.spkopts = leg.spkopts; + cur.spkthrlevel = leg.spkthrlevel; + cur.spkthrlimit = leg.spkthrlimit; + cur.spkgroup = leg.spkgroup; + cur.amplrejpos = leg.amplrejpos; + cur.amplrejneg = leg.amplrejneg; + cur.refelecchan = leg.refelecchan; + copyArr(cur.unitmapping, leg.unitmapping, this, &Adapter::fromLegacy); + copyArr2D(cur.spkhoops, leg.spkhoops, this, &Adapter::fromLegacy); +} + +void Adapter::fromLegacy(::cbPKT_FS_BASIS& cur, const cbPKT_FS_BASIS& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.fs = leg.fs; + copyArr2D(cur.basis, leg.basis); +} + +void Adapter::fromLegacy(::cbPKT_SS_MODELSET& cur, const cbPKT_SS_MODELSET& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.chan = leg.chan; + cur.unit_number = leg.unit_number; + cur.valid = leg.valid; + cur.inverted = leg.inverted; + cur.num_samples = leg.num_samples; + copyArr(cur.mu_x, leg.mu_x); + copyArr2D(cur.Sigma_x, leg.Sigma_x); + cur.determinant_Sigma_x = leg.determinant_Sigma_x; + copyArr2D(cur.Sigma_x_inv, leg.Sigma_x_inv); + cur.log_determinant_Sigma_x = leg.log_determinant_Sigma_x; + cur.subcluster_spread_factor_numerator = leg.subcluster_spread_factor_numerator; + cur.subcluster_spread_factor_denominator = leg.subcluster_spread_factor_denominator; + cur.mu_e = leg.mu_e; + cur.sigma_e_squared = leg.sigma_e_squared; +} + +void Adapter::fromLegacy(::cbPKT_SS_DETECT& cur, const cbPKT_SS_DETECT& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.fThreshold = leg.fThreshold; + cur.fMultiplier = leg.fMultiplier; +} + +void Adapter::fromLegacy(::cbPKT_SS_ARTIF_REJECT& cur, const cbPKT_SS_ARTIF_REJECT& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.nMaxSimulChans = leg.nMaxSimulChans; + cur.nRefractoryCount = leg.nRefractoryCount; +} + +void Adapter::fromLegacy(::cbPKT_SS_NOISE_BOUNDARY& cur, const cbPKT_SS_NOISE_BOUNDARY& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.chan = leg.chan; + copyArr(cur.afc, leg.afc); + copyArr2D(cur.afS, leg.afS); +} + +void Adapter::fromLegacy(::cbPKT_SS_STATISTICS& cur, const cbPKT_SS_STATISTICS& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.nUpdateSpikes = leg.nUpdateSpikes; + cur.nAutoalg = leg.nAutoalg; + cur.nMode = leg.nMode; + cur.fMinClusterPairSpreadFactor = leg.fMinClusterPairSpreadFactor; + cur.fMaxSubclusterSpreadFactor = leg.fMaxSubclusterSpreadFactor; + cur.fMinClusterHistCorrMajMeasure = leg.fMinClusterHistCorrMajMeasure; + cur.fMaxClusterPairHistCorrMajMeasure = leg.fMaxClusterPairHistCorrMajMeasure; + cur.fClusterHistValleyPercentage = leg.fClusterHistValleyPercentage; + cur.fClusterHistClosePeakPercentage = leg.fClusterHistClosePeakPercentage; + cur.fClusterHistMinPeakPercentage = leg.fClusterHistMinPeakPercentage; + cur.nWaveBasisSize = leg.nWaveBasisSize; + cur.nWaveSampleSize = leg.nWaveSampleSize; +} + +void Adapter::fromLegacy(::cbAdaptControl& cur, const cbAdaptControl& leg) const { + cur.nMode = leg.nMode; + cur.fTimeOutMinutes = leg.fTimeOutMinutes; + cur.fElapsedMinutes = leg.fElapsedMinutes; +} + +void Adapter::fromLegacy(::cbPKT_SS_STATUS& cur, const cbPKT_SS_STATUS& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + fromLegacy(cur.cntlUnitStats, leg.cntlUnitStats); + fromLegacy(cur.cntlNumUnits, leg.cntlNumUnits); +} + +void Adapter::fromLegacy(::cbproto::SpikeSorting& cur, const cbSPIKE_SORTING& leg) const { + copyArr(cur.basis, leg.asBasis, this, &Adapter::fromLegacy); + copyArr2D(cur.models, leg.asSortModel, this, &Adapter::fromLegacy); + fromLegacy(cur.detect, leg.pktDetect); + fromLegacy(cur.artifact_reject, leg.pktArtifReject); + copyArr(cur.noise_boundary, leg.pktNoiseBoundary, this, &Adapter::fromLegacy); + fromLegacy(cur.statistics, leg.pktStatistics); + fromLegacy(cur.status, leg.pktStatus); +} + +void Adapter::fromLegacy(::cbPKT_NTRODEINFO& cur, const cbPKT_NTRODEINFO& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.ntrode = leg.ntrode; + copyArr(cur.label, leg.label); + copyArr2D(cur.ellipses, leg.ellipses, this, &Adapter::fromLegacy); + cur.nSite = leg.nSite; + cur.fs = leg.fs; + copyArr(cur.nChan, leg.nChan); +} + +void Adapter::fromLegacy(::cbWaveformData& cur, const cbWaveformData& leg) const { + cur.offset = leg.offset; // aka sineFrequency + cur.seq = leg.seq; // aka sineAmplitude + cur.seqTotal = leg.seqTotal; + cur.phases = leg.phases; + copyArr(cur.duration, leg.duration); + copyArr(cur.amplitude, leg.amplitude); +} + +void Adapter::fromLegacy(::cbPKT_AOUT_WAVEFORM& cur, const cbPKT_AOUT_WAVEFORM& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.chan = leg.chan; + cur.mode = leg.mode; + cur.repeats = leg.repeats; + cur.trig = leg.trig; + cur.trigInst = leg.trigInst; + cur.trigChan = leg.trigChan; + cur.trigValue = leg.trigValue; + cur.trigNum = leg.trigNum; + cur.active = leg.active; + fromLegacy(cur.wave, leg.wave); +} + +void Adapter::fromLegacy(::cbPKT_LNC& cur, const cbPKT_LNC& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.lncFreq = leg.lncFreq; + cur.lncRefChan = leg.lncRefChan; + cur.lncGlobalMode = leg.lncGlobalMode; +} + +void Adapter::fromLegacy(::cbPKT_NPLAY& cur, const cbPKT_NPLAY& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.ftime = leg.ftime; // aka opt + cur.stime = leg.stime; + cur.etime = leg.etime; + cur.val = leg.val; + cur.mode = leg.mode; + cur.flags = leg.flags; + cur.speed = leg.speed; + copyArr(cur.fname, leg.fname); +} + +void Adapter::fromLegacy(::cbVIDEOSOURCE& cur, const cbVIDEOSOURCE& leg) const { + copyArr(cur.name, leg.name); + cur.fps = leg.fps; +} + +void Adapter::fromLegacy(::cbTRACKOBJ& cur, const cbTRACKOBJ& leg) const { + copyArr(cur.name, leg.name); + cur.type = leg.type; + cur.pointCount = leg.pointCount; +} + +void Adapter::fromLegacy(::cbPKT_FILECFG& cur, const cbPKT_FILECFG& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.options = leg.options; + cur.duration = leg.duration; + cur.recording = leg.recording; + cur.extctrl = leg.extctrl; + copyArr(cur.username, leg.username); + copyArr(cur.filename, leg.filename); // aka datetime + copyArr(cur.comment, leg.comment); +} + +void Adapter::fromLegacy(NativeConfigBuffer& cur, const cbCFGBUFF& leg) const { + // TODO: VERIFY that each list that's assumed to be instrument-independent is in fact independent from any particular instrument. + cur.version = cbVERSION_MAJOR * 100 + cbVERSION_MINOR; // Central's version field contains garbage data, so replace it with the protocol version + cur.sysflags = leg.sysflags; + cur.instrument_status = static_cast(InstrumentStatus::ACTIVE); + fromLegacy(cur.sysinfo, leg.sysinfo); + fromLegacy(cur.procinfo, leg.procinfo[instrument_idx]); + copyArr(cur.bankinfo, leg.bankinfo[instrument_idx], this, &Adapter::fromLegacy); + copyArr(cur.groupinfo, leg.groupinfo[instrument_idx], this, &Adapter::fromLegacy); + copyArr(cur.filtinfo, leg.filtinfo[instrument_idx], this, &Adapter::fromLegacy); + fromLegacy(cur.adaptinfo, leg.adaptinfo[instrument_idx]); + fromLegacy(cur.refelecinfo, leg.refelecinfo[instrument_idx]); + copyArr(cur.chaninfo, leg.chaninfo, this, &Adapter::fromLegacy); + copyArr(cur.asBasis, leg.isSortingOptions.asBasis, this, &Adapter::fromLegacy); + copyArr2D(cur.asSortModel, leg.isSortingOptions.asSortModel, this, &Adapter::fromLegacy); + // TODO: Move native isSortingOptions fields into a struct + fromLegacy(cur.pktDetect, leg.isSortingOptions.pktDetect); + fromLegacy(cur.pktArtifReject, leg.isSortingOptions.pktArtifReject); + copyArr(cur.pktNoiseBoundary, leg.isSortingOptions.pktNoiseBoundary, this, &Adapter::fromLegacy); + fromLegacy(cur.pktStatistics, leg.isSortingOptions.pktStatistics); + fromLegacy(cur.pktStatus, leg.isSortingOptions.pktStatus); + copyArr(cur.isNTrodeInfo, leg.isNTrodeInfo, this, &Adapter::fromLegacy); + copyArr2D(cur.isWaveform, leg.isWaveform, this, &Adapter::fromLegacy); + fromLegacy(cur.isLnc, leg.isLnc[instrument_idx]); + fromLegacy(cur.isNPlay, leg.isNPlay); + copyArr(cur.isVideoSource, leg.isVideoSource, this, &Adapter::fromLegacy); + copyArr(cur.isTrackObj, leg.isTrackObj, this, &Adapter::fromLegacy); + fromLegacy(cur.fileinfo, leg.fileinfo); +} + +void Adapter::fromLegacy(NativeNSPStatus& cur, const NSPStatus& leg) const { + switch(leg) { + case NSPStatus::NSP_INIT: + cur = NativeNSPStatus::NSP_INIT; + break; + case NSPStatus::NSP_NOIPADDR: + cur = NativeNSPStatus::NSP_NOIPADDR; + break; + case NSPStatus::NSP_NOREPLY: + cur = NativeNSPStatus::NSP_NOREPLY; + break; + case NSPStatus::NSP_FOUND: + cur = NativeNSPStatus::NSP_FOUND; + break; + case NSPStatus::NSP_INVALID: + /* fallthrough */ + default: + cur = NativeNSPStatus::NSP_INVALID; + break; + } +} + +void Adapter::fromLegacy(::cbPKT_UNIT_SELECTION& cur, const cbPKT_UNIT_SELECTION& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + cur.lastchan = leg.lastchan; + copyArr(cur.abyUnitSelections, leg.abyUnitSelections); +} + +void Adapter::fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const { + fromLegacy(cur.isSelection, leg.isSelection[instrument_idx]); + cur.m_iBlockRecording = leg.m_iBlockRecording; + cur.m_nPCStatusFlags = leg.m_nPCStatusFlags; + cur.m_nNumFEChans = leg.m_nNumFEChans; + cur.m_nNumAnainChans = leg.m_nNumAnainChans; + cur.m_nNumAnalogChans = leg.m_nNumAnalogChans; + cur.m_nNumAoutChans = leg.m_nNumAoutChans; + cur.m_nNumAudioChans = leg.m_nNumAudioChans; + cur.m_nNumAnalogoutChans = leg.m_nNumAnalogoutChans; + cur.m_nNumDiginChans = leg.m_nNumDiginChans; + cur.m_nNumSerialChans = leg.m_nNumSerialChans; + cur.m_nNumDigoutChans = leg.m_nNumDigoutChans; + cur.m_nNumTotalChans = leg.m_nNumTotalChans; + fromLegacy(cur.m_nNspStatus, leg.m_nNspStatus[instrument_idx]); + cur.m_nNumNTrodesPerInstrument = leg.m_nNumNTrodesPerInstrument[instrument_idx]; + cur.m_nGeminiSystem = leg.m_nGeminiSystem; + // ignore APP_WORKSPACE +} + +void Adapter::fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const { + cur.received = leg.received; + cur.lasttime = leg.lasttime; + cur.headwrap = leg.headwrap; + cur.headindex = leg.headindex; + copyArr(cur.buffer, leg.buffer); +} + +void Adapter::fromLegacy(NativeTransmitBuffer& cur, const cbXMTBUFF& leg) const { + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); +} + +void Adapter::fromLegacy(NativeTransmitBufferLocal& cur, const cbXMTBUFFLOCAL& leg) const { + cur.transmitted = leg.transmitted; + cur.headindex = leg.headindex; + cur.tailindex = leg.tailindex; + cur.last_valid_index = leg.last_valid_index; + cur.bufferlen = leg.bufferlen; + copyArr(cur.buffer, leg.buffer); +} + +void Adapter::fromLegacy(::cbPKT_SPK& cur, const cbPKT_SPK& leg) const { + fromLegacy(cur.cbpkt_header, leg.cbpkt_header); + copyArr(cur.fPattern, leg.fPattern); + cur.nPeak = leg.nPeak; + cur.nValley = leg.nValley; + copyArr(cur.wave, leg.wave); +} + +void Adapter::fromLegacy(NativeSpikeCache& cur, const cbSPKCACHE& leg) const { + cur.chid = leg.chid; + cur.pktcnt = leg.pktcnt; + cur.pktsize = leg.pktsize; + cur.head = leg.head; + cur.valid = leg.valid; + copyArr(cur.spkpkt, leg.spkpkt, this, &Adapter::fromLegacy); +} + +void Adapter::fromLegacy(NativeSpikeBuffer& cur, const cbSPKBUFF& leg) const { + cur.flags = leg.flags; + cur.chidmax = leg.chidmax; + cur.linesize = leg.linesize; + cur.spkcount = leg.spkcount; + copyArr(cur.cache, leg.cache, this, &Adapter::fromLegacy); +} + +void Adapter::toLegacy(cbPKT_HEADER& leg, const ::cbPKT_HEADER& cur) const { + leg.time = cur.time; + leg.chid = cur.chid; + leg.type = cur.type; + leg.dlen = cur.dlen; + leg.instrument = cur.instrument; + leg.reserved = cur.reserved; +} + +void Adapter::toLegacy(cbPKT_SYSINFO& leg, const ::cbPKT_SYSINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.sysfreq = cur.sysfreq; + leg.spikelen = cur.spikelen; + leg.spikepre = cur.spikepre; + leg.resetque = cur.resetque; + leg.runlevel = cur.runlevel; + leg.runflags = cur.runflags; +} + +void Adapter::toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.proc = cur.proc; + leg.idcode = cur.idcode; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; + leg.bankcount = cur.bankcount; + leg.groupcount = cur.groupcount; + leg.filtcount = cur.filtcount; + leg.sortcount = cur.sortcount; + leg.unitcount = cur.unitcount; + leg.hoopcount = cur.hoopcount; + leg.reserved = cur.reserved; + leg.version = cur.version; +} + +void Adapter::toLegacy(cbPKT_BANKINFO& leg, const ::cbPKT_BANKINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.idcode = cur.idcode; + copyArr(leg.ident, cur.ident); + copyArr(leg.label, cur.label); + leg.chanbase = cur.chanbase; + leg.chancount = cur.chancount; +} + +void Adapter::toLegacy(cbPKT_GROUPINFO& leg, const ::cbPKT_GROUPINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.proc = cur.proc; + leg.group = cur.group; + copyArr(leg.label, cur.label); + leg.period = cur.period; + leg.length = cur.length; + copyArr(leg.list, cur.list); +} + +void Adapter::toLegacy(cbPKT_FILTINFO& leg, const ::cbPKT_FILTINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.proc = cur.proc; + leg.filt = cur.filt; + copyArr(leg.label, cur.label); + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; + leg.gain = cur.gain; + leg.sos1a1 = cur.sos1a1; + leg.sos1a2 = cur.sos1a2; + leg.sos1b1 = cur.sos1b1; + leg.sos1b2 = cur.sos1b2; + leg.sos2a1 = cur.sos2a1; + leg.sos2a2 = cur.sos2a2; + leg.sos2b1 = cur.sos2b1; + leg.sos2b2 = cur.sos2b2; +} + +void Adapter::toLegacy(cbPKT_ADAPTFILTINFO& leg, const ::cbPKT_ADAPTFILTINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.dLearningRate = cur.dLearningRate; + leg.nRefChan1 = cur.nRefChan1; + leg.nRefChan2 = cur.nRefChan2; +} + +void Adapter::toLegacy(cbPKT_REFELECFILTINFO& leg, const ::cbPKT_REFELECFILTINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.chan = cur.chan; + leg.nMode = cur.nMode; + leg.nRefChan = cur.nRefChan; +} + +void Adapter::toLegacy(cbSCALING& leg, const ::cbSCALING& cur) const { + leg.digmin = cur.digmin; + leg.digmax = cur.digmax; + leg.anamin = cur.anamin; + leg.anamax = cur.anamax; + leg.anagain = cur.anagain; + copyArr(leg.anaunit, cur.anaunit); +} + +void Adapter::toLegacy(cbFILTDESC& leg, const ::cbFILTDESC& cur) const { + leg.hpfreq = cur.hpfreq; + leg.hporder = cur.hporder; + leg.hptype = cur.hptype; + leg.lpfreq = cur.lpfreq; + leg.lporder = cur.lporder; + leg.lptype = cur.lptype; +} + +void Adapter::toLegacy(cbMANUALUNITMAPPING& leg, const ::cbMANUALUNITMAPPING& cur) const { + leg.nOverride = cur.nOverride; + copyArr(leg.afOrigin, cur.afOrigin); + copyArr2D(leg.afShape, cur.afShape); + leg.aPhi = cur.aPhi; + leg.bValid = cur.bValid; +} + +void Adapter::toLegacy(cbHOOP& leg, const ::cbHOOP& cur) const { + leg.valid = cur.valid; + leg.time = cur.time; + leg.min = cur.min; + leg.max = cur.max; +} + +void Adapter::toLegacy(cbPKT_CHANINFO& leg, const ::cbPKT_CHANINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.chan = cur.chan; + leg.proc = cur.proc; + leg.bank = cur.bank; + leg.term = cur.term; + leg.chancaps = cur.chancaps; + leg.doutcaps = cur.doutcaps; + leg.dinpcaps = cur.dinpcaps; + leg.aoutcaps = cur.aoutcaps; + leg.ainpcaps = cur.ainpcaps; + leg.spkcaps = cur.spkcaps; + toLegacy(leg.physcalin, cur.physcalin); + toLegacy(leg.phyfiltin, cur.phyfiltin); + toLegacy(leg.physcalout, cur.physcalout); + toLegacy(leg.phyfiltout, cur.phyfiltout); + copyArr(leg.label, cur.label); + leg.userflags = cur.userflags; + copyArr(leg.position, cur.position); + toLegacy(leg.scalin, cur.scalin); + toLegacy(leg.scalout, cur.scalout); + leg.doutopts = cur.doutopts; + leg.dinpopts = cur.dinpopts; + leg.aoutopts = cur.aoutopts; + leg.eopchar = cur.eopchar; + leg.moninst = cur.moninst; // aka lowsamples + leg.monchan = cur.monchan; // aka highsamples + leg.outvalue = cur.outvalue; // aka offset + leg.trigtype = cur.trigtype; + copyArr(leg.reserved, cur.reserved); + leg.triginst = cur.triginst; + leg.trigchan = cur.trigchan; + leg.trigval = cur.trigval; + leg.ainpopts = cur.ainpopts; + leg.lncrate = cur.lncrate; + leg.smpfilter = cur.smpfilter; + leg.smpgroup = cur.smpgroup; + leg.smpdispmin = cur.smpdispmin; + leg.smpdispmax = cur.smpdispmax; + leg.spkfilter = cur.spkfilter; + leg.spkdispmax = cur.spkdispmax; + leg.lncdispmax = cur.lncdispmax; + leg.spkopts = cur.spkopts; + leg.spkthrlevel = cur.spkthrlevel; + leg.spkthrlimit = cur.spkthrlimit; + leg.spkgroup = cur.spkgroup; + leg.amplrejpos = cur.amplrejpos; + leg.amplrejneg = cur.amplrejneg; + leg.refelecchan = cur.refelecchan; + copyArr(leg.unitmapping, cur.unitmapping, this, &Adapter::toLegacy); + copyArr2D(leg.spkhoops, cur.spkhoops, this, &Adapter::toLegacy); +} + +void Adapter::toLegacy(cbPKT_FS_BASIS& leg, const ::cbPKT_FS_BASIS& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.fs = cur.fs; + copyArr2D(leg.basis, cur.basis); +} + +void Adapter::toLegacy(cbPKT_SS_MODELSET& leg, const ::cbPKT_SS_MODELSET& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.chan = cur.chan; + leg.unit_number = cur.unit_number; + leg.valid = cur.valid; + leg.inverted = cur.inverted; + leg.num_samples = cur.num_samples; + copyArr(leg.mu_x, cur.mu_x); + copyArr2D(leg.Sigma_x, cur.Sigma_x); + leg.determinant_Sigma_x = cur.determinant_Sigma_x; + copyArr2D(leg.Sigma_x_inv, cur.Sigma_x_inv); + leg.log_determinant_Sigma_x = cur.log_determinant_Sigma_x; + leg.subcluster_spread_factor_numerator = cur.subcluster_spread_factor_numerator; + leg.subcluster_spread_factor_denominator = cur.subcluster_spread_factor_denominator; + leg.mu_e = cur.mu_e; + leg.sigma_e_squared = cur.sigma_e_squared; +} + +void Adapter::toLegacy(cbPKT_SS_DETECT& leg, const ::cbPKT_SS_DETECT& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.fThreshold = cur.fThreshold; + leg.fMultiplier = cur.fMultiplier; +} + +void Adapter::toLegacy(cbPKT_SS_ARTIF_REJECT& leg, const ::cbPKT_SS_ARTIF_REJECT& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.nMaxSimulChans = cur.nMaxSimulChans; + leg.nRefractoryCount = cur.nRefractoryCount; +} + +void Adapter::toLegacy(cbPKT_SS_NOISE_BOUNDARY& leg, const ::cbPKT_SS_NOISE_BOUNDARY& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.chan = cur.chan; + copyArr(leg.afc, cur.afc); + copyArr2D(leg.afS, cur.afS); +} + +void Adapter::toLegacy(cbPKT_SS_STATISTICS& leg, const ::cbPKT_SS_STATISTICS& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.nUpdateSpikes = cur.nUpdateSpikes; + leg.nAutoalg = cur.nAutoalg; + leg.nMode = cur.nMode; + leg.fMinClusterPairSpreadFactor = cur.fMinClusterPairSpreadFactor; + leg.fMaxSubclusterSpreadFactor = cur.fMaxSubclusterSpreadFactor; + leg.fMinClusterHistCorrMajMeasure = cur.fMinClusterHistCorrMajMeasure; + leg.fMaxClusterPairHistCorrMajMeasure = cur.fMaxClusterPairHistCorrMajMeasure; + leg.fClusterHistValleyPercentage = cur.fClusterHistValleyPercentage; + leg.fClusterHistClosePeakPercentage = cur.fClusterHistClosePeakPercentage; + leg.fClusterHistMinPeakPercentage = cur.fClusterHistMinPeakPercentage; + leg.nWaveBasisSize = cur.nWaveBasisSize; + leg.nWaveSampleSize = cur.nWaveSampleSize; +} + +void Adapter::toLegacy(cbAdaptControl& leg, const ::cbAdaptControl& cur) const { + leg.nMode = cur.nMode; + leg.fTimeOutMinutes = cur.fTimeOutMinutes; + leg.fElapsedMinutes = cur.fElapsedMinutes; +} + +void Adapter::toLegacy(cbPKT_SS_STATUS& leg, const ::cbPKT_SS_STATUS& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + toLegacy(leg.cntlUnitStats, cur.cntlUnitStats); + toLegacy(leg.cntlNumUnits, cur.cntlNumUnits); +} + +void Adapter::toLegacy(cbSPIKE_SORTING& leg, const ::cbproto::SpikeSorting& cur) const { + copyArr(leg.asBasis, cur.basis, this, &Adapter::toLegacy); + copyArr2D(leg.asSortModel, cur.models, this, &Adapter::toLegacy); + toLegacy(leg.pktDetect, cur.detect); + toLegacy(leg.pktArtifReject, cur.artifact_reject); + copyArr(leg.pktNoiseBoundary, cur.noise_boundary, this, &Adapter::toLegacy); + toLegacy(leg.pktStatistics, cur.statistics); + toLegacy(leg.pktStatus, cur.status); +} + +void Adapter::toLegacy(cbPKT_NTRODEINFO& leg, const ::cbPKT_NTRODEINFO& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.ntrode = cur.ntrode; + copyArr(leg.label, cur.label); + copyArr2D(leg.ellipses, cur.ellipses, this, &Adapter::toLegacy); + leg.nSite = cur.nSite; + leg.fs = cur.fs; + copyArr(leg.nChan, cur.nChan); +} + +void Adapter::toLegacy(cbWaveformData& leg, const ::cbWaveformData& cur) const { + leg.offset = cur.offset; // aka sineFrequency + leg.seq = cur.seq; // aka sineAmplitude + leg.seqTotal = cur.seqTotal; + leg.phases = cur.phases; + copyArr(leg.duration, cur.duration); + copyArr(leg.amplitude, cur.amplitude); +} + +void Adapter::toLegacy(cbPKT_AOUT_WAVEFORM& leg, const ::cbPKT_AOUT_WAVEFORM& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.chan = cur.chan; + leg.mode = cur.mode; + leg.repeats = cur.repeats; + leg.trig = cur.trig; + leg.trigInst = cur.trigInst; + leg.trigChan = cur.trigChan; + leg.trigValue = cur.trigValue; + leg.trigNum = cur.trigNum; + leg.active = cur.active; + toLegacy(leg.wave, cur.wave); +} + +void Adapter::toLegacy(cbPKT_LNC& leg, const ::cbPKT_LNC& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.lncFreq = cur.lncFreq; + leg.lncRefChan = cur.lncRefChan; + leg.lncGlobalMode = cur.lncGlobalMode; +} + +void Adapter::toLegacy(cbPKT_NPLAY& leg, const ::cbPKT_NPLAY& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.ftime = cur.ftime; // aka opt + leg.stime = cur.stime; + leg.etime = cur.etime; + leg.val = cur.val; + leg.mode = cur.mode; + leg.flags = cur.flags; + leg.speed = cur.speed; + copyArr(leg.fname, cur.fname); +} + +void Adapter::toLegacy(cbVIDEOSOURCE& leg, const ::cbVIDEOSOURCE& cur) const { + copyArr(leg.name, cur.name); + leg.fps = cur.fps; +} + +void Adapter::toLegacy(cbTRACKOBJ& leg, const ::cbTRACKOBJ& cur) const { + copyArr(leg.name, cur.name); + leg.type = cur.type; + leg.pointCount = cur.pointCount; +} + +void Adapter::toLegacy(cbPKT_FILECFG& leg, const ::cbPKT_FILECFG& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.options = cur.options; + leg.duration = cur.duration; + leg.recording = cur.recording; + leg.extctrl = cur.extctrl; + copyArr(leg.username, cur.username); + copyArr(leg.filename, cur.filename); // aka datetime + copyArr(leg.comment, cur.comment); +} + +void Adapter::toLegacy(NSPStatus& leg, const NativeNSPStatus& cur) const { + switch(cur) { + case NativeNSPStatus::NSP_INIT: + leg = NSPStatus::NSP_INIT; + break; + case NativeNSPStatus::NSP_NOIPADDR: + leg = NSPStatus::NSP_NOIPADDR; + break; + case NativeNSPStatus::NSP_NOREPLY: + leg = NSPStatus::NSP_NOREPLY; + break; + case NativeNSPStatus::NSP_FOUND: + leg = NSPStatus::NSP_FOUND; + break; + case NativeNSPStatus::NSP_INVALID: + /* fallthrough */ + default: + leg = NSPStatus::NSP_INVALID; + break; + } +} + +void Adapter::toLegacy(cbPKT_UNIT_SELECTION& leg, const ::cbPKT_UNIT_SELECTION& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + leg.lastchan = cur.lastchan; + copyArr(leg.abyUnitSelections, cur.abyUnitSelections); +} + +void Adapter::toLegacy(cbRECBUFF& leg, const NativeReceiveBuffer& cur) const { + leg.received = cur.received; + leg.lasttime = cur.lasttime; + leg.headwrap = cur.headwrap; + leg.headindex = cur.headindex; + copyArr(leg.buffer, cur.buffer); +} + +void Adapter::toLegacy(cbXMTBUFF& leg, const NativeTransmitBuffer& cur) const { + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); +} + +void Adapter::toLegacy(cbXMTBUFFLOCAL& leg, const NativeTransmitBufferLocal& cur) const { + leg.transmitted = cur.transmitted; + leg.headindex = cur.headindex; + leg.tailindex = cur.tailindex; + leg.last_valid_index = cur.last_valid_index; + leg.bufferlen = cur.bufferlen; + copyArr(leg.buffer, cur.buffer); +} + +void Adapter::toLegacy(cbPKT_SPK& leg, const ::cbPKT_SPK& cur) const { + toLegacy(leg.cbpkt_header, cur.cbpkt_header); + copyArr(leg.fPattern, cur.fPattern); + leg.nPeak = cur.nPeak; + leg.nValley = cur.nValley; + copyArr(leg.wave, cur.wave); +} + +Adapter::Adapter(uint8_t instrument_idx, void* cfg_ptr, void* rec_ptr, void* xmt_ptr, void* xmt_local_ptr, void* status_ptr, void* spike_ptr) + : instrument_idx(instrument_idx) + , cfg(static_cast(cfg_ptr)) + , rec(static_cast(rec_ptr)) + , xmt(static_cast(xmt_ptr)) + , xmt_local(static_cast(xmt_local_ptr)) + , status(static_cast(status_ptr)) + , spike(static_cast(spike_ptr)) +{} + +uint32_t Adapter::getMaxProcs() const { + return cbMAXPROCS; +} + +uint32_t& Adapter::getRecReceived() { + return rec->received; +} + +uint64_t Adapter::getRecLasttime() { + return rec->lasttime; +} + +void Adapter::setRecLasttime(uint64_t lasttime) { + rec->lasttime = lasttime; +} + +uint32_t& Adapter::getRecHeadwrapPtr() { + return rec->headwrap; +} + +uint32_t& Adapter::getRecHeadindexPtr() { + return rec->headindex; +} + +uint32_t* Adapter::getRecBufferPtr() { + return rec->buffer; +} + +uint32_t& Adapter::getXmtTransmittedPtr() { + return xmt->transmitted; +} + +uint32_t& Adapter::getXmtHeadindexPtr() { + return xmt->headindex; +} + +uint32_t& Adapter::getXmtTailindexPtr() { + return xmt->tailindex; +} + +uint32_t& Adapter::getXmtLastValidIndexPtr() { + return xmt->last_valid_index; +} + +uint32_t& Adapter::getXmtBufferlenPtr() { + return xmt->bufferlen; +} + +uint32_t* Adapter::getXmtBufferPtr() { + return xmt->buffer; +} + +uint32_t& Adapter::getLocalXmtTransmittedPtr() { + return xmt->transmitted; +} + +uint32_t& Adapter::getLocalXmtHeadindexPtr() { + return xmt->headindex; +} + +uint32_t& Adapter::getLocalXmtTailindexPtr() { + return xmt->tailindex; +} + +uint32_t& Adapter::getLocalXmtLastValidIndexPtr() { + return xmt->last_valid_index; +} + +uint32_t& Adapter::getLocalXmtBufferlenPtr() { + return xmt->bufferlen; +} + +uint32_t* Adapter::getLocalXmtBufferPtr() { + return xmt->buffer; +} + +cbutil::Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { + fromLegacy(buf, cfg->procinfo[instrument_idx]); + return cbutil::Result::ok(); +} + +cbutil::Result Adapter::getBankInfo(::cbPKT_BANKINFO& buf, uint32_t bank_num) const { + uint32_t bank_idx = bank_num - 1; + if (bank_idx >= std::size(cfg->bankinfo[0])) { + return cbutil::Result::error("Bank number out of range"); + } + fromLegacy(buf, cfg->bankinfo[instrument_idx][bank_idx]); + return cbutil::Result::ok(); +} + +cbutil::Result Adapter::getFilterInfo(::cbPKT_FILTINFO& buf, uint32_t filter_num) const { + uint32_t filter_idx = filter_num - 1; + if (filter_idx >= std::size(cfg->filtinfo[0])) { + return cbutil::Result::error("Filter number out of range"); + } + fromLegacy(buf, cfg->filtinfo[instrument_idx][filter_idx]); + return cbutil::Result::ok(); +} + +cbutil::Result Adapter::getChanInfo(::cbPKT_CHANINFO& buf, uint32_t channel_idx) const { + if (channel_idx >= std::size(cfg->chaninfo)) { + return cbutil::Result::error("Channel number out of range"); + } + fromLegacy(buf, cfg->chaninfo[channel_idx]); + return cbutil::Result::ok(); +} + +cbutil::Result Adapter::getSysInfo(::cbPKT_SYSINFO& buf) const { + fromLegacy(buf, cfg->sysinfo); + return cbutil::Result::ok(); +} + +cbutil::Result Adapter::getGroupInfo(::cbPKT_GROUPINFO& buf, uint32_t group_idx) const { + if (group_idx >= std::size(cfg->groupinfo[0])) { + return cbutil::Result::error("Group index out of range"); + } + fromLegacy(buf, cfg->groupinfo[instrument_idx][group_idx]); + return cbutil::Result::ok(); +} + +cbutil::Result Adapter::getConfigBuffer(NativeConfigBuffer& buf) const { + fromLegacy(buf, *cfg); + return cbutil::Result::ok(); +} + +cbutil::Result Adapter::getPcStatus(NativePCStatus& buf) const { + fromLegacy(buf, *status); + return cbutil::Result::ok(); +} + +cbutil::Result Adapter::getSpikeCache(NativeSpikeCache& buf, uint32_t channel_idx) const { + if (channel_idx >= std::size(spike->cache)) { + return cbutil::Result::error("Channel index out of range"); + } + fromLegacy(buf, spike->cache[channel_idx]); + return cbutil::Result::ok(); +} + +cbutil::Result Adapter::setProcInfo(const ::cbPKT_PROCINFO& info) { + toLegacy(cfg->procinfo[instrument_idx], info); + return cbutil::Result::ok(); +} + +cbutil::Result Adapter::setBankInfo(uint32_t bank_num, const ::cbPKT_BANKINFO& info) { + uint32_t bank_idx = bank_num - 1; + if (bank_idx >= std::size(cfg->bankinfo[0])) { + return cbutil::Result::error("Bank number out of range"); + } + toLegacy(cfg->bankinfo[instrument_idx][bank_idx], info); + return cbutil::Result::ok(); +} + +cbutil::Result Adapter::setFilterInfo(uint32_t filter_num, const ::cbPKT_FILTINFO& info) { + uint32_t filter_idx = filter_num - 1; + if (filter_idx >= std::size(cfg->filtinfo[0])) { + return cbutil::Result::error("Filter number out of range"); + } + toLegacy(cfg->filtinfo[instrument_idx][filter_idx], info); + return cbutil::Result::ok(); +} + +cbutil::Result Adapter::setChanInfo(uint32_t channel_idx, const ::cbPKT_CHANINFO& info) { + if (channel_idx >= std::size(cfg->chaninfo)) { + return cbutil::Result::error("Channel number out of range"); + } + toLegacy(cfg->chaninfo[channel_idx], info); + return cbutil::Result::ok(); +} + +cbutil::Result Adapter::setSysInfo(const ::cbPKT_SYSINFO& info) { + toLegacy(cfg->sysinfo, info); + return cbutil::Result::ok(); +} + +cbutil::Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GROUPINFO& info) { + if (group_idx >= std::size(cfg->groupinfo[0])) { + return cbutil::Result::error("Group index out of range"); + } + toLegacy(cfg->groupinfo[instrument_idx][group_idx], info); + return cbutil::Result::ok(); +} + +cbutil::Result Adapter::setNspStatus(const NativeNSPStatus& status) const { + toLegacy(this->status->m_nNspStatus[instrument_idx], status); + return cbutil::Result::ok(); +} + +cbutil::Result Adapter::setGeminiSystem(bool is_gemini) const { + status->m_nGeminiSystem = is_gemini ? 1 : 0; + return cbutil::Result::ok(); +} + +} // namespace central_v7_8 + +} // namespace cbshm diff --git a/src/cbshm/src/shmem_session.cpp b/src/cbshm/src/shmem_session.cpp index 3bff2f73..f65f94c4 100644 --- a/src/cbshm/src/shmem_session.cpp +++ b/src/cbshm/src/shmem_session.cpp @@ -34,14 +34,17 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -185,7 +188,8 @@ struct ShmemSession::Impl { uint32_t rec_tailindex; // Our read position in receive buffer uint32_t rec_tailwrap; // Our wrap counter - // Detected protocol version for CENTRAL mode + // Detected versions for CENTRAL mode + CentralVersion central_version; cbproto_protocol_version_t compat_protocol; // Typed accessor for config buffer @@ -231,6 +235,7 @@ struct ShmemSession::Impl { , rec_buffer_len(0) , rec_tailindex(0) , rec_tailwrap(0) + , central_version(CentralVersion::UNKNOWN) , compat_protocol(CBPROTO_PROTOCOL_CURRENT) {} @@ -374,35 +379,39 @@ struct ShmemSession::Impl { if (mode == Mode::CLIENT && layout == ShmemLayout::CENTRAL) { // Detect protocol version for CLIENT + CENTRAL mode - auto compat_result = detectCompatProtocol(); - if (compat_result.isError()) { - return Result::error("Failed to get Central's protocol version: " + compat_result.error()); + auto central_result = detectCentralVersion(); + if (central_result.isError()) { + return Result::error("Failed to get Central's version: " + central_result.error()); + } + central_version = central_result.value(); + compat_protocol = getProtocolVersion(central_version); + + // Select the bootstrap adapter for fetching pointers to Central's shared memory. + switch (central_version) { + case CentralVersion::V7_0: + bootstrap_adapter = std::make_unique(); + break; + case CentralVersion::V7_5: + bootstrap_adapter = std::make_unique(); + break; + case CentralVersion::V7_6: + bootstrap_adapter = std::make_unique(); + break; + case CentralVersion::V7_7: + bootstrap_adapter = std::make_unique(); + break; + default: + /* fallthrough */ + case CentralVersion::CURRENT: + bootstrap_adapter = std::make_unique(); + break; } - compat_protocol = compat_result.value(); } else { // The compatibility protocol is ignored for NATIVE or CENTRAL // layouts and is always current for STANDALONE mode. compat_protocol = CBPROTO_PROTOCOL_CURRENT; } - // Select the bootstrap adapter for fetching pointers to Central's shared memory. - switch (compat_protocol) { - default: - /* fallthrough */ - case CBPROTO_PROTOCOL_CURRENT: - bootstrap_adapter = std::make_unique(); - break; - case CBPROTO_PROTOCOL_410: - bootstrap_adapter = std::make_unique(); - break; - case CBPROTO_PROTOCOL_400: - bootstrap_adapter = std::make_unique(); - break; - case CBPROTO_PROTOCOL_311: - bootstrap_adapter = std::make_unique(); - break; - } - // Compute buffer sizes based on layout and protocol version if (layout == ShmemLayout::NATIVE) { cfg_buffer_size = sizeof(NativeConfigBuffer); @@ -546,22 +555,27 @@ struct ShmemSession::Impl { } #endif - // Select the adapter for compatibility with Central's shared memory. - switch (compat_protocol) { - default: - /* fallthrough */ - case CBPROTO_PROTOCOL_CURRENT: - adapter = std::make_unique(inst.toIndex(), cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); - break; - case CBPROTO_PROTOCOL_410: - adapter = std::make_unique(inst.toIndex(), cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); - break; - case CBPROTO_PROTOCOL_400: - adapter = std::make_unique(inst.toIndex(), cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); - break; - case CBPROTO_PROTOCOL_311: - adapter = std::make_unique(inst.toIndex(), cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); - break; + if (mode == Mode::CLIENT && layout == ShmemLayout::CENTRAL) { + // Select the adapter for compatibility with Central's shared memory. + switch (central_version) { + case CentralVersion::V7_0: + adapter = std::make_unique(inst.toIndex(), cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); + break; + case CentralVersion::V7_5: + adapter = std::make_unique(inst.toIndex(), cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); + break; + case CentralVersion::V7_6: + adapter = std::make_unique(inst.toIndex(), cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); + break; + case CentralVersion::V7_7: + adapter = std::make_unique(inst.toIndex(), cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); + break; + default: + /* fallthrough */ + case CentralVersion::CURRENT: + adapter = std::make_unique(inst.toIndex(), cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); + break; + } } // Initialize buffers in standalone mode From 26ea1a127b424247e22fc987595350a4a0c31776 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Tue, 30 Jun 2026 18:04:25 -0600 Subject: [PATCH 43/62] Move Central version detection outside of ShmemSession Version detection logic for Central has been moved to central_version.h and central_version.cpp. Two functions, detectCentralVersion and getProtocolVersion (maybe getCentralProtocol instead?), are used by ShmemSession::Impl to fetch the current version of Central and it's protocol version. In the future, these functions will be called outside of ShmemSession so they aren't called every time a new instrument is inspected. --- src/cbshm/CMakeLists.txt | 1 + src/cbshm/include/cbshm/central_current.h | 6 +- src/cbshm/include/cbshm/central_version.h | 36 ++++ src/cbshm/src/central_version.cpp | 200 ++++++++++++++++++++++ src/cbshm/src/shmem_session.cpp | 196 +++------------------ 5 files changed, 263 insertions(+), 176 deletions(-) create mode 100644 src/cbshm/include/cbshm/central_version.h create mode 100644 src/cbshm/src/central_version.cpp diff --git a/src/cbshm/CMakeLists.txt b/src/cbshm/CMakeLists.txt index 9b218869..bca29984 100644 --- a/src/cbshm/CMakeLists.txt +++ b/src/cbshm/CMakeLists.txt @@ -9,6 +9,7 @@ project(cbshm # Library sources set(CBSHMEM_SOURCES src/shmem_session.cpp + src/central_version.cpp src/central_adapters/v7_8.cpp src/central_adapters/v7_7.cpp src/central_adapters/v7_6.cpp diff --git a/src/cbshm/include/cbshm/central_current.h b/src/cbshm/include/cbshm/central_current.h index bbd95e1f..29644d60 100644 --- a/src/cbshm/include/cbshm/central_current.h +++ b/src/cbshm/include/cbshm/central_current.h @@ -15,12 +15,12 @@ #ifndef CBSHM_CENTRAL_ADAPTERS_CURRENT_H #define CBSHM_CENTRAL_ADAPTERS_CURRENT_H -#include -#include +#include +#include namespace cbshm { -namespace central = cbshm::central_v4_2; +namespace central = cbshm::central_v7_8; } // namespace cbshm diff --git a/src/cbshm/include/cbshm/central_version.h b/src/cbshm/include/cbshm/central_version.h new file mode 100644 index 00000000..4ab95b95 --- /dev/null +++ b/src/cbshm/include/cbshm/central_version.h @@ -0,0 +1,36 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file central_version.h +/// @author Caden Shmookler +/// @date 2026-06-25 +/// +/// @brief Protocol version detection for Central +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef CBSHM_CENTRAL_VERSION_H +#define CBSHM_CENTRAL_VERSION_H + +#include +#include +#include + +namespace cbshm { + +enum class CentralVersion { + UNKNOWN, + V7_0, + V7_5, + V7_6, + V7_7, + CURRENT, // V7_8 +}; + +/// @brief Detect the protocol version from Central's binary. +cbutil::Result detectCentralVersion(); + +/// @brief Convert the Central version to the protocol version. +cbproto_protocol_version_t getProtocolVersion(CentralVersion version); + +} // namespace cbshm + +#endif // CBSHM_CENTRAL_VERSION_H diff --git a/src/cbshm/src/central_version.cpp b/src/cbshm/src/central_version.cpp new file mode 100644 index 00000000..83f6e04c --- /dev/null +++ b/src/cbshm/src/central_version.cpp @@ -0,0 +1,200 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file central_version.cpp +/// @author Caden Shmookler +/// @date 2026-06-25 +/// +/// @brief Protocol version detection for Central +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// Platform headers MUST be included first (before cbproto) +#include "platform_first.h" +#ifdef _WIN32 + #include + #include + + #include + #include +#endif + +#include + +namespace cbshm { + +cbutil::Result detectCentralVersion() { +#ifdef _WIN32 + // The 'version' field in Central's shared memory configuration buffer + // is set to a magic number, 96, instead of a meaningful value that + // indicates the application or protocol version. The only other field + // in Central's shared memory with version information is procinfo[].version, + // but it's byte offset changes between protocol versions so it is unusable. + // This function infers Central's protocol version by inspecting + // VersionInfo.ProductVersion in Central.exe and converting from application + // version to protocol version. + // + // This process for inferring the protocol version is indirect and brittle. + // If a future version of Central were to have a different executable name, + // version field name, or version format, then this detection method would + // fail to deduce the protocol version. + + // Get the path to Central's executable file from the running processes list. + + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (snapshot == INVALID_HANDLE_VALUE) { + return cbutil::Result::error("Failed to get a snapshot of the running processes from the Tool Help library"); + } + + PROCESSENTRY32 process_entry{}; + process_entry.dwSize = sizeof(process_entry); + if (! Process32First(snapshot, &process_entry)) { + return cbutil::Result::error("Failed to get the first process from the running processes snapshot"); + } + + // Enumerate the running processes and identify Central by it's process name. + DWORD central_pid = 0; + do { + if (std::string(process_entry.szExeFile) == "Central.exe") { + central_pid = process_entry.th32ProcessID; + break; + } + } while(Process32Next(snapshot, &process_entry)); + if (central_pid == 0) { + return cbutil::Result::error("Failed to find Central among the currently running processes. Is Central running?"); + } + + HANDLE central = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, central_pid); + if (! central) { + return cbutil::Result::error("Failed to inspect Central's process"); + } + + char central_path[MAX_PATH] = {0}; + DWORD central_path_size = MAX_PATH; + if (! QueryFullProcessImageNameA(central, NULL, central_path, ¢ral_path_size)) { + CloseHandle(central); + return cbutil::Result::error("Failed to get the path to Central's executable"); + } + CloseHandle(central); + + // Get Central's application version by inspecting the properties of the + // Central.exe binary + + DWORD handle = 0; + DWORD block_size = GetFileVersionInfoSizeA(central_path, &handle); + if (block_size == 0) { + return cbutil::Result::error("Failed to get the length of the resource block containing Central's application version"); + } + + std::vector block(block_size); + if (!GetFileVersionInfoA(central_path, handle, block_size, block.data())) { + return cbutil::Result::error("Failed to extract the version resource block from Central"); + } + + struct LangCodePage { + WORD lang; + WORD codepage; + } *translate = nullptr; + UINT translate_size = 0; + if (!VerQueryValueA(block.data(), "\\VarFileInfo\\Translation", (LPVOID*)&translate, &translate_size) || translate_size == 0) { + return cbutil::Result::error("Failed to lookup the available version translations for Central"); + } + + char sub_block[64]; + sprintf_s(sub_block, sizeof(sub_block), "\\StringFileInfo\\%04x%04x\\ProductVersion", translate[0].lang, translate[0].codepage); + + char* value = nullptr; + UINT value_size = 0; + if (!VerQueryValueA(block.data(), sub_block, (LPVOID*)&value, &value_size) || value_size == 0) { + return cbutil::Result::error("Failed to extract Central's version from the resource block"); + } + std::string app_version = std::string(value, value_size - 1); // strip trailing null byte + + // Get the indicies of both dots in the version string + size_t ldot_idx = app_version.find("."); + size_t rdot_idx = app_version.rfind("."); + if (ldot_idx == std::string::npos || rdot_idx == std::string::npos) { + return cbutil::Result::error("Failed to find both dots separating the major, minor, and patch version values in '" + app_version + "'"); + } + + // Extract the major version number + char* major_version_begin = app_version.data(); + char* major_version_end = app_version.data() + ldot_idx; + uint32_t major_version; + std::from_chars_result result{}; + result.ptr = nullptr; + result.ec = std::errc(0); + result = std::from_chars(major_version_begin, major_version_end, major_version); + if (result.ec != std::errc(0) || result.ptr != major_version_end) { + return cbutil::Result::error("Failed to isolate the major version value from '" + app_version + "'"); + } + + // Extract the minor version number + char* minor_version_begin = app_version.data() + ldot_idx + 1; + char* minor_version_end = app_version.data() + rdot_idx; + uint32_t minor_version; + result.ptr = nullptr; + result.ec = std::errc(0); + result = std::from_chars(minor_version_begin, minor_version_end, minor_version); + if (result.ec != std::errc(0) || result.ptr != minor_version_end) { + return cbutil::Result::error("Failed to isolate the minor version value from '" + app_version + "'"); + } + + // Convert application version to protocol version + switch(major_version) { + case 7: + switch (minor_version) { + default: + return cbutil::Result::ok(CentralVersion::CURRENT); + // return cbutil::Result::error("Unrecognized minor version number in version '" + app_version + "'"); + case 8: + return cbutil::Result::ok(CentralVersion::CURRENT); + case 7: + return cbutil::Result::ok(CentralVersion::V7_7); + case 6: + return cbutil::Result::ok(CentralVersion::V7_6); + case 5: + return cbutil::Result::ok(CentralVersion::V7_5); + case 0: + return cbutil::Result::ok(CentralVersion::V7_0); + } + break; + case 6: + /* fallthrough */ + case 5: + /* fallthrough */ + case 4: + /* fallthrough */ + case 3: + /* fallthrough */ + case 2: + /* fallthrough */ + case 1: + return cbutil::Result::error("Unsupported major version number in version '" + app_version + "'. Please update Central to a newer version"); + default: + return cbutil::Result::ok(CentralVersion::UNKNOWN); + // return cbutil::Result::error("Unrecognized major version number in version '" + app_version + "'" ); + } +#else + return cbutil::Result::error("Compatibility with Central requires Windows"); +#endif +} + +cbproto_protocol_version_t getProtocolVersion(CentralVersion version) { + switch (version) { + default: + /* fallthrough */ + case CentralVersion::UNKNOWN: + return CBPROTO_PROTOCOL_UNKNOWN; + case CentralVersion::V7_0: + return CBPROTO_PROTOCOL_311; + case CentralVersion::V7_5: + return CBPROTO_PROTOCOL_400; + case CentralVersion::V7_6: + /* fallthrough */ + case CentralVersion::V7_7: + return CBPROTO_PROTOCOL_410; + case CentralVersion::CURRENT: + return CBPROTO_PROTOCOL_CURRENT; + } +} + +} // namespace cbshm diff --git a/src/cbshm/src/shmem_session.cpp b/src/cbshm/src/shmem_session.cpp index f65f94c4..f3cd53b5 100644 --- a/src/cbshm/src/shmem_session.cpp +++ b/src/cbshm/src/shmem_session.cpp @@ -14,11 +14,7 @@ // Platform headers MUST be included first (before cbproto) #include "platform_first.h" #ifdef _WIN32 - #include - #include - - #include - #include + #include #endif #ifndef _WIN32 @@ -48,7 +44,6 @@ #include #include #include -#include #include #include // std::gcd @@ -115,15 +110,28 @@ struct SegmentNames { // "cbshm__", where name_qualifier is the device token // (e.g. "hub1"), matching the names a CereLink STANDALONE publishes. inline SegmentNames makeSegmentNames(ShmemLayout layout, const std::string& name_qualifier) { - if (layout == ShmemLayout::CENTRAL) { - const std::string& s = name_qualifier; // instance suffix - return SegmentNames{"cbCFGbuffer" + s, "cbRECbuffer" + s, "XmtGlobal" + s, - "XmtLocal" + s, "cbSTATUSbuffer" + s, "cbSPKbuffer" + s, - "cbSIGNALevent" + s}; - } - auto seg = [&](const char* s) { return "cbshm_" + name_qualifier + "_" + s; }; - return SegmentNames{seg("config"), seg("receive"), seg("xmt_global"), seg("xmt_local"), - seg("status"), seg("spike"), seg("signal")}; + const std::string& s = name_qualifier; // instance suffix + if (layout == ShmemLayout::NATIVE) { + return SegmentNames{ + "cbshm_config_" + s, + "cbshm_receive_" + s, + "cbshm_xmt_global_" + s, + "cbshm_xmt_local_" + s, + "cbshm_status_" + s, + "cbshm_spike_" + s, + "cbshm_signal_" + s + }; + } else { + return SegmentNames{ + "cbCFGbuffer" + s, + "cbRECbuffer" + s, + "XmtGlobal" + s, + "XmtLocal" + s, + "cbSTATUSbuffer" + s, + "cbSPKbuffer" + s, + "cbSIGNALevent" + s + }; + } } } // namespace @@ -724,164 +732,6 @@ struct ShmemSession::Impl { return Result::ok(); } - /// @brief Detect the protocol version from Central's binary (CENTRAL only). - Result detectCompatProtocol() { -#ifdef _WIN32 - // The 'version' field in Central's shared memory configuration buffer - // is set to a magic number, 96, instead of a meaningful value that - // indicates the application or protocol version. The only other field - // in Central's shared memory with version information is procinfo[].version, - // but it's byte offset changes between protocol versions so it is unusable. - // This function infers Central's protocol version by inspecting - // VersionInfo.ProductVersion in Central.exe and converting from application - // version to protocol version. - // - // This process for inferring the protocol version is indirect and brittle. - // If a future version of Central were to have a different executable name, - // version field name, or version format, then this detection method would - // fail to deduce the protocol version. - - // Get the path to Central's executable file from the running processes list. - - HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if (snapshot == INVALID_HANDLE_VALUE) { - return Result::error("Failed to get a snapshot of the running processes from the Tool Help library"); - } - - PROCESSENTRY32 process_entry{}; - process_entry.dwSize = sizeof(process_entry); - if (! Process32First(snapshot, &process_entry)) { - return Result::error("Failed to get the first process from the running processes snapshot"); - } - - // Enumerate the running processes and identify Central by it's process name. - DWORD central_pid = 0; - do { - if (std::string(process_entry.szExeFile) == "Central.exe") { - central_pid = process_entry.th32ProcessID; - break; - } - } while(Process32Next(snapshot, &process_entry)); - if (central_pid == 0) { - return Result::error("Failed to find Central among the currently running processes. Is Central running?"); - } - - HANDLE central = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, central_pid); - if (! central) { - return Result::error("Failed to inspect Central's process"); - } - - char central_path[MAX_PATH] = {0}; - DWORD central_path_size = MAX_PATH; - if (! QueryFullProcessImageNameA(central, NULL, central_path, ¢ral_path_size)) { - CloseHandle(central); - return Result::error("Failed to get the path to Central's executable"); - } - CloseHandle(central); - - // Get Central's application version by inspecting the properties of the - // Central.exe binary - - DWORD handle = 0; - DWORD block_size = GetFileVersionInfoSizeA(central_path, &handle); - if (block_size == 0) { - return Result::error("Failed to get the length of the resource block containing Central's application version"); - } - - std::vector block(block_size); - if (!GetFileVersionInfoA(central_path, handle, block_size, block.data())) { - return Result::error("Failed to extract the version resource block from Central"); - } - - struct LangCodePage { - WORD lang; - WORD codepage; - } *translate = nullptr; - UINT translate_size = 0; - if (!VerQueryValueA(block.data(), "\\VarFileInfo\\Translation", (LPVOID*)&translate, &translate_size) || translate_size == 0) { - return Result::error("Failed to lookup the available version translations for Central"); - } - - char sub_block[64]; - sprintf_s(sub_block, sizeof(sub_block), "\\StringFileInfo\\%04x%04x\\ProductVersion", translate[0].lang, translate[0].codepage); - - char* value = nullptr; - UINT value_size = 0; - if (!VerQueryValueA(block.data(), sub_block, (LPVOID*)&value, &value_size) || value_size == 0) { - return Result::error("Failed to extract Central's version from the resource block"); - } - std::string app_version = std::string(value, value_size - 1); // strip trailing null byte - - // Get the indicies of both dots in the version string - size_t ldot_idx = app_version.find("."); - size_t rdot_idx = app_version.rfind("."); - if (ldot_idx == std::string::npos || rdot_idx == std::string::npos) { - return Result::error("Failed to find both dots separating the major, minor, and patch version values in '" + app_version + "'"); - } - - // Extract the major version number - char* major_version_begin = app_version.data(); - char* major_version_end = app_version.data() + ldot_idx; - uint32_t major_version; - std::from_chars_result result{}; - result.ptr = nullptr; - result.ec = std::errc(0); - result = std::from_chars(major_version_begin, major_version_end, major_version); - if (result.ec != std::errc(0) || result.ptr != major_version_end) { - return Result::error("Failed to isolate the major version value from '" + app_version + "'"); - } - - // Extract the minor version number - char* minor_version_begin = app_version.data() + ldot_idx + 1; - char* minor_version_end = app_version.data() + rdot_idx; - uint32_t minor_version; - result.ptr = nullptr; - result.ec = std::errc(0); - result = std::from_chars(minor_version_begin, minor_version_end, minor_version); - if (result.ec != std::errc(0) || result.ptr != minor_version_end) { - return Result::error("Failed to isolate the minor version value from '" + app_version + "'"); - } - - // Convert application version to protocol version - switch(major_version) { - default: - return Result::ok(CBPROTO_PROTOCOL_CURRENT); - // return Result::error("Unrecognized major version number in version '" + app_version + "'" ); - case 7: - switch (minor_version) { - default: - return Result::ok(CBPROTO_PROTOCOL_CURRENT); - // return Result::error("Unrecognized minor version number in version '" + app_version + "'"); - case 8: - return Result::ok(CBPROTO_PROTOCOL_CURRENT); - case 7: - /* fallthrough */ - case 6: - return Result::ok(CBPROTO_PROTOCOL_410); - case 5: - return Result::ok(CBPROTO_PROTOCOL_400); - case 0: - return Result::ok(CBPROTO_PROTOCOL_311); - } - break; - case 6: - /* fallthrough */ - case 5: - /* fallthrough */ - case 4: - /* fallthrough */ - case 3: - /* fallthrough */ - case 2: - /* fallthrough */ - case 1: - return Result::error("Unsupported major version number in version '" + app_version + "'. Please update Central to a newer version"); - } -#else - return Result::error("Compatibility with Central requires Windows"); -#endif - } - // Helper: get sysfreq from cbPKT_SYSINFO // Guaranteed to provide a frequency greater than or equal to 1 // or the default frequency if the true value is unavailable. From a7042ffa76ee192eeb172fce03a3cdd3626a4eaa Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Wed, 1 Jul 2026 07:26:37 -0600 Subject: [PATCH 44/62] FIX: nullptr cannot be compared to Result type --- tests/integration/test_sdk_configuration.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/test_sdk_configuration.cpp b/tests/integration/test_sdk_configuration.cpp index aeb48a35..3a41fb11 100644 --- a/tests/integration/test_sdk_configuration.cpp +++ b/tests/integration/test_sdk_configuration.cpp @@ -205,7 +205,7 @@ TEST_F(ChannelInfoTest, GetChanInfoInvalid) { ASSERT_TRUE(result.isOk()) << result.error(); // Channel 0 is invalid (1-based) - EXPECT_EQ(result.value().getChanInfo(0), nullptr); + EXPECT_FALSE(result.value().getChanInfo(0).isOk()); } TEST_F(ChannelInfoTest, GetChannelLabels) { @@ -334,7 +334,7 @@ TEST_F(FilterInfoTest, GetFilterInfoInvalid) { auto result = createNPlaySession(); ASSERT_TRUE(result.isOk()) << result.error(); - EXPECT_EQ(result.value().getFilterInfo(9999), nullptr); + EXPECT_FALSE(result.value().getFilterInfo(9999).isOk()); } /////////////////////////////////////////////////////////////////////////////////////////////////// From daf6d331c0194357a0171aac4bd944d4b677e67e Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Wed, 1 Jul 2026 10:42:53 -0600 Subject: [PATCH 45/62] FIX: cbRECBUFFLEN instead of sizeof(cbRECBUFFLEN) --- src/cbshm/src/central_adapters/v7_0.cpp | 2 +- src/cbshm/src/central_adapters/v7_5.cpp | 2 +- src/cbshm/src/central_adapters/v7_6.cpp | 2 +- src/cbshm/src/central_adapters/v7_7.cpp | 2 +- src/cbshm/src/central_adapters/v7_8.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cbshm/src/central_adapters/v7_0.cpp b/src/cbshm/src/central_adapters/v7_0.cpp index 1cbb89f2..24457094 100644 --- a/src/cbshm/src/central_adapters/v7_0.cpp +++ b/src/cbshm/src/central_adapters/v7_0.cpp @@ -39,7 +39,7 @@ size_t BootstrapAdapter::getSpikeBufferSize() const { } size_t BootstrapAdapter::getReceiveBufferLen() const { - return sizeof(cbRECBUFFLEN); + return cbRECBUFFLEN; } void Adapter::fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const { diff --git a/src/cbshm/src/central_adapters/v7_5.cpp b/src/cbshm/src/central_adapters/v7_5.cpp index 4f2512d2..f805e279 100644 --- a/src/cbshm/src/central_adapters/v7_5.cpp +++ b/src/cbshm/src/central_adapters/v7_5.cpp @@ -39,7 +39,7 @@ size_t BootstrapAdapter::getSpikeBufferSize() const { } size_t BootstrapAdapter::getReceiveBufferLen() const { - return sizeof(cbRECBUFFLEN); + return cbRECBUFFLEN; } void Adapter::fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const { diff --git a/src/cbshm/src/central_adapters/v7_6.cpp b/src/cbshm/src/central_adapters/v7_6.cpp index 9caecac4..02e92f73 100644 --- a/src/cbshm/src/central_adapters/v7_6.cpp +++ b/src/cbshm/src/central_adapters/v7_6.cpp @@ -39,7 +39,7 @@ size_t BootstrapAdapter::getSpikeBufferSize() const { } size_t BootstrapAdapter::getReceiveBufferLen() const { - return sizeof(cbRECBUFFLEN); + return cbRECBUFFLEN; } void Adapter::fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const { diff --git a/src/cbshm/src/central_adapters/v7_7.cpp b/src/cbshm/src/central_adapters/v7_7.cpp index cd045f9d..149e36b9 100644 --- a/src/cbshm/src/central_adapters/v7_7.cpp +++ b/src/cbshm/src/central_adapters/v7_7.cpp @@ -39,7 +39,7 @@ size_t BootstrapAdapter::getSpikeBufferSize() const { } size_t BootstrapAdapter::getReceiveBufferLen() const { - return sizeof(cbRECBUFFLEN); + return cbRECBUFFLEN; } void Adapter::fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const { diff --git a/src/cbshm/src/central_adapters/v7_8.cpp b/src/cbshm/src/central_adapters/v7_8.cpp index 35b3dd57..de759dce 100644 --- a/src/cbshm/src/central_adapters/v7_8.cpp +++ b/src/cbshm/src/central_adapters/v7_8.cpp @@ -39,7 +39,7 @@ size_t BootstrapAdapter::getSpikeBufferSize() const { } size_t BootstrapAdapter::getReceiveBufferLen() const { - return sizeof(cbRECBUFFLEN); + return cbRECBUFFLEN; } void Adapter::fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const { From aa726cc0cc43feabfdc551d2ee528f25815e9180 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Wed, 1 Jul 2026 15:23:26 -0600 Subject: [PATCH 46/62] Fix the example for the Central client --- examples/CentralClient/central_client.cpp | 155 ++++++++-------------- 1 file changed, 59 insertions(+), 96 deletions(-) diff --git a/examples/CentralClient/central_client.cpp b/examples/CentralClient/central_client.cpp index 5475f8d9..5929fdf6 100644 --- a/examples/CentralClient/central_client.cpp +++ b/examples/CentralClient/central_client.cpp @@ -11,13 +11,14 @@ /// central_client 1 # Instance 1 (for multi-instance setups) /////////////////////////////////////////////////////////////////////////////////////////////////// +#include "cbproto/instrument_id.h" +#include +#include #include -#include #include #include #include #include -#include #include #include #include @@ -28,11 +29,6 @@ std::atomic g_running{true}; void signalHandler(int) { g_running = false; } -static std::string makeName(const char* base, int instance) { - if (instance == 0) return base; - return std::string(base) + std::to_string(instance); -} - int main(int argc, char* argv[]) { int instance = 0; if (argc >= 2) instance = std::atoi(argv[1]); @@ -44,88 +40,30 @@ int main(int argc, char* argv[]) { std::cout << " CereLink Central Client Diagnostic\n"; std::cout << "==============================================\n\n"; - // Print struct sizes for comparison with Central - std::cout << "=== Struct Size Verification ===\n"; - std::cout << " sizeof(CentralLegacyCFGBUFF): " << sizeof(CentralLegacyCFGBUFF) << "\n"; - std::cout << " sizeof(CentralReceiveBuffer): " << sizeof(CentralReceiveBuffer) << "\n"; - std::cout << " sizeof(CentralTransmitBuffer): " << sizeof(CentralTransmitBuffer) << "\n"; - std::cout << " sizeof(CentralTransmitBufferLocal): " << sizeof(CentralTransmitBufferLocal) << "\n"; - std::cout << " sizeof(CentralPCStatus): " << sizeof(CentralPCStatus) << "\n"; - std::cout << " sizeof(CentralSpikeBuffer): " << sizeof(CentralSpikeBuffer) << "\n"; - std::cout << " sizeof(CentralSpikeCache): " << sizeof(CentralSpikeCache) << "\n"; - std::cout << " sizeof(CentralAppWorkspace): " << sizeof(CentralAppWorkspace) << "\n"; - std::cout << "\n"; - - // Print key constants - std::cout << "=== Key Constants ===\n"; - std::cout << " CENTRAL_cbMAXPROCS: " << CENTRAL_cbMAXPROCS << "\n"; - std::cout << " CENTRAL_cbNUM_FE_CHANS: " << CENTRAL_cbNUM_FE_CHANS << "\n"; - std::cout << " CENTRAL_cbMAXCHANS: " << CENTRAL_cbMAXCHANS << "\n"; - std::cout << " CENTRAL_cbMAXBANKS: " << CENTRAL_cbMAXBANKS << "\n"; - std::cout << " CENTRAL_cbMAXNTRODES: " << CENTRAL_cbMAXNTRODES << "\n"; - std::cout << " CENTRAL_AOUT_NUM_GAIN_CHANS: " << CENTRAL_AOUT_NUM_GAIN_CHANS << "\n"; - std::cout << " CENTRAL_cbPKT_SPKCACHELINECNT: " << CENTRAL_cbPKT_SPKCACHELINECNT << "\n"; - std::cout << " CENTRAL_cbMAXAPPWORKSPACES: " << CENTRAL_cbMAXAPPWORKSPACES << "\n"; - std::cout << " sizeof(PROCTIME): " << sizeof(PROCTIME) << "\n"; - std::cout << "\n"; - - // Construct names for this instance - std::string cfg_name = makeName("cbCFGbuffer", instance); - std::string rec_name = makeName("cbRECbuffer", instance); - std::string xmt_name = makeName("XmtGlobal", instance); - std::string xmtl_name = makeName("XmtLocal", instance); - std::string status_name = makeName("cbSTATUSbuffer", instance); - std::string spk_name = makeName("cbSPKbuffer", instance); - std::string signal_name = makeName("cbSIGNALevent", instance); + // For the CENTRAL layout, name_qualifier is the Central instance suffix + // ("" for the primary instance, "1" for instance 1, etc.). + std::string instance_suffix = (instance == 0) ? "" : std::to_string(instance); std::cout << "=== Attempting Central CLIENT mode (instance " << instance << ") ===\n"; - std::cout << " Config: " << cfg_name << "\n"; - std::cout << " Receive: " << rec_name << "\n"; - std::cout << " XmtGlob: " << xmt_name << "\n"; - std::cout << " XmtLoc: " << xmtl_name << "\n"; - std::cout << " Status: " << status_name << "\n"; - std::cout << " Spike: " << spk_name << "\n"; - std::cout << " Signal: " << signal_name << "\n\n"; - - auto result = ShmemSession::create( - cfg_name, rec_name, xmt_name, xmtl_name, - status_name, spk_name, signal_name, - Mode::CLIENT, ShmemLayout::CENTRAL_COMPAT); + std::cout << std::endl; + + // Each ShmemSession targets a single instrument for its lifetime, so attach + // a fresh session per instrument id we want to inspect. + auto makeSession = [&](cbproto::InstrumentId id) { + return ShmemSession::create( + Mode::CLIENT, ShmemLayout::CENTRAL, instance_suffix, id); + }; + + auto result = makeSession(cbproto::InstrumentId::fromOneBased(cbNSP1)); if (result.isError()) { std::cerr << "FAILED to attach to Central's shared memory: " << result.error() << "\n"; - std::cerr << "\nIs Central running?\n"; + std::cerr << "\nIs Central running?" << std::endl; return 1; } auto session = std::move(result.value()); - std::cout << "SUCCESS: Attached to Central's shared memory!\n\n"; - - // Read config buffer - auto* cfg = session.getLegacyConfigBuffer(); - if (!cfg) { - std::cerr << "ERROR: getLegacyConfigBuffer() returned null\n"; - return 1; - } - - std::cout << "=== Config Buffer Contents ===\n"; - std::cout << " version: " << cfg->version << "\n"; - std::cout << " sysflags: 0x" << std::hex << cfg->sysflags << std::dec << "\n"; - - // Read procinfo for each instrument - std::cout << "\n=== Processor Info ===\n"; - for (uint32_t i = 0; i < CENTRAL_cbMAXPROCS; ++i) { - auto& proc = cfg->procinfo[i]; - // procinfo version field = (major << 16) | minor - uint32_t ver = proc.cbpkt_header.type; // Version is stored in a known field - std::cout << " Proc[" << i << "]:" - << " time=" << proc.cbpkt_header.time - << " chid=" << proc.cbpkt_header.chid - << " type=0x" << std::hex << proc.cbpkt_header.type << std::dec - << " dlen=" << proc.cbpkt_header.dlen - << " inst=" << (int)proc.cbpkt_header.instrument - << "\n"; - } + std::cout << "SUCCESS: Attached to Central's shared memory!" << std::endl; // Detect protocol version auto proto = session.getCompatProtocolVersion(); @@ -139,25 +77,53 @@ int main(int argc, char* argv[]) { default: std::cout << "UNKNOWN\n"; break; } + // Read procinfo for each instrument (one session per instrument) + std::cout << "\n=== Processor Info ===\n"; + uint32_t max_procs = session.getMaxProcs(); + for (uint32_t i = 0; i < max_procs; ++i) { + auto inst_result = makeSession(cbproto::InstrumentId::fromIndex(i)); + if (inst_result.isError()) { + std::cerr << "ERROR: failed to attach for instrument " << i + << ": " << inst_result.error() << std::endl; + return 1; + } + auto inst_session = std::move(inst_result.value()); + + // Read config buffer + auto cfg = std::make_unique(); + auto cfg_res = inst_session.getLegacyConfigBuffer(*cfg); + if (cfg_res.isError()) { + std::cerr << "ERROR: getLegacyConfigBuffer() returned error: " << cfg_res.error() << std::endl; + return 1; + } + + auto& proc = cfg->procinfo; + std::cout << " Proc: " + << " time=" << proc.cbpkt_header.time + << " chid=" << proc.cbpkt_header.chid + << " type=0x" << std::hex << proc.cbpkt_header.type << std::dec + << " dlen=" << proc.cbpkt_header.dlen + << " inst=" << (int)proc.cbpkt_header.instrument + << "\n"; + } + // Read status buffer std::cout << "\n=== PC Status ===\n"; auto num_total = session.getNumTotalChans(); if (num_total.isOk()) { std::cout << " Total channels: " << num_total.value() << "\n"; } - for (uint32_t i = 0; i < CENTRAL_cbMAXPROCS; ++i) { - auto nsp = session.getNspStatus(cbproto::InstrumentId::fromIndex(i)); - if (nsp.isOk()) { - const char* status_str = "?"; - switch (nsp.value()) { - case NSPStatus::NSP_INIT: status_str = "INIT"; break; - case NSPStatus::NSP_NOIPADDR: status_str = "NOIPADDR"; break; - case NSPStatus::NSP_NOREPLY: status_str = "NOREPLY"; break; - case NSPStatus::NSP_FOUND: status_str = "FOUND"; break; - case NSPStatus::NSP_INVALID: status_str = "INVALID"; break; - } - std::cout << " NSP[" << i << "] status: " << status_str << "\n"; + auto nsp = session.getNspStatus(); + if (nsp.isOk()) { + const char* status_str = "?"; + switch (nsp.value()) { + case NativeNSPStatus::NSP_INIT: status_str = "INIT"; break; + case NativeNSPStatus::NSP_NOIPADDR: status_str = "NOIPADDR"; break; + case NativeNSPStatus::NSP_NOREPLY: status_str = "NOREPLY"; break; + case NativeNSPStatus::NSP_FOUND: status_str = "FOUND"; break; + case NativeNSPStatus::NSP_INVALID: status_str = "INVALID"; break; } + std::cout << " NSP status: " << status_str << "\n"; } auto gemini = session.isGeminiSystem(); if (gemini.isOk()) { @@ -166,7 +132,7 @@ int main(int argc, char* argv[]) { // Read some channel info std::cout << "\n=== Sample Channel Info ===\n"; - for (uint32_t ch = 0; ch < 5 && ch < CENTRAL_cbMAXCHANS; ++ch) { + for (uint32_t ch = 0; ch < 5 && ch < cbMAXCHANS; ++ch) { auto ci = session.getChanInfo(ch); if (ci.isOk()) { auto& chan = ci.value(); @@ -184,9 +150,6 @@ int main(int argc, char* argv[]) { std::cout << "\n=== Monitoring Receive Buffer ===\n"; std::cout << "Waiting for packets (Ctrl+C to stop)...\n\n"; - // Set instrument filter for Hub1 (index 0 in GEMSTART=2 mapping) - session.setInstrumentFilter(0); - uint64_t total_packets = 0; auto start = std::chrono::steady_clock::now(); From 4738c8f79dff91955a075960dcab1964d559e598 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Wed, 1 Jul 2026 15:40:38 -0600 Subject: [PATCH 47/62] FIX: xmt -> xmt_local for local operations --- src/cbshm/src/central_adapters/v7_0.cpp | 12 ++++++------ src/cbshm/src/central_adapters/v7_5.cpp | 12 ++++++------ src/cbshm/src/central_adapters/v7_6.cpp | 12 ++++++------ src/cbshm/src/central_adapters/v7_7.cpp | 12 ++++++------ src/cbshm/src/central_adapters/v7_8.cpp | 12 ++++++------ 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/cbshm/src/central_adapters/v7_0.cpp b/src/cbshm/src/central_adapters/v7_0.cpp index 24457094..5099879b 100644 --- a/src/cbshm/src/central_adapters/v7_0.cpp +++ b/src/cbshm/src/central_adapters/v7_0.cpp @@ -967,27 +967,27 @@ uint32_t* Adapter::getXmtBufferPtr() { } uint32_t& Adapter::getLocalXmtTransmittedPtr() { - return xmt->transmitted; + return xmt_local->transmitted; } uint32_t& Adapter::getLocalXmtHeadindexPtr() { - return xmt->headindex; + return xmt_local->headindex; } uint32_t& Adapter::getLocalXmtTailindexPtr() { - return xmt->tailindex; + return xmt_local->tailindex; } uint32_t& Adapter::getLocalXmtLastValidIndexPtr() { - return xmt->last_valid_index; + return xmt_local->last_valid_index; } uint32_t& Adapter::getLocalXmtBufferlenPtr() { - return xmt->bufferlen; + return xmt_local->bufferlen; } uint32_t* Adapter::getLocalXmtBufferPtr() { - return xmt->buffer; + return xmt_local->buffer; } cbutil::Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { diff --git a/src/cbshm/src/central_adapters/v7_5.cpp b/src/cbshm/src/central_adapters/v7_5.cpp index f805e279..3a798e58 100644 --- a/src/cbshm/src/central_adapters/v7_5.cpp +++ b/src/cbshm/src/central_adapters/v7_5.cpp @@ -968,27 +968,27 @@ uint32_t* Adapter::getXmtBufferPtr() { } uint32_t& Adapter::getLocalXmtTransmittedPtr() { - return xmt->transmitted; + return xmt_local->transmitted; } uint32_t& Adapter::getLocalXmtHeadindexPtr() { - return xmt->headindex; + return xmt_local->headindex; } uint32_t& Adapter::getLocalXmtTailindexPtr() { - return xmt->tailindex; + return xmt_local->tailindex; } uint32_t& Adapter::getLocalXmtLastValidIndexPtr() { - return xmt->last_valid_index; + return xmt_local->last_valid_index; } uint32_t& Adapter::getLocalXmtBufferlenPtr() { - return xmt->bufferlen; + return xmt_local->bufferlen; } uint32_t* Adapter::getLocalXmtBufferPtr() { - return xmt->buffer; + return xmt_local->buffer; } cbutil::Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { diff --git a/src/cbshm/src/central_adapters/v7_6.cpp b/src/cbshm/src/central_adapters/v7_6.cpp index 02e92f73..45c4e066 100644 --- a/src/cbshm/src/central_adapters/v7_6.cpp +++ b/src/cbshm/src/central_adapters/v7_6.cpp @@ -972,27 +972,27 @@ uint32_t* Adapter::getXmtBufferPtr() { } uint32_t& Adapter::getLocalXmtTransmittedPtr() { - return xmt->transmitted; + return xmt_local->transmitted; } uint32_t& Adapter::getLocalXmtHeadindexPtr() { - return xmt->headindex; + return xmt_local->headindex; } uint32_t& Adapter::getLocalXmtTailindexPtr() { - return xmt->tailindex; + return xmt_local->tailindex; } uint32_t& Adapter::getLocalXmtLastValidIndexPtr() { - return xmt->last_valid_index; + return xmt_local->last_valid_index; } uint32_t& Adapter::getLocalXmtBufferlenPtr() { - return xmt->bufferlen; + return xmt_local->bufferlen; } uint32_t* Adapter::getLocalXmtBufferPtr() { - return xmt->buffer; + return xmt_local->buffer; } cbutil::Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { diff --git a/src/cbshm/src/central_adapters/v7_7.cpp b/src/cbshm/src/central_adapters/v7_7.cpp index 149e36b9..a77f5414 100644 --- a/src/cbshm/src/central_adapters/v7_7.cpp +++ b/src/cbshm/src/central_adapters/v7_7.cpp @@ -973,27 +973,27 @@ uint32_t* Adapter::getXmtBufferPtr() { } uint32_t& Adapter::getLocalXmtTransmittedPtr() { - return xmt->transmitted; + return xmt_local->transmitted; } uint32_t& Adapter::getLocalXmtHeadindexPtr() { - return xmt->headindex; + return xmt_local->headindex; } uint32_t& Adapter::getLocalXmtTailindexPtr() { - return xmt->tailindex; + return xmt_local->tailindex; } uint32_t& Adapter::getLocalXmtLastValidIndexPtr() { - return xmt->last_valid_index; + return xmt_local->last_valid_index; } uint32_t& Adapter::getLocalXmtBufferlenPtr() { - return xmt->bufferlen; + return xmt_local->bufferlen; } uint32_t* Adapter::getLocalXmtBufferPtr() { - return xmt->buffer; + return xmt_local->buffer; } cbutil::Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { diff --git a/src/cbshm/src/central_adapters/v7_8.cpp b/src/cbshm/src/central_adapters/v7_8.cpp index de759dce..f11de4ea 100644 --- a/src/cbshm/src/central_adapters/v7_8.cpp +++ b/src/cbshm/src/central_adapters/v7_8.cpp @@ -973,27 +973,27 @@ uint32_t* Adapter::getXmtBufferPtr() { } uint32_t& Adapter::getLocalXmtTransmittedPtr() { - return xmt->transmitted; + return xmt_local->transmitted; } uint32_t& Adapter::getLocalXmtHeadindexPtr() { - return xmt->headindex; + return xmt_local->headindex; } uint32_t& Adapter::getLocalXmtTailindexPtr() { - return xmt->tailindex; + return xmt_local->tailindex; } uint32_t& Adapter::getLocalXmtLastValidIndexPtr() { - return xmt->last_valid_index; + return xmt_local->last_valid_index; } uint32_t& Adapter::getLocalXmtBufferlenPtr() { - return xmt->bufferlen; + return xmt_local->bufferlen; } uint32_t* Adapter::getLocalXmtBufferPtr() { - return xmt->buffer; + return xmt_local->buffer; } cbutil::Result Adapter::getProcInfo(::cbPKT_PROCINFO& buf) const { From db37643816255dfef4ff3b315e586d28acfa4b72 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Wed, 1 Jul 2026 15:58:34 -0600 Subject: [PATCH 48/62] FIX: Central adapter construction Some transmit/receive buffer logic depends on the transmit/receive methods provided by the Central adapter even if Central is not in use. This fix always constructs the Central adapter for the most recent version so it's available. --- src/cbshm/src/shmem_session.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cbshm/src/shmem_session.cpp b/src/cbshm/src/shmem_session.cpp index f3cd53b5..74d8609e 100644 --- a/src/cbshm/src/shmem_session.cpp +++ b/src/cbshm/src/shmem_session.cpp @@ -417,7 +417,9 @@ struct ShmemSession::Impl { } else { // The compatibility protocol is ignored for NATIVE or CENTRAL // layouts and is always current for STANDALONE mode. + central_version = CentralVersion::CURRENT; compat_protocol = CBPROTO_PROTOCOL_CURRENT; + bootstrap_adapter = std::make_unique(); } // Compute buffer sizes based on layout and protocol version @@ -584,6 +586,10 @@ struct ShmemSession::Impl { adapter = std::make_unique(inst.toIndex(), cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); break; } + } else { + // The adapter is used to fetch the byte offset of fields in the transmit/receive buffers. + // TODO: Add helper methods in Impl for fetching byte offsets of transmit/receive buffer fields without relying on the Central adapter. + adapter = std::make_unique(inst.toIndex(), cfg_buffer_raw, rec_buffer_raw, xmt_buffer_raw, xmt_local_buffer_raw, status_buffer_raw, spike_buffer_raw); } // Initialize buffers in standalone mode From ecc22893736db71e607d5f4eb505be245ee81b67 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Wed, 1 Jul 2026 17:57:58 -0600 Subject: [PATCH 49/62] FIX: STANDALONE+CENTRAL (theoretically possible, not supported from this point forward) --- .../include/cbshm/central_adapters/base.h | 2 ++ .../include/cbshm/central_adapters/v7_0.h | 2 ++ .../include/cbshm/central_adapters/v7_5.h | 2 ++ .../include/cbshm/central_adapters/v7_6.h | 2 ++ .../include/cbshm/central_adapters/v7_7.h | 2 ++ .../include/cbshm/central_adapters/v7_8.h | 2 ++ src/cbshm/src/central_adapters/v7_0.cpp | 8 +++++ src/cbshm/src/central_adapters/v7_5.cpp | 8 +++++ src/cbshm/src/central_adapters/v7_6.cpp | 8 +++++ src/cbshm/src/central_adapters/v7_7.cpp | 8 +++++ src/cbshm/src/central_adapters/v7_8.cpp | 8 +++++ src/cbshm/src/shmem_session.cpp | 19 ++++++++++++ tests/unit/test_shmem_session.cpp | 30 +++++++++++-------- 13 files changed, 89 insertions(+), 12 deletions(-) diff --git a/src/cbshm/include/cbshm/central_adapters/base.h b/src/cbshm/include/cbshm/central_adapters/base.h index e8d8d37f..02ce0ff8 100644 --- a/src/cbshm/include/cbshm/central_adapters/base.h +++ b/src/cbshm/include/cbshm/central_adapters/base.h @@ -33,6 +33,8 @@ class CentralBootstrapAdapterBase { virtual size_t getStatusBufferSize() const = 0; virtual size_t getSpikeBufferSize() const = 0; virtual size_t getReceiveBufferLen() const = 0; + virtual size_t getTransmitBufferLen() const = 0; + virtual size_t getTransmitBufferLocalLen() const = 0; }; /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/cbshm/include/cbshm/central_adapters/v7_0.h b/src/cbshm/include/cbshm/central_adapters/v7_0.h index 665520c1..ea94e932 100644 --- a/src/cbshm/include/cbshm/central_adapters/v7_0.h +++ b/src/cbshm/include/cbshm/central_adapters/v7_0.h @@ -30,6 +30,8 @@ class BootstrapAdapter : public ::cbshm::CentralBootstrapAdapterBase { size_t getStatusBufferSize() const override; size_t getSpikeBufferSize() const override; size_t getReceiveBufferLen() const override; + size_t getTransmitBufferLen() const override; + size_t getTransmitBufferLocalLen() const override; }; /// diff --git a/src/cbshm/include/cbshm/central_adapters/v7_5.h b/src/cbshm/include/cbshm/central_adapters/v7_5.h index 954edc94..b7420177 100644 --- a/src/cbshm/include/cbshm/central_adapters/v7_5.h +++ b/src/cbshm/include/cbshm/central_adapters/v7_5.h @@ -30,6 +30,8 @@ class BootstrapAdapter : public ::cbshm::CentralBootstrapAdapterBase { size_t getStatusBufferSize() const override; size_t getSpikeBufferSize() const override; size_t getReceiveBufferLen() const override; + size_t getTransmitBufferLen() const override; + size_t getTransmitBufferLocalLen() const override; }; /// diff --git a/src/cbshm/include/cbshm/central_adapters/v7_6.h b/src/cbshm/include/cbshm/central_adapters/v7_6.h index b1089963..afcd7b42 100644 --- a/src/cbshm/include/cbshm/central_adapters/v7_6.h +++ b/src/cbshm/include/cbshm/central_adapters/v7_6.h @@ -30,6 +30,8 @@ class BootstrapAdapter : public ::cbshm::CentralBootstrapAdapterBase { size_t getStatusBufferSize() const override; size_t getSpikeBufferSize() const override; size_t getReceiveBufferLen() const override; + size_t getTransmitBufferLen() const override; + size_t getTransmitBufferLocalLen() const override; }; /// diff --git a/src/cbshm/include/cbshm/central_adapters/v7_7.h b/src/cbshm/include/cbshm/central_adapters/v7_7.h index 9de9ec5a..deb0b59f 100644 --- a/src/cbshm/include/cbshm/central_adapters/v7_7.h +++ b/src/cbshm/include/cbshm/central_adapters/v7_7.h @@ -30,6 +30,8 @@ class BootstrapAdapter : public ::cbshm::CentralBootstrapAdapterBase { size_t getStatusBufferSize() const override; size_t getSpikeBufferSize() const override; size_t getReceiveBufferLen() const override; + size_t getTransmitBufferLen() const override; + size_t getTransmitBufferLocalLen() const override; }; /// diff --git a/src/cbshm/include/cbshm/central_adapters/v7_8.h b/src/cbshm/include/cbshm/central_adapters/v7_8.h index 5e549758..9be34334 100644 --- a/src/cbshm/include/cbshm/central_adapters/v7_8.h +++ b/src/cbshm/include/cbshm/central_adapters/v7_8.h @@ -30,6 +30,8 @@ class BootstrapAdapter : public ::cbshm::CentralBootstrapAdapterBase { size_t getStatusBufferSize() const override; size_t getSpikeBufferSize() const override; size_t getReceiveBufferLen() const override; + size_t getTransmitBufferLen() const override; + size_t getTransmitBufferLocalLen() const override; }; /// diff --git a/src/cbshm/src/central_adapters/v7_0.cpp b/src/cbshm/src/central_adapters/v7_0.cpp index 5099879b..0b684153 100644 --- a/src/cbshm/src/central_adapters/v7_0.cpp +++ b/src/cbshm/src/central_adapters/v7_0.cpp @@ -42,6 +42,14 @@ size_t BootstrapAdapter::getReceiveBufferLen() const { return cbRECBUFFLEN; } +size_t BootstrapAdapter::getTransmitBufferLen() const { + return cbXMT_GLOBAL_BUFFLEN; +} + +size_t BootstrapAdapter::getTransmitBufferLocalLen() const { + return cbXMT_LOCAL_BUFFLEN; +} + void Adapter::fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const { cur.time = leg.time; // TODO: explicit or implicit conversion here (?) (and for all PROCTIME) cur.chid = leg.chid; diff --git a/src/cbshm/src/central_adapters/v7_5.cpp b/src/cbshm/src/central_adapters/v7_5.cpp index 3a798e58..a675009c 100644 --- a/src/cbshm/src/central_adapters/v7_5.cpp +++ b/src/cbshm/src/central_adapters/v7_5.cpp @@ -42,6 +42,14 @@ size_t BootstrapAdapter::getReceiveBufferLen() const { return cbRECBUFFLEN; } +size_t BootstrapAdapter::getTransmitBufferLen() const { + return cbXMT_GLOBAL_BUFFLEN; +} + +size_t BootstrapAdapter::getTransmitBufferLocalLen() const { + return cbXMT_LOCAL_BUFFLEN; +} + void Adapter::fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const { cur.time = leg.time; cur.chid = leg.chid; diff --git a/src/cbshm/src/central_adapters/v7_6.cpp b/src/cbshm/src/central_adapters/v7_6.cpp index 45c4e066..2f2741d9 100644 --- a/src/cbshm/src/central_adapters/v7_6.cpp +++ b/src/cbshm/src/central_adapters/v7_6.cpp @@ -42,6 +42,14 @@ size_t BootstrapAdapter::getReceiveBufferLen() const { return cbRECBUFFLEN; } +size_t BootstrapAdapter::getTransmitBufferLen() const { + return cbXMT_GLOBAL_BUFFLEN; +} + +size_t BootstrapAdapter::getTransmitBufferLocalLen() const { + return cbXMT_LOCAL_BUFFLEN; +} + void Adapter::fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const { cur.time = leg.time; cur.chid = leg.chid; diff --git a/src/cbshm/src/central_adapters/v7_7.cpp b/src/cbshm/src/central_adapters/v7_7.cpp index a77f5414..c334c978 100644 --- a/src/cbshm/src/central_adapters/v7_7.cpp +++ b/src/cbshm/src/central_adapters/v7_7.cpp @@ -42,6 +42,14 @@ size_t BootstrapAdapter::getReceiveBufferLen() const { return cbRECBUFFLEN; } +size_t BootstrapAdapter::getTransmitBufferLen() const { + return cbXMT_GLOBAL_BUFFLEN; +} + +size_t BootstrapAdapter::getTransmitBufferLocalLen() const { + return cbXMT_LOCAL_BUFFLEN; +} + void Adapter::fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const { cur.time = leg.time; cur.chid = leg.chid; diff --git a/src/cbshm/src/central_adapters/v7_8.cpp b/src/cbshm/src/central_adapters/v7_8.cpp index f11de4ea..77d86567 100644 --- a/src/cbshm/src/central_adapters/v7_8.cpp +++ b/src/cbshm/src/central_adapters/v7_8.cpp @@ -42,6 +42,14 @@ size_t BootstrapAdapter::getReceiveBufferLen() const { return cbRECBUFFLEN; } +size_t BootstrapAdapter::getTransmitBufferLen() const { + return cbXMT_GLOBAL_BUFFLEN; +} + +size_t BootstrapAdapter::getTransmitBufferLocalLen() const { + return cbXMT_LOCAL_BUFFLEN; +} + void Adapter::fromLegacy(::cbPKT_HEADER& cur, const cbPKT_HEADER& leg) const { cur.time = leg.time; cur.chid = leg.chid; diff --git a/src/cbshm/src/shmem_session.cpp b/src/cbshm/src/shmem_session.cpp index 74d8609e..fb8138f3 100644 --- a/src/cbshm/src/shmem_session.cpp +++ b/src/cbshm/src/shmem_session.cpp @@ -645,6 +645,25 @@ struct ShmemSession::Impl { } } + // Initialize transmit buffers in STANDALONE + CENTRAL mode. When Central + // owns the shared memory it populates last_valid_index/bufferlen itself, + // but in STANDALONE we create the segments, so we must set them or + // enqueuePacket's wrap check sees a zero-length ring and always reports + // "Transmit buffer full". (The receive/config/status/spike segments are + // fresh-mapped zero, which is a valid empty ring.) + if (mode == Mode::STANDALONE && layout == ShmemLayout::CENTRAL) { + std::memset(xmt_buffer_raw, 0, xmt_buffer_size); + std::memset(xmt_local_buffer_raw, 0, xmt_local_buffer_size); + + uint32_t xmt_len = static_cast(bootstrap_adapter->getTransmitBufferLen()); + adapter->getXmtLastValidIndexPtr() = xmt_len - 1; + adapter->getXmtBufferlenPtr() = xmt_len; + + uint32_t xmt_local_len = static_cast(bootstrap_adapter->getTransmitBufferLocalLen()); + adapter->getLocalXmtLastValidIndexPtr() = xmt_local_len - 1; + adapter->getLocalXmtBufferlenPtr() = xmt_local_len; + } + is_open = true; // In CLIENT mode, sync our read position to the current head so we only diff --git a/tests/unit/test_shmem_session.cpp b/tests/unit/test_shmem_session.cpp index 35b348e3..37c9f2aa 100644 --- a/tests/unit/test_shmem_session.cpp +++ b/tests/unit/test_shmem_session.cpp @@ -106,23 +106,29 @@ TEST_F(ShmemSessionTest, InstrumentStatusInitiallyInactive) { } TEST_F(ShmemSessionTest, SetInstrumentActive) { + // A ShmemSession represents a single instrument; setInstrumentActive()/ + // isInstrumentActive() operate on that one instrument's status. Verify the + // full active/inactive round-trip (InstrumentToggle only covers activation). auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()); auto& session = result.value(); - // Activate first instrument - auto set_result = session.setInstrumentActive(true); - ASSERT_TRUE(set_result.isOk()); + // Starts inactive. + auto initial = session.isInstrumentActive(); + ASSERT_TRUE(initial.isOk()); + EXPECT_FALSE(initial.value()); - // Verify it's active - auto active_result = session.isInstrumentActive(); - ASSERT_TRUE(active_result.isOk()); - EXPECT_TRUE(active_result.value()); - - // Other instruments should still be inactive - auto active_result2 = session.isInstrumentActive(); - ASSERT_TRUE(active_result2.isOk()); - EXPECT_FALSE(active_result2.value()); + // Activating is reflected by isInstrumentActive(). + ASSERT_TRUE(session.setInstrumentActive(true).isOk()); + auto activated = session.isInstrumentActive(); + ASSERT_TRUE(activated.isOk()); + EXPECT_TRUE(activated.value()); + + // Deactivating toggles it back off. + ASSERT_TRUE(session.setInstrumentActive(false).isOk()); + auto deactivated = session.isInstrumentActive(); + ASSERT_TRUE(deactivated.isOk()); + EXPECT_FALSE(deactivated.value()); } // TODO: getFirstActiveInstrument() and multi-instrument-per-session tracking were From 7bbbd008a43b7d51986f184d40dbefeb767aac2b Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Thu, 2 Jul 2026 17:11:21 -0400 Subject: [PATCH 50/62] Add client mode sequence diagrams. --- docs/README.md | 7 +- docs/cbSdkOpen_flowchart.svg | 4 - docs/cbSdkOpen_flowchart_V2.svg | 4 - docs/client_mode_sequence_diagrams.md | 274 ++++++++++++++++++++++++++ 4 files changed, 275 insertions(+), 14 deletions(-) delete mode 100644 docs/cbSdkOpen_flowchart.svg delete mode 100644 docs/cbSdkOpen_flowchart_V2.svg create mode 100644 docs/client_mode_sequence_diagrams.md diff --git a/docs/README.md b/docs/README.md index 662cea2f..646bb993 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,9 +4,4 @@ cbmex.pdf and .doc are here for historical reasons only. Contact the manufacture ## Source Code Architecture -### cbSdkOpen - -Here is a high-level flowchart for what happens inside the SDK when you call cbSdkOpen. - -![cbSdkOpen flowchart](cbSdkOpen_flowchart.svg) - +See the [client sequence diagrams](client_mode_sequence_diagrams.md). diff --git a/docs/cbSdkOpen_flowchart.svg b/docs/cbSdkOpen_flowchart.svg deleted file mode 100644 index de1e07d8..00000000 --- a/docs/cbSdkOpen_flowchart.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - -
cbSdkOpen
cbSdkOpen
instantiate app;
app.SdkOpen
instantiate a...
No?
UDP
No?...
Yes?
Central
Yes?...
Shared
Mutex
Exists?
Shared...
Open
Open
Register `this`
IntNetworkEvent
Callback
Register `this`...
Register `this`
ProcessIncomingPacket
delegate
Register `this`...
SdkApp : InstNetwork < QThread, InstNetwork:Listener
SdkApp : InstNetwork < QThread, InstNetwo...
QAppPriv::pApp
QCoreApplication
QAppPriv::pApp...
start(highPriority)
start(highPriority)
wait(connect mutex);
wait(connect mut...
return error code
return error code
InstNetwork::run
InstNetwork::run
NET_EVENT
INIT
NET_EVENT...
cbOpen
cbOpen
Yes
Yes
standalone?
standalone?
Open
Central's
buffers
Open...
No
No
Create
shared
buffers
Create...
NET_EVENT
NETSTANDALONE
NET_EVENT...
NET_EVENT
NETCLIENT
NET_EVENT...
Instrument
.Reset()
(clear cache)
Instrument...
Instrument
Open()
(open UDP)
Instrument...
startTimer(10)
startTimer(10)
exec()
(wait for quit();)
exec()...
while
!m_bDone
while...
cbWaitForData();
cbWaitForData();
OnWaitEvent();
OnWaitEvent();
Monitor semaphore in shared buffer
Monitor semaphor...
cbCheckForData
cbCheckForData
Process
IncomingPacket
Process...
handle config packets
handle config pa...
listener->
Process
IncomingPacket
listener->...
NET_EVENT
CLOSE
NET_EVENT...
Instrument
Close
Instrument...
cbClose
cbClose
InstNetwork::timerEvent
InstNetwork::timerEvent
yes
yes
no
no
m_bDone?
m_bDone?
killTimer()
QThread::quit()
killTimer()...
continue handshake
continue handsha...
yes
yes
first 5 secs?
first 5 secs?
Instrument
Tick()
Instrument...
Instrument
Recv()
Instrument...
Process
IncomingPacket
Process...
Instrument
Send()
Instrument...
process packet cache
process packet c...
cbSdkClose
cbSdkClose
Deallocate Trial constructs
Deallocate Trial con...
NULL callbacks
NULL callbacks
m_bDone = true;
m_bDone = true;
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/cbSdkOpen_flowchart_V2.svg b/docs/cbSdkOpen_flowchart_V2.svg deleted file mode 100644 index 421c0005..00000000 --- a/docs/cbSdkOpen_flowchart_V2.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - -
cbSdkClose
cbSdkClose
Deallocate Trial constructs
Deallocate Trial con...
NULL callbacks
NULL callbacks
m_bDone = true;
m_bDone = true;
cbSdkOpen
cbSdkOpen
instantiate app;
app.SdkOpen
instantiate a...
No?
ConType UDP
No?...
Yes?
conType Central
Yes?...
SdkApp
Open
SdkApp...
Register `this`
IntNetworkEvent
Callback
Register `this`...
Register `this`
ProcessIncomingPacket
delegate
Register `this`...
SdkApp : InstNetwork, InstNetwork:Listener
SdkApp : InstNetwork, InstNetwork...
return error code
return error code
Shared
Mutex
Exists?
Shared...
NET_EVENT
INIT
NET_EVENT...
cbOpen
cbOpen
yes
yes
standalone?
standalone?
wait for device_io
mutex
wait for device_i...
std::thread device_io
std::thread device_io
Create
shared
buffers
Create...
Instrument
.Reset()
(clear cache)
Instrument...
Instrument
Open()
(open UDP)
Instrument...
m_bDone?
m_bDone?
first 5 secs?
first 5 secs?
no
no
Instrument
Recv()
Instrument...
Instrument
Send()
Instrument...
continue handshake
continue handsha...
if no data
sleep(1 ms)
if no data...
cleanup
thread
cleanup...
buffer
buffer
buffer
buffer
std::thread buffer_io
std::thread buffer_io
Open
shared
buffers
Open...
NET_EVENT
CLOSE
NET_EVENT...
Instrument
Close
Instrument...
cbClose
cbClose
m_bDone?
m_bDone?
cbWaitForData();
cbWaitForData();
OnWaitEvent();
OnWaitEvent();
Monitor semaphore in shared buffer
Monitor semaphor...
cbCheckForData
cbCheckForData
Process
IncomingPacket
Process...
handle config packets
handle config pa...
listener->
Process
IncomingPacket
listener->...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/client_mode_sequence_diagrams.md b/docs/client_mode_sequence_diagrams.md new file mode 100644 index 00000000..593c0696 --- /dev/null +++ b/docs/client_mode_sequence_diagrams.md @@ -0,0 +1,274 @@ +# Client Mode Sequence Diagrams + +Sequence diagrams for the workflow between CereLink clients and cbsdk, for each of the +three client modes, and the differences in Central-compatible client mode when attached +to older Central versions. + +Reflects the code as of PR #190 (multi-version Central compatibility). Key sources: +`src/cbsdk/src/sdk_session.cpp`, `src/cbshm/src/shmem_session.cpp`, +`src/cbshm/src/central_version.cpp`, `src/cbshm/include/cbshm/central_adapters/*`. + +**See also**: [Shared memory architecture](shared_memory_architecture.md), +[Multi-version Central compatibility](multi_version_central_compat/README.md). + +## Mode selection (common entry point) + +Every client — C++ or pycbsdk (`Session()` → `cbsdk_session_create()` → +`SdkSession::create()`) — goes through the same three-way probe: + +```mermaid +sequenceDiagram + participant App as Client app / pycbsdk + participant SDK as SdkSession::create() + participant SHM as cbshm::ShmemSession + + App->>SDK: create(config{device_type=HUB1, ...}) + Note over SDK: instrument index from GEMSTART==2 map
(Hub1→0, Hub2→1, Hub3→2, NSP→3, legacy→0) + SDK->>SHM: create(CLIENT, CENTRAL, instance="", inst) + alt Central.exe running & its segments open + SHM-->>SDK: ok → CENTRAL-COMPAT CLIENT mode + else fails (no Central / non-Windows / wrong version) + SDK->>SHM: create(CLIENT, NATIVE, "hub1", inst 0) + alt cbshm_hub1_* segments exist AND owner alive + Note over SHM: isOwnerAlive(): kill(owner_pid, 0)
rejects stale segments + SHM-->>SDK: ok → NATIVE CLIENT mode + else fails or stale + SDK->>SHM: create(STANDALONE, NATIVE, "hub1", inst 0) + SHM-->>SDK: creates 7 segments → NATIVE STANDALONE mode + end + end +``` + +Note that the first attempt does not merely test whether Central's shared memory exists: +`ShmemSession::Impl::open()` calls `detectCentralVersion()` first, which requires finding +a running `Central.exe` process (Windows-only). If Central crashed leaving segments +behind, or on any POSIX platform, attempt 1 fails before any segment is touched. + +## Mode 1 — NATIVE STANDALONE (owns the device) + +```mermaid +sequenceDiagram + participant App as Client app + participant SDK as SdkSession + participant Q as SPSC queue +
callback thread + participant SHM as ShmemSession
(NATIVE, writer) + participant DEV as cbdev DeviceSession
(recv + send threads) + participant NSP as Device (UDP) + + rect rgba(88,110,255,0.15) + Note over App,NSP: Startup + App->>SDK: create() + SDK->>SHM: create(STANDALONE, NATIVE, "hub1") + Note over SHM: shm_unlink stale → create 7 segments
init cfg (owner_pid), xmt rings, status, spike cache + SDK->>DEV: createDeviceSession(params) + Note over DEV: ProtocolDetector probes device →
wraps in DeviceSession_311/400/410 if old protocol + SDK->>SDK: start(): spawn callback thread,
register recv + datagram callbacks,
DEV.startReceiveThread(), spawn send thread + SDK->>DEV: handshake (autorun ? performStartupHandshake : requestConfiguration) + DEV->>NSP: SYSSET/config request + NSP-->>DEV: SYSREP + config dump (PROCREP, CHANREP...) + SDK->>DEV: sendClockProbe() (initial) + end + + rect rgba(46,180,80,0.15) + Note over App,NSP: Steady state — receive path + NSP-->>DEV: UDP datagram (device-native protocol) + Note over DEV: versioned wrapper translates every packet
→ CURRENT format before anyone sees it + loop each packet in datagram + DEV->>SDK: receive callback(pkt) + SDK->>SHM: storePacket → writeToReceiveBuffer
(wrap-marker padding, release-store head) + SDK->>SHM: mirror config reps: setProcInfo / setSysInfo /
setGroupInfo / setChanInfo (+CMP overlay) + SDK->>Q: push(pkt) + end + DEV->>SDK: datagram-complete callback + SDK->>DEV: sendClockProbe() (every ~100 ms) + SDK->>SHM: setClockSync(offset_ns, uncertainty) + SDK->>SHM: signalData() — sem_post / SetEvent (wakes CLIENTs) + SDK->>Q: notify callback thread + Q->>App: dispatchBatch: group-batch callbacks,
then per-packet (event/group/config) callbacks + end + + rect rgba(255,150,40,0.15) + Note over App,NSP: Steady state — send path + App->>SDK: sendPacket(cmd) + SDK->>SHM: enqueuePacket (time stamped ns, CURRENT format → xmt ring) + Note over SDK: send thread polls xmt ring + SDK->>SHM: dequeuePacket + SDK->>DEV: sendPacket (wrapper translates to device protocol) + DEV->>NSP: UDP (paced: sleep every 8 packets) + end +``` + +Four threads total: cbdev UDP receive, cbdev-driven callbacks feeding the SPSC queue, +the SDK callback dispatcher, and the SDK send thread (plus main). + +## Mode 2 — NATIVE CLIENT (attaches to a CereLink STANDALONE) + +```mermaid +sequenceDiagram + participant App as Client app + participant SDK as SdkSession + participant SHM as ShmemSession
(NATIVE, reader) + participant SA as STANDALONE process + participant NSP as Device + + rect rgba(88,110,255,0.15) + Note over App,SA: Startup + App->>SDK: create() + SDK->>SHM: create(CLIENT, NATIVE, "hub1") + Note over SHM: attach cbshm_hub1_* (rec/status/spk read-only,
cfg + xmt read-write), tail synced to current head + SDK->>SHM: isOwnerAlive()? (kill(owner_pid,0)) + SDK->>SDK: start(): spawn ONE shmem-receive thread + SDK->>SHM: rebuildChannelTypeCache() from shmem chaninfo + end + + rect rgba(46,180,80,0.15) + Note over App,NSP: Steady state — receive + NSP-->>SA: UDP → translated to CURRENT → rec ring + SA-->>SHM: signalData() + SHM-->>SDK: waitForData(250ms) returns true + loop drain ring until empty (batches of 128) + SDK->>SHM: readReceiveBuffer() + Note over SHM: CURRENT format already — no translation,
no instrument filtering (single-device ring),
skip chid=0/type=0 wrap markers + SDK->>SDK: scan batch: SYSREP → runlevel,
NPLAYREP → complete client clock probe + SDK->>App: dispatchBatch → user callbacks (same thread) + end + end + + rect rgba(255,150,40,0.15) + Note over App,NSP: Send + client clock sync + App->>SDK: sendPacket(cmd) + SDK->>SHM: enqueuePacket → cbshm_hub1_xmt + SA->>SHM: dequeuePacket (its send thread) + SA->>NSP: UDP + Note over SDK: every ~2 s: enqueue NPLAYSET probe the same way —
NPLAYREP returns via rec ring → ClockSync sample + end +``` + +No callback thread — the ~256 MB ring absorbs bursts, so callbacks run directly on the +shmem-receive thread. + +## Mode 3 — CENTRAL-COMPAT CLIENT, latest Central (7.8 / protocol 4.2) + +This is the baseline that the versioned adapter machinery runs through even when no +translation is needed: + +```mermaid +sequenceDiagram + participant App as Client app + participant SDK as SdkSession + participant SHM as ShmemSession
(CENTRAL layout) + participant VER as central_version.cpp + participant ADP as central::Adapter (v7_8) + participant CTL as Central.exe + participant NSP as Devices (up to 4) + + rect rgba(88,110,255,0.15) + Note over App,CTL: Startup + App->>SDK: create(HUB1) — instrument idx 0 (GEMSTART==2) + SDK->>SHM: create(CLIENT, CENTRAL, instance="", inst) + SHM->>VER: detectCentralVersion() + VER->>CTL: enumerate processes → find Central.exe →
read VersionInfo.ProductVersion + VER-->>SHM: "7.8.x" → CentralVersion::CURRENT → protocol 4.2 + Note over SHM: BootstrapAdapter(CURRENT) supplies buffer sizes + SHM->>CTL: OpenFileMapping: cbCFGbuffer, cbRECbuffer,
XmtGlobal, XmtLocal, cbSTATUSbuffer, cbSPKbuffer, cbSIGNALevent + SHM->>ADP: construct with raw pointers into each segment + Note over SHM: tail ← head (only NEW packets) + SDK->>SDK: start(): shmem-receive thread,
rebuildChannelTypeCache via adapter + end + + rect rgba(46,180,80,0.15) + Note over App,NSP: Steady state — receive + NSP-->>CTL: UDP (all instruments) → Central writes RAW device
packets into ONE shared cbRECbuffer, SetEvent(~100/s) + CTL-->>SDK: waitForData wakes + loop drain ring + SDK->>SHM: readReceiveBuffer() + Note over SHM: protocol == CURRENT → parse 16-byte header,
copy packet as-is (no translation)
non-Gemini system: header.time ticks→ns via sysfreq
then FILTER: instrument != 0 → discard (after copy) + SDK->>App: dispatchBatch → callbacks + end + end + + rect rgba(255,150,40,0.15) + Note over App,NSP: Config access & send + App->>SDK: getChanInfo(n) + SDK->>SHM: getChanInfo → layout==CENTRAL + SHM->>ADP: getChanInfo(buf, idx) + Note over ADP: translate Central's cbPKT_CHANINFO struct →
cbproto type (7.8: field-for-field copy) + App->>SDK: sendPacket(cmd) + SDK->>SHM: enqueuePacket (ns→ticks if non-Gemini) → XmtGlobal + CTL->>NSP: Central's own loop drains XmtGlobal (4 pkts/10 ms) + end +``` + +Key contrasts with native client mode: the ring holds **raw device packets from all +instruments** (filtering discards other instruments' packets *after* fully +copying/translating them), config reads go through a struct-translating adapter instead +of direct pointer reads, and instrument status is assumed always-active / read-only. + +## How the flow changes with older Central versions + +The skeleton above is identical for 7.0–7.7; the deltas are confined to three seams — +version resolution at open, the adapter behind every config accessor, and per-packet +translation in the ring buffer paths: + +```mermaid +sequenceDiagram + participant SDK as SdkSession + participant SHM as ShmemSession + participant ADP as v7_x Adapter + participant PT as cbproto::PacketTranslator + participant CTL as Central (old) + + Note over SHM,CTL: Open: version → adapter selection + SHM->>CTL: read Central.exe ProductVersion + alt 7.7 / 7.6 → protocol 4.1 + SHM->>ADP: v7_7 / v7_6 BootstrapAdapter + Adapter + else 7.5 → protocol 4.0 + SHM->>ADP: v7_5 (16-byte header, reordered fields, 8-bit type) + else 7.0 → protocol 3.11 + SHM->>ADP: v7_0 (8-byte header, uint32 tick timestamps) + else major < 7 + SHM-->>SDK: error "update Central" → SDK falls back to NATIVE modes + end + Note over SHM,ADP: BootstrapAdapter returns VERSION-SPECIFIC buffer sizes
(segment mapping would be misaligned with wrong sizes) + + Note over SDK,PT: Receive: readReceiveBuffer (per packet) + SDK->>SHM: readReceiveBuffer() + alt protocol 3.11 + SHM->>SHM: parse 8-byte HEADER_311, copy raw to temp buf + SHM->>SHM: header→current: time = ticks·1e9/30000,
type u8→u16, instrument := 0 + SHM->>PT: translatePayload_311_to_current
(NPLAY, COMMENT, CHANINFO, SYSPROTOCOLMONITOR resize) + else protocol 4.0 + SHM->>SHM: parse HEADER_400, copy raw to temp buf + SHM->>SHM: header→current (field reorder, type widened) + SHM->>PT: translatePayload_400_to_current + else protocol 4.1 + SHM->>SHM: header identical — copy in place + SHM->>PT: translatePayload_410_to_current (payload-only diffs) + else protocol 4.2 (Central 7.8) + SHM->>SHM: straight copy, no PacketTranslator + end + Note over SHM: then (4.0+, non-Gemini): time ticks→ns via sysfreq
then instrument filter — same as current + + Note over SDK,CTL: Transmit: enqueuePacket (reverse translation) + SDK->>SHM: enqueuePacket(current-format pkt, time=ns) + alt 3.11 + SHM->>PT: current→311 header (ns→30 kHz ticks) + payload + else 4.0 / 4.1 + SHM->>PT: current→400/410 (+ ns→ticks when non-Gemini) + end + SHM->>CTL: write legacy-format packet into XmtGlobal ring + + Note over SDK,ADP: Config: every get/set goes through the versioned adapter + SDK->>SHM: getProcInfo / getChanInfo / getSpikeCache / getPcStatus ... + SHM->>ADP: v7_x translates that version's struct layout ↔ cbproto types
(array-size clamping/zero-fill via copyArr helpers) +``` + +### Version-to-behavior summary + +| Central app version | Protocol | Header in `cbRECbuffer` | Packet translation | Config/status/spike access | +|---|---|---|---|---| +| 7.8, and any unrecognized 7.x minor | 4.2 (CURRENT) | 16 B, ns timestamps | none | `central` (v7_8) adapter, ~identity copy | +| 7.7, 7.6 | 4.1 | 16 B, identical to current | payload-only (4 packet types) | v7_7 / v7_6 adapters | +| 7.5 | 4.0 | 16 B, reordered, u8 type | header + payload both ways | v7_5 adapter | +| 7.0 | 3.11 | 8 B, u32 ticks @30 kHz | header + payload + timestamp unit conversion; instrument forced to 0 | v7_0 adapter | +| major < 7 | — | — | attach refused → SDK falls back to native modes | — | From b90f5e7ad16fe0b27329c093cb705168779fd855 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Thu, 2 Jul 2026 06:53:33 -0600 Subject: [PATCH 51/62] Add additional tests for the Central adapter Common methods for all Adapter methods are tested. All copyArr and copyArr2D methods from base.h are tested. detectCentralVersion does not have unit tests and must be tested manually. --- tests/unit/CMakeLists.txt | 19 + tests/unit/test_central_adapter_base.cpp | 257 ++++++++++++++ tests/unit/test_central_adapters.cpp | 424 +++++++++++++++++++++++ 3 files changed, 700 insertions(+) create mode 100644 tests/unit/test_central_adapter_base.cpp create mode 100644 tests/unit/test_central_adapters.cpp diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 7450b753..ce1c5996 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -58,6 +58,25 @@ gtest_discover_tests(cbshm_tests) message(STATUS "Unit tests configured for cbshm") +# cbshm central adapter tests (per-version translation + copyArr helpers). +# Fully off-Windows testable: adapters translate caller-owned buffers, no shared +# memory or Central.exe required. +add_executable(cbshm_adapter_tests + test_central_adapters.cpp + test_central_adapter_base.cpp +) + +target_link_libraries(cbshm_adapter_tests + PRIVATE + cbshm + cbproto + GTest::gtest_main +) + +gtest_discover_tests(cbshm_adapter_tests) + +message(STATUS "Unit tests configured for cbshm central adapters") + # cbdev tests (non-device-dependent: packet translation, clock sync) add_executable(cbdev_tests test_packet_translation.cpp diff --git a/tests/unit/test_central_adapter_base.cpp b/tests/unit/test_central_adapter_base.cpp new file mode 100644 index 00000000..f721bc2d --- /dev/null +++ b/tests/unit/test_central_adapter_base.cpp @@ -0,0 +1,257 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file test_central_adapter_base.cpp +/// @author CereLink Development Team +/// +/// @brief Unit tests for the version-agnostic array helpers in CentralAdapterBase +/// (copyArr / copyArr2D). +/// +/// These helpers are the core "layout adaptation" primitive: whenever a Central +/// struct and its native equivalent have arrays of different dimensions, the +/// adapters copy the overlapping region and zero-fill the remainder. Getting the +/// truncation / zero-fill semantics wrong is exactly how a version bump silently +/// corrupts config data, so they are tested here in isolation from any concrete +/// version adapter. +/// +/// copyArr / copyArr2D are `protected static` members of CentralAdapterBase. We +/// reach them through a derived helper that re-exports them with public access +/// via using-declarations. The helper is never instantiated (it stays abstract), +/// so the pure-virtual interface does not need to be implemented. +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +using namespace cbshm; + +namespace { + +/// Re-exports the protected static array helpers with public access. +/// Abstract (pure virtuals left unimplemented) and never instantiated — we only +/// call its static members. +struct CopyArrAccess : public CentralAdapterBase { + using CentralAdapterBase::copyArr; + using CentralAdapterBase::copyArr2D; +}; + +/// A translator used to exercise the per-element translation-function overloads. +/// Doubles the source value into a wider destination type. +struct Doubler { + void translate(int32_t& dst, const int16_t& src) const { + dst = static_cast(src) * 2; + } +}; + +} // namespace + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name copyArr — 1-D, same element type (plain memcpy path) +/// @{ + +TEST(CopyArr1D, EqualSize_CopiesAll) { + int src[4] = {10, 20, 30, 40}; + int dst[4] = {0, 0, 0, 0}; + + CopyArrAccess::copyArr(dst, src); + + for (int i = 0; i < 4; ++i) EXPECT_EQ(dst[i], src[i]) << "index " << i; +} + +TEST(CopyArr1D, DestSmaller_Truncates) { + // lhs_n (3) < rhs_n (5): only the first 3 source elements are copied. + int src[5] = {1, 2, 3, 4, 5}; + int dst[3] = {-1, -1, -1}; + + CopyArrAccess::copyArr(dst, src); + + EXPECT_EQ(dst[0], 1); + EXPECT_EQ(dst[1], 2); + EXPECT_EQ(dst[2], 3); + // No overflow past dst[2] — verified implicitly by the fixed-size array. +} + +TEST(CopyArr1D, DestLarger_CopiesThenZeroFills) { + // lhs_n (5) > rhs_n (2): copy the 2 source elements, zero-fill the tail. + int src[2] = {7, 8}; + int dst[5] = {99, 99, 99, 99, 99}; + + CopyArrAccess::copyArr(dst, src); + + EXPECT_EQ(dst[0], 7); + EXPECT_EQ(dst[1], 8); + EXPECT_EQ(dst[2], 0) << "tail must be zero-filled"; + EXPECT_EQ(dst[3], 0); + EXPECT_EQ(dst[4], 0); +} + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name copyArr — 1-D, per-element translation-function overload +/// @{ + +TEST(CopyArr1DTranslate, EqualSize_TranslatesEach) { + Doubler d; + int16_t src[3] = {1, 2, 3}; + int32_t dst[3] = {0, 0, 0}; + + CopyArrAccess::copyArr(dst, src, &d, &Doubler::translate); + + EXPECT_EQ(dst[0], 2); + EXPECT_EQ(dst[1], 4); + EXPECT_EQ(dst[2], 6); +} + +TEST(CopyArr1DTranslate, DestSmaller_TranslatesTruncated) { + Doubler d; + int16_t src[4] = {5, 6, 7, 8}; + int32_t dst[2] = {0, 0}; + + CopyArrAccess::copyArr(dst, src, &d, &Doubler::translate); + + EXPECT_EQ(dst[0], 10); + EXPECT_EQ(dst[1], 12); +} + +TEST(CopyArr1DTranslate, DestLarger_TranslatesThenZeroFills) { + Doubler d; + int16_t src[2] = {3, 4}; + int32_t dst[4] = {99, 99, 99, 99}; + + CopyArrAccess::copyArr(dst, src, &d, &Doubler::translate); + + EXPECT_EQ(dst[0], 6); + EXPECT_EQ(dst[1], 8); + EXPECT_EQ(dst[2], 0) << "tail must be zero-filled (raw memset)"; + EXPECT_EQ(dst[3], 0); +} + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name copyArr2D — matching inner dimension (fast memcpy path) +/// @{ + +TEST(CopyArr2D, EqualDims_CopiesAll) { + int src[2][3] = {{1, 2, 3}, {4, 5, 6}}; + int dst[2][3] = {{0, 0, 0}, {0, 0, 0}}; + + CopyArrAccess::copyArr2D(dst, src); + + for (int y = 0; y < 2; ++y) + for (int x = 0; x < 3; ++x) + EXPECT_EQ(dst[y][x], src[y][x]) << "(" << y << "," << x << ")"; +} + +TEST(CopyArr2D, FewerDestRows_SameInner_Truncates) { + // lhs_ny (1) < rhs_ny (3), matching inner dim: memcpy of lhs_ny*lhs_nx. + int src[3][2] = {{1, 2}, {3, 4}, {5, 6}}; + int dst[1][2] = {{-1, -1}}; + + CopyArrAccess::copyArr2D(dst, src); + + EXPECT_EQ(dst[0][0], 1); + EXPECT_EQ(dst[0][1], 2); +} + +TEST(CopyArr2D, MoreDestRows_SameInner_ZeroFillsExtraRows) { + // lhs_ny (3) > rhs_ny (1), matching inner dim: copy row 0, zero-fill rows 1..2. + int src[1][2] = {{9, 8}}; + int dst[3][2] = {{5, 5}, {5, 5}, {5, 5}}; + + CopyArrAccess::copyArr2D(dst, src); + + EXPECT_EQ(dst[0][0], 9); + EXPECT_EQ(dst[0][1], 8); + for (int x = 0; x < 2; ++x) { + EXPECT_EQ(dst[1][x], 0) << "extra row 1 must be zero-filled"; + EXPECT_EQ(dst[2][x], 0) << "extra row 2 must be zero-filled"; + } +} + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name copyArr2D — mismatched inner dimension (per-row fallback path) +/// @{ + +TEST(CopyArr2D, MismatchedInner_DestInnerSmaller_TruncatesEachRow) { + int src[2][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}}; + int dst[2][2] = {{0, 0}, {0, 0}}; + + CopyArrAccess::copyArr2D(dst, src); + + EXPECT_EQ(dst[0][0], 1); + EXPECT_EQ(dst[0][1], 2); + EXPECT_EQ(dst[1][0], 5); + EXPECT_EQ(dst[1][1], 6); +} + +TEST(CopyArr2D, MismatchedInner_DestInnerLarger_ZeroFillsEachRowTail) { + int src[2][2] = {{1, 2}, {3, 4}}; + int dst[2][4] = {{9, 9, 9, 9}, {9, 9, 9, 9}}; + + CopyArrAccess::copyArr2D(dst, src); + + EXPECT_EQ(dst[0][0], 1); + EXPECT_EQ(dst[0][1], 2); + EXPECT_EQ(dst[0][2], 0) << "per-row tail must be zero-filled"; + EXPECT_EQ(dst[0][3], 0); + EXPECT_EQ(dst[1][0], 3); + EXPECT_EQ(dst[1][1], 4); + EXPECT_EQ(dst[1][2], 0); + EXPECT_EQ(dst[1][3], 0); +} + +TEST(CopyArr2D, MismatchedInner_MoreDestRows_ZeroFillsExtraRows) { + // lhs_ny (3) > rhs_ny (1) AND inner dims differ: per-row copy of row 0, + // then the extra rows are zero-filled. + int src[1][2] = {{1, 2}}; + int dst[3][3] = {{7, 7, 7}, {7, 7, 7}, {7, 7, 7}}; + + CopyArrAccess::copyArr2D(dst, src); + + EXPECT_EQ(dst[0][0], 1); + EXPECT_EQ(dst[0][1], 2); + EXPECT_EQ(dst[0][2], 0); + for (int y = 1; y < 3; ++y) + for (int x = 0; x < 3; ++x) + EXPECT_EQ(dst[y][x], 0) << "extra row " << y << " must be zero-filled"; +} + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name copyArr2D — per-element translation-function overload +/// @{ + +TEST(CopyArr2DTranslate, TranslatesEachElement) { + Doubler d; + int16_t src[2][2] = {{1, 2}, {3, 4}}; + int32_t dst[2][2] = {{0, 0}, {0, 0}}; + + CopyArrAccess::copyArr2D(dst, src, &d, &Doubler::translate); + + EXPECT_EQ(dst[0][0], 2); + EXPECT_EQ(dst[0][1], 4); + EXPECT_EQ(dst[1][0], 6); + EXPECT_EQ(dst[1][1], 8); +} + +TEST(CopyArr2DTranslate, MoreDestRows_TranslatesThenZeroFills) { + Doubler d; + int16_t src[1][2] = {{5, 6}}; + int32_t dst[3][2] = {{9, 9}, {9, 9}, {9, 9}}; + + CopyArrAccess::copyArr2D(dst, src, &d, &Doubler::translate); + + EXPECT_EQ(dst[0][0], 10); + EXPECT_EQ(dst[0][1], 12); + for (int y = 1; y < 3; ++y) + for (int x = 0; x < 2; ++x) + EXPECT_EQ(dst[y][x], 0) << "extra row " << y << " must be zero-filled"; +} + +/// @} diff --git a/tests/unit/test_central_adapters.cpp b/tests/unit/test_central_adapters.cpp new file mode 100644 index 00000000..fd4554c2 --- /dev/null +++ b/tests/unit/test_central_adapters.cpp @@ -0,0 +1,424 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file test_central_adapters.cpp +/// @author CereLink Development Team +/// +/// @brief Unit tests for the per-version Central shared-memory adapters +/// (central_v7_0 .. central_v7_8). +/// +/// These adapters translate between each Central version's binary struct layout +/// and the native cbproto types. They are the heart of the multi-version-compat +/// feature and are fully unit-testable off-Windows: the Adapter constructor takes +/// raw pointers to caller-owned buffers (no shared memory, no Central.exe), and +/// the private fromLegacy/toLegacy overloads are exercised transitively through +/// the public get/set methods. +/// +/// Structure: +/// - AdapterRoundTrip : ONE typed body run against all five versions. Verifies +/// the universal invariant "what you set is what you get" +/// (translation round-trips through the version's legacy +/// layout without loss). +/// - Divergence tests : targeted, named tests for behavior that genuinely +/// differs by version/protocol group (NSP/Gemini write +/// contract, v7_0 PcStatus hardcoding, bit-packed vs split +/// CHANINFO/AOUT fields, PROCINFO sortmethod aliasing). +/// +/// NOTE (scaffold): the round-trip assertions target fields that are expected to +/// survive on every version. Some index ranges (bank/filter/group/channel) and a +/// few divergence checks are marked TODO where they require inspecting the raw +/// version-specific legacy struct — fill those in against central_types/vX_Y.h. +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace cbshm; + +namespace { + +/// Binds a version's BootstrapAdapter + Adapter together for typed tests. +template +struct VersionTraits { + using Bootstrap = Boot; + using Adapter = Adpt; +}; + +using V7_0 = VersionTraits; +using V7_5 = VersionTraits; +using V7_6 = VersionTraits; +using V7_7 = VersionTraits; +using V7_8 = VersionTraits; + +/// All five versions — for invariants that must hold everywhere. +using AllVersions = ::testing::Types; + +/// Versions where setNspStatus / setGeminiSystem succeed (protocol 4.0+). +/// v7_0 (protocol 3.11) lacks these fields and returns errors — covered separately. +using NspWritableVersions = ::testing::Types; + +/// Stub size for the receive/transmit ring buffers. None of the adapter +/// *translation* tests dereference these buffers — the Adapter constructor only +/// stores the pointers (verified in the ctor), and no test here calls the +/// getRec*/getXmt*/enqueue/dequeue paths. Allocating Central's full rings +/// (~805 MB receive + ~290 MB transmit for v7_8) in every SetUp would zero-fill +/// >1 GB per test, blowing up wall time and risking OOM on CI. A small valid +/// allocation is all the pointers need. Ring-buffer behavior belongs in a +/// separate ShmemSession-level test, not here. +static constexpr size_t kStubRingSize = 4096; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @brief Owns the Central buffers and constructs the Adapter over them. +/// +/// The config and status buffers are allocated at their real (version-reported) +/// size because the tests read translated data out of them. The receive/transmit +/// rings are stubbed (see kStubRingSize). The spike buffer is stubbed by default +/// and only allocated full-size when a fixture overrides needsFullSpikeBuffer() +/// (i.e. when a test actually reads the spike cache). +/// +template +class AdapterFixture : public ::testing::Test { +protected: + typename T::Bootstrap boot; + std::vector cfg, rec, xmt, xmt_local, status, spike; + std::unique_ptr adapter; + + static constexpr uint8_t kInstrument = 0; + + /// Override to true in fixtures whose tests dereference the spike buffer. + virtual bool needsFullSpikeBuffer() const { return false; } + + void SetUp() override { + cfg.assign(boot.getConfigBufferSize(), 0); + status.assign(boot.getStatusBufferSize(), 0); + rec.assign(kStubRingSize, 0); + xmt.assign(kStubRingSize, 0); + xmt_local.assign(kStubRingSize, 0); + spike.assign(needsFullSpikeBuffer() ? boot.getSpikeBufferSize() : kStubRingSize, 0); + + adapter = std::make_unique( + kInstrument, cfg.data(), rec.data(), xmt.data(), + xmt_local.data(), status.data(), spike.data()); + } +}; + +} // namespace + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name AdapterRoundTrip — universal set/get invariants (all versions) +/// +/// LIMITATION: these are inverse-pair tests. set*() writes via toLegacy, get*() +/// reads via fromLegacy, so they verify the two translations are mutual inverses. +/// That catches dropped fields, truncation, and *asymmetric* mistakes (e.g. a +/// moninst/monchan swap in only one direction). It does NOT catch a *symmetric* +/// bug where both directions agree on a layout that does not match Central's real +/// bytes. Proving the on-wire layout requires seeding a raw version-specific +/// legacy struct and reading it back — see the scaffolded TODOs at the bottom of +/// this file. +/// @{ + +TYPED_TEST_SUITE(AdapterFixture, AllVersions); + +TYPED_TEST(AdapterFixture, BootstrapSizesArePositive) { + // Every buffer must have a non-zero size or the adapter would map nothing. + EXPECT_GT(this->boot.getConfigBufferSize(), 0u); + EXPECT_GT(this->boot.getReceiveBufferSize(), 0u); + EXPECT_GT(this->boot.getTransmitBufferSize(), 0u); + EXPECT_GT(this->boot.getTransmitBufferLocalSize(), 0u); + EXPECT_GT(this->boot.getStatusBufferSize(), 0u); + EXPECT_GT(this->boot.getSpikeBufferSize(), 0u); + EXPECT_GT(this->boot.getReceiveBufferLen(), 0u); + EXPECT_GT(this->boot.getTransmitBufferLen(), 0u); + EXPECT_GT(this->boot.getTransmitBufferLocalLen(), 0u); +} + +TYPED_TEST(AdapterFixture, MaxProcsIsSane) { + EXPECT_GE(this->adapter->getMaxProcs(), 1u); +} + +TYPED_TEST(AdapterFixture, ProcInfoRoundTrip) { + cbPKT_PROCINFO in; + std::memset(&in, 0, sizeof(in)); + in.proc = 1; + in.chancount = 256; + in.bankcount = 8; + // `reserved` is the field that actually diverges by version: on v7_0 it is + // aliased to the legacy `sortmethod` field, on v7_5+ it maps straight across. + // Exercise it explicitly so the round-trip touches the version-specific path + // rather than only the direct-copy scalars. + in.reserved = 0xABCDu; + + ASSERT_TRUE(this->adapter->setProcInfo(in).isOk()); + + cbPKT_PROCINFO out; + std::memset(&out, 0, sizeof(out)); + ASSERT_TRUE(this->adapter->getProcInfo(out).isOk()); + + EXPECT_EQ(out.proc, in.proc); + EXPECT_EQ(out.chancount, in.chancount); + EXPECT_EQ(out.bankcount, in.bankcount); + EXPECT_EQ(out.reserved, in.reserved); +} + +TYPED_TEST(AdapterFixture, BankInfoRoundTrip) { + const uint32_t bank = 1; // 1-based + cbPKT_BANKINFO in; + std::memset(&in, 0, sizeof(in)); + in.proc = 1; + in.bank = bank; + in.chancount = 32; + + ASSERT_TRUE(this->adapter->setBankInfo(bank, in).isOk()); + + cbPKT_BANKINFO out; + std::memset(&out, 0, sizeof(out)); + ASSERT_TRUE(this->adapter->getBankInfo(out, bank).isOk()); + + EXPECT_EQ(out.proc, in.proc); + EXPECT_EQ(out.bank, in.bank); + EXPECT_EQ(out.chancount, in.chancount); +} + +TYPED_TEST(AdapterFixture, FilterInfoRoundTrip) { + const uint32_t filt = 1; // 1-based + cbPKT_FILTINFO in; + std::memset(&in, 0, sizeof(in)); + in.proc = 1; + in.filt = filt; + in.hpfreq = 250000; + + ASSERT_TRUE(this->adapter->setFilterInfo(filt, in).isOk()); + + cbPKT_FILTINFO out; + std::memset(&out, 0, sizeof(out)); + ASSERT_TRUE(this->adapter->getFilterInfo(out, filt).isOk()); + + EXPECT_EQ(out.filt, in.filt); + EXPECT_EQ(out.hpfreq, in.hpfreq); +} + +TYPED_TEST(AdapterFixture, ChanInfoRoundTrip) { + const uint32_t chan_idx = 0; // 0-based index into the buffer + cbPKT_CHANINFO in; + std::memset(&in, 0, sizeof(in)); + in.chan = 1; + in.proc = 1; + in.bank = 1; + std::strncpy(in.label, "elec001", cbLEN_STR_LABEL); + + ASSERT_TRUE(this->adapter->setChanInfo(chan_idx, in).isOk()); + + cbPKT_CHANINFO out; + std::memset(&out, 0, sizeof(out)); + ASSERT_TRUE(this->adapter->getChanInfo(out, chan_idx).isOk()); + + EXPECT_EQ(out.chan, in.chan); + EXPECT_EQ(out.proc, in.proc); + EXPECT_EQ(out.bank, in.bank); + EXPECT_STREQ(out.label, in.label); +} + +TYPED_TEST(AdapterFixture, SysInfoRoundTrip) { + cbPKT_SYSINFO in; + std::memset(&in, 0, sizeof(in)); + in.sysfreq = 30000; + + ASSERT_TRUE(this->adapter->setSysInfo(in).isOk()); + + cbPKT_SYSINFO out; + std::memset(&out, 0, sizeof(out)); + ASSERT_TRUE(this->adapter->getSysInfo(out).isOk()); + + EXPECT_EQ(out.sysfreq, in.sysfreq); +} + +TYPED_TEST(AdapterFixture, GroupInfoRoundTrip) { + const uint32_t group = 0; // 0-based + cbPKT_GROUPINFO in; + std::memset(&in, 0, sizeof(in)); + in.proc = 1; + in.group = 1; + + ASSERT_TRUE(this->adapter->setGroupInfo(group, in).isOk()); + + cbPKT_GROUPINFO out; + std::memset(&out, 0, sizeof(out)); + ASSERT_TRUE(this->adapter->getGroupInfo(out, group).isOk()); + + EXPECT_EQ(out.proc, in.proc); + EXPECT_EQ(out.group, in.group); +} + +TYPED_TEST(AdapterFixture, GetConfigBufferReflectsProcInfo) { + // Write a distinctive value, then verify the full-buffer translation carries + // it through — not just that the call returns ok. + cbPKT_PROCINFO in; + std::memset(&in, 0, sizeof(in)); + in.proc = 7; + in.chancount = 128; + ASSERT_TRUE(this->adapter->setProcInfo(in).isOk()); + + // Large struct — heap-allocate. + auto buf = std::make_unique(); + ASSERT_TRUE(this->adapter->getConfigBuffer(*buf).isOk()); + + EXPECT_EQ(buf->procinfo.proc, 7u); + EXPECT_EQ(buf->procinfo.chancount, 128u); +} + +// pc-status is exercised meaningfully for every version elsewhere: v7_0 by +// V7_0Fixture (hardcoded fields) and v7_5..v7_8 by NspWritableFixture +// (buffer-backed fields), so no generic smoke test is needed here. + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Divergence — NSP status / Gemini write contract +/// +/// v7_0 (protocol 3.11) has no NSP-status or Gemini fields, so the setters must +/// return errors. v7_5+ have real fields and must succeed. +/// @{ + +// v7_0-specific divergence. Reuses AdapterFixture's buffer setup rather +// than re-allocating the six buffers by hand. +class V7_0Fixture : public AdapterFixture {}; + +TEST_F(V7_0Fixture, SetNspStatusReturnsError) { + EXPECT_TRUE(adapter->setNspStatus(NativeNSPStatus::NSP_FOUND).isError()) + << "v3.11 has no NSP status field"; + EXPECT_TRUE(adapter->setGeminiSystem(true).isError()) + << "v3.11 does not recognize Gemini systems"; +} + +// CHARACTERIZATION TEST (not a correctness assertion). v7_0's status buffer has +// no NSP/Gemini fields, so getPcStatus substitutes fixed values that do not come +// from the buffer. Those substitutes are stopgaps the implementation itself marks +// "TODO: VERIFY" — they are NOT known to be the right values. This test pins the +// current behavior so that (a) accidental changes to the stopgap are noticed and +// (b) when real 3.11 handling is implemented, this test fails loudly and must be +// revisited. Do not read a passing result as "these values are correct." +TEST_F(V7_0Fixture, PcStatusReportsStopgapDefaults) { + NativePCStatus out; + std::memset(&out, 0, sizeof(out)); + ASSERT_TRUE(adapter->getPcStatus(out).isOk()); + + // Independent of the (zeroed) buffer contents, confirming these are synthesized. + EXPECT_EQ(out.m_nNspStatus, NativeNSPStatus::NSP_FOUND); + EXPECT_EQ(out.m_nGeminiSystem, 1u); +} + +// Typed over v7_5..v7_8: setters succeed and getPcStatus reflects the buffer. +template +class NspWritableFixture : public AdapterFixture {}; +TYPED_TEST_SUITE(NspWritableFixture, NspWritableVersions); + +TYPED_TEST(NspWritableFixture, SetNspStatusSucceeds) { + EXPECT_TRUE(this->adapter->setNspStatus(NativeNSPStatus::NSP_FOUND).isOk()); +} + +TYPED_TEST(NspWritableFixture, GeminiFlagReflectsBuffer) { + // Zeroed buffer → not Gemini. + NativePCStatus before; + std::memset(&before, 0, sizeof(before)); + ASSERT_TRUE(this->adapter->getPcStatus(before).isOk()); + EXPECT_EQ(before.m_nGeminiSystem, 0u); + + // After setting, getPcStatus reflects the change. + ASSERT_TRUE(this->adapter->setGeminiSystem(true).isOk()); + NativePCStatus after; + std::memset(&after, 0, sizeof(after)); + ASSERT_TRUE(this->adapter->getPcStatus(after).isOk()); + EXPECT_NE(after.m_nGeminiSystem, 0u); +} + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Spike cache read (needs a full-size spike buffer) +/// @{ + +// getSpikeCache dereferences the spike buffer, so this fixture opts into the +// full-size allocation (all other fixtures stub it — see kStubRingSize). +template +class SpikeAdapterFixture : public AdapterFixture { +protected: + bool needsFullSpikeBuffer() const override { return true; } +}; +TYPED_TEST_SUITE(SpikeAdapterFixture, AllVersions); + +TYPED_TEST(SpikeAdapterFixture, GetSpikeCacheReadsEmptyCache) { + NativeSpikeCache cache; + std::memset(&cache, 0xFF, sizeof(cache)); // poison, so a real copy is observable + + ASSERT_TRUE(this->adapter->getSpikeCache(cache, 0).isOk()); + + // The zeroed spike buffer translates to an empty cache line; confirm the + // fields were actually populated (not left poisoned). + EXPECT_EQ(cache.valid, 0u); + EXPECT_EQ(cache.chid, 0u); +} + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Divergence — bit-packed vs split fields (CHANINFO monsource, AOUT trig) +/// +/// v7_0/v7_5 store moninst/monchan packed into a single 32-bit monsource and +/// trig/trigInst packed into a single 16-bit trig; v7_6+ store them as separate +/// fields. A set→get round-trip is symmetric on every version (below), so it does +/// NOT by itself distinguish packed from split storage. To prove the on-wire +/// layout, inspect the raw legacy struct in the cfg buffer. +/// @{ + +TYPED_TEST(AdapterFixture, ChanInfoMonSourceRoundTrips) { + const uint32_t chan_idx = 0; + cbPKT_CHANINFO in; + std::memset(&in, 0, sizeof(in)); + in.chan = 1; + in.moninst = 2; + in.monchan = 5; + in.triginst = 1; + + ASSERT_TRUE(this->adapter->setChanInfo(chan_idx, in).isOk()); + + cbPKT_CHANINFO out; + std::memset(&out, 0, sizeof(out)); + ASSERT_TRUE(this->adapter->getChanInfo(out, chan_idx).isOk()); + + EXPECT_EQ(out.moninst, in.moninst); + EXPECT_EQ(out.monchan, in.monchan); + // triginst is hardcoded to 0 on v7_0 (no such field in 3.11); real elsewhere. + // TODO: split this expectation by version once the v7_0 contract is confirmed. +} + +// TODO(scaffold): raw-layout divergence check. Cast the cfg buffer to the +// version's legacy cbCFGBUFF (from cbshm/central_types/vX_Y.h) and assert: +// - v7_0/v7_5: cfg->chaninfo[0].monsource == ((moninst << 16) | monchan) +// - v7_6+ : cfg->chaninfo[0].moninst / .monchan are separate fields +// This is the only way to verify storage format rather than round-trip symmetry. +// +// TEST(AdapterV7_0Divergence, ChanInfoPacksMonSource) { ... } +// TEST(AdapterV7_6Divergence, ChanInfoSplitsMonSource) { ... } + +// TODO(scaffold): AOUT_WAVEFORM trig/trigInst packing. There is no public +// getWaveform accessor on the adapter, so this divergence is only reachable by +// inspecting the raw legacy buffer after a config-buffer translation, or via the +// ShmemSession receive/transmit path. Decide the seam before implementing. + +// TODO(scaffold): PROCINFO sortmethod aliasing (v7_0 only). v7_0 maps +// cur.reserved <-> leg.sortmethod. Verify by setting cbPKT_PROCINFO.reserved, +// round-tripping, and (for proof of aliasing) inspecting the raw legacy +// procinfo.sortmethod in the cfg buffer. + +/// @} From f75d19f2eab433c5dcf696e741e6d0a13577732e Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Mon, 6 Jul 2026 11:23:48 -0600 Subject: [PATCH 52/62] Remove tests dependent on unknown behavior --- tests/unit/test_central_adapters.cpp | 77 +--------------------------- 1 file changed, 1 insertion(+), 76 deletions(-) diff --git a/tests/unit/test_central_adapters.cpp b/tests/unit/test_central_adapters.cpp index fd4554c2..b357c7d8 100644 --- a/tests/unit/test_central_adapters.cpp +++ b/tests/unit/test_central_adapters.cpp @@ -18,8 +18,7 @@ /// (translation round-trips through the version's legacy /// layout without loss). /// - Divergence tests : targeted, named tests for behavior that genuinely -/// differs by version/protocol group (NSP/Gemini write -/// contract, v7_0 PcStatus hardcoding, bit-packed vs split +/// differs by version/protocol group (bit-packed vs split /// CHANINFO/AOUT fields, PROCINFO sortmethod aliasing). /// /// NOTE (scaffold): the round-trip assertions target fields that are expected to @@ -64,10 +63,6 @@ using V7_8 = VersionTraits; -/// Versions where setNspStatus / setGeminiSystem succeed (protocol 4.0+). -/// v7_0 (protocol 3.11) lacks these fields and returns errors — covered separately. -using NspWritableVersions = ::testing::Types; - /// Stub size for the receive/transmit ring buffers. None of the adapter /// *translation* tests dereference these buffers — the Adapter constructor only /// stores the pointers (verified in the ctor), and no test here calls the @@ -277,73 +272,6 @@ TYPED_TEST(AdapterFixture, GetConfigBufferReflectsProcInfo) { EXPECT_EQ(buf->procinfo.chancount, 128u); } -// pc-status is exercised meaningfully for every version elsewhere: v7_0 by -// V7_0Fixture (hardcoded fields) and v7_5..v7_8 by NspWritableFixture -// (buffer-backed fields), so no generic smoke test is needed here. - -/// @} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -/// @name Divergence — NSP status / Gemini write contract -/// -/// v7_0 (protocol 3.11) has no NSP-status or Gemini fields, so the setters must -/// return errors. v7_5+ have real fields and must succeed. -/// @{ - -// v7_0-specific divergence. Reuses AdapterFixture's buffer setup rather -// than re-allocating the six buffers by hand. -class V7_0Fixture : public AdapterFixture {}; - -TEST_F(V7_0Fixture, SetNspStatusReturnsError) { - EXPECT_TRUE(adapter->setNspStatus(NativeNSPStatus::NSP_FOUND).isError()) - << "v3.11 has no NSP status field"; - EXPECT_TRUE(adapter->setGeminiSystem(true).isError()) - << "v3.11 does not recognize Gemini systems"; -} - -// CHARACTERIZATION TEST (not a correctness assertion). v7_0's status buffer has -// no NSP/Gemini fields, so getPcStatus substitutes fixed values that do not come -// from the buffer. Those substitutes are stopgaps the implementation itself marks -// "TODO: VERIFY" — they are NOT known to be the right values. This test pins the -// current behavior so that (a) accidental changes to the stopgap are noticed and -// (b) when real 3.11 handling is implemented, this test fails loudly and must be -// revisited. Do not read a passing result as "these values are correct." -TEST_F(V7_0Fixture, PcStatusReportsStopgapDefaults) { - NativePCStatus out; - std::memset(&out, 0, sizeof(out)); - ASSERT_TRUE(adapter->getPcStatus(out).isOk()); - - // Independent of the (zeroed) buffer contents, confirming these are synthesized. - EXPECT_EQ(out.m_nNspStatus, NativeNSPStatus::NSP_FOUND); - EXPECT_EQ(out.m_nGeminiSystem, 1u); -} - -// Typed over v7_5..v7_8: setters succeed and getPcStatus reflects the buffer. -template -class NspWritableFixture : public AdapterFixture {}; -TYPED_TEST_SUITE(NspWritableFixture, NspWritableVersions); - -TYPED_TEST(NspWritableFixture, SetNspStatusSucceeds) { - EXPECT_TRUE(this->adapter->setNspStatus(NativeNSPStatus::NSP_FOUND).isOk()); -} - -TYPED_TEST(NspWritableFixture, GeminiFlagReflectsBuffer) { - // Zeroed buffer → not Gemini. - NativePCStatus before; - std::memset(&before, 0, sizeof(before)); - ASSERT_TRUE(this->adapter->getPcStatus(before).isOk()); - EXPECT_EQ(before.m_nGeminiSystem, 0u); - - // After setting, getPcStatus reflects the change. - ASSERT_TRUE(this->adapter->setGeminiSystem(true).isOk()); - NativePCStatus after; - std::memset(&after, 0, sizeof(after)); - ASSERT_TRUE(this->adapter->getPcStatus(after).isOk()); - EXPECT_NE(after.m_nGeminiSystem, 0u); -} - -/// @} - /////////////////////////////////////////////////////////////////////////////////////////////////// /// @name Spike cache read (needs a full-size spike buffer) /// @{ @@ -388,7 +316,6 @@ TYPED_TEST(AdapterFixture, ChanInfoMonSourceRoundTrips) { in.chan = 1; in.moninst = 2; in.monchan = 5; - in.triginst = 1; ASSERT_TRUE(this->adapter->setChanInfo(chan_idx, in).isOk()); @@ -398,8 +325,6 @@ TYPED_TEST(AdapterFixture, ChanInfoMonSourceRoundTrips) { EXPECT_EQ(out.moninst, in.moninst); EXPECT_EQ(out.monchan, in.monchan); - // triginst is hardcoded to 0 on v7_0 (no such field in 3.11); real elsewhere. - // TODO: split this expectation by version once the v7_0 contract is confirmed. } // TODO(scaffold): raw-layout divergence check. Cast the cfg buffer to the From e9f8f361300854b64be6751240e40fa36373994b Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Mon, 6 Jul 2026 11:28:38 -0600 Subject: [PATCH 53/62] Update sequence diagram docs and clean other docs --- docs/client_mode_sequence_diagrams.md | 15 ++--- docs/multi_version_central_compat/README.md | 68 ++++++++++++++++++--- docs/shared_memory_architecture.md | 28 +++++---- src/cbsdk/src/sdk_session.cpp | 5 +- src/cbshm/src/shmem_session.cpp | 34 ++++++----- 5 files changed, 104 insertions(+), 46 deletions(-) diff --git a/docs/client_mode_sequence_diagrams.md b/docs/client_mode_sequence_diagrams.md index 593c0696..19e23c99 100644 --- a/docs/client_mode_sequence_diagrams.md +++ b/docs/client_mode_sequence_diagrams.md @@ -98,8 +98,9 @@ sequenceDiagram end ``` -Four threads total: cbdev UDP receive, cbdev-driven callbacks feeding the SPSC queue, -the SDK callback dispatcher, and the SDK send thread (plus main). +Three worker threads (plus main): the cbdev UDP-receive thread — which also runs the +receive and datagram-complete callbacks that feed the SPSC queue — the SDK callback +dispatcher, and the SDK send thread. ## Mode 2 — NATIVE CLIENT (attaches to a CereLink STANDALONE) @@ -137,7 +138,7 @@ sequenceDiagram rect rgba(255,150,40,0.15) Note over App,NSP: Send + client clock sync App->>SDK: sendPacket(cmd) - SDK->>SHM: enqueuePacket → cbshm_hub1_xmt + SDK->>SHM: enqueuePacket → cbshm_hub1_xmt_global SA->>SHM: dequeuePacket (its send thread) SA->>NSP: UDP Note over SDK: every ~2 s: enqueue NPLAYSET probe the same way —
NPLAYREP returns via rec ring → ClockSync sample @@ -182,7 +183,7 @@ sequenceDiagram CTL-->>SDK: waitForData wakes loop drain ring SDK->>SHM: readReceiveBuffer() - Note over SHM: protocol == CURRENT → parse 16-byte header,
copy packet as-is (no translation)
non-Gemini system: header.time ticks→ns via sysfreq
then FILTER: instrument != 0 → discard (after copy) + Note over SHM: protocol == CURRENT → parse 16-byte header,
copy packet as-is (no translation)
non-Gemini system: header.time ticks→ns via sysfreq
then FILTER: instrument != selected idx (0 for HUB1) → discard (after copy) SDK->>App: dispatchBatch → callbacks end end @@ -223,7 +224,7 @@ sequenceDiagram alt 7.7 / 7.6 → protocol 4.1 SHM->>ADP: v7_7 / v7_6 BootstrapAdapter + Adapter else 7.5 → protocol 4.0 - SHM->>ADP: v7_5 (16-byte header, reordered fields, 8-bit type) + SHM->>ADP: v7_5 (16-byte header, 8-bit type widens to 16 → shifted offsets) else 7.0 → protocol 3.11 SHM->>ADP: v7_0 (8-byte header, uint32 tick timestamps) else major < 7 @@ -268,7 +269,7 @@ sequenceDiagram | Central app version | Protocol | Header in `cbRECbuffer` | Packet translation | Config/status/spike access | |---|---|---|---|---| | 7.8, and any unrecognized 7.x minor | 4.2 (CURRENT) | 16 B, ns timestamps | none | `central` (v7_8) adapter, ~identity copy | -| 7.7, 7.6 | 4.1 | 16 B, identical to current | payload-only (4 packet types) | v7_7 / v7_6 adapters | -| 7.5 | 4.0 | 16 B, reordered, u8 type | header + payload both ways | v7_5 adapter | +| 7.7, 7.6 | 4.1 | 16 B, identical to current | payload-only (3 packets / 4 type codes) | v7_7 / v7_6 adapters | +| 7.5 | 4.0 | 16 B, u8 type widened to u16 → shifted offsets | header + payload both ways | v7_5 adapter | | 7.0 | 3.11 | 8 B, u32 ticks @30 kHz | header + payload + timestamp unit conversion; instrument forced to 0 | v7_0 adapter | | major < 7 | — | — | attach refused → SDK falls back to native modes | — | diff --git a/docs/multi_version_central_compat/README.md b/docs/multi_version_central_compat/README.md index 6cd3bbaf..63ed7e41 100644 --- a/docs/multi_version_central_compat/README.md +++ b/docs/multi_version_central_compat/README.md @@ -6,16 +6,20 @@ ## Brief -This document describes a compatibility layer within CereLink which enables cross-version compatibility with Central's shared memory. Previous versions of CereLink only supported the latest version of Central. This compatibility layer consists of an `Adapter` class which hides the implementation differences between protocol versions behind a common interface. +This document describes a compatibility layer within CereLink which enables cross-version compatibility with Central's shared memory. Previous versions of CereLink only supported the latest version of Central. This compatibility layer consists of an `Adapter` class which hides the implementation differences between Central versions behind a common interface. Adapters are selected per Central application version (see the `CentralVersion` enum in [Organization](#organization)). Central has a 'protocol version' and an 'application version'. As of the writing of this document, the most recent protocol and application versions are 4.2 and 7.8.0 respectively. Shared memory compatibility is dependent on the protocol version. Protocols with different major version numbers are completely incompatible whereas protocols with different minor version numbers may be partially compatible. Different application versions do not break protocol compatibility unless the protocol version has also changed. ## Organization -Each supported protocol version has a `BootstrapAdapter` and `Adapter`. The `BootstrapAdapter` class fetches the sizes of shared memory structs in order to instantiate an `Adapter` with raw pointers to each struct. Each adapter has a collection of Central structs which are translated to and from the native CereLink equivalents. These native equivalents (defined in cbproto and native_types.h) are the common language used by `ShmemSession` to perform operations on the shared memory buffers. +Each supported application version of Central has a `BootstrapAdapter` and `Adapter`. The `BootstrapAdapter` class fetches the sizes of shared memory structs in order to instantiate an `Adapter` with raw pointers to each struct. Each adapter has a collection of Central structs which are translated to and from the native CereLink equivalents. These native equivalents (defined in cbproto and native_types.h) are the common language used by `ShmemSession` to perform operations on the shared memory buffers. -The structure and sizes of types are defined in `src/cbshm/include/cbshm/central_types/*`. The translation behavior is defined in `src/cbshm/src/central_adapters/*`. Version headers in `src/cbshm/include/cbshm/central_adapters/*` should be nearly identical. +Adapters are named after the Central *application* version they support (e.g. `v7_0`, `v7_5`), not the protocol version. The `CentralVersion` enum in `src/cbshm/include/cbshm/central_version.h` enumerates every supported application version: `V7_0`, `V7_5`, `V7_6`, `V7_7`, and `CURRENT` (the newest supported version, currently 7.8). + +The structure and sizes of types are defined in `src/cbshm/include/cbshm/central_types/.h`. The adapter and bootstrap adapter classes are declared in `src/cbshm/include/cbshm/central_adapters/.h`, and their translation behavior is defined in `src/cbshm/src/central_adapters/.cpp`. Each version lives in its own namespace (e.g. `central_v7_0`). The current version's types and adapters live in `central_v7_8`, which `src/cbshm/include/cbshm/central_current.h` aliases as `central`. Version headers in `src/cbshm/include/cbshm/central_adapters/*` should be nearly identical. + +At runtime, `detectCentralVersion` (declared in `src/cbshm/include/cbshm/central_version.h`, defined in `src/cbshm/src/central_version.cpp`) inspects the application version of the running `Central.exe` and returns the matching `CentralVersion`. `getProtocolVersion` converts a `CentralVersion` to its protocol version for the receive/transmit buffer logic. `ShmemSession::Impl::open` uses the detected `CentralVersion` to select the appropriate `BootstrapAdapter` and `Adapter`. ## Limitations @@ -86,13 +90,31 @@ editor src/cbshm/src/central_adapters/.cpp Verify your changes by diffing the existing version header with the added version header. -#### 7. Add the version to ShmemSession::Impl +#### 7. Register the version + +First, add a value for the version to the `CentralVersion` enum. Because the added version is newer than any currently supported version, it becomes the new `CURRENT`; add an explicit value for the version that `CURRENT` previously coded for (e.g. `V7_8`). ```bash -editor src/cbshm/src/shmem_session.cpp +editor src/cbshm/include/cbshm/central_version.h +``` + +Repoint the `central` alias at the added version's namespace. + +```bash +editor src/cbshm/include/cbshm/central_current.h +``` + +Map the application version to the added `CentralVersion` value in `detectCentralVersion`, and map each `CentralVersion` value to its protocol version in `getProtocolVersion`. The added version maps to `CBPROTO_PROTOCOL_CURRENT`; the previously-current version now maps to its own (frozen) protocol version. + +```bash +editor src/cbshm/src/central_version.cpp ``` -Add `#include .h>` at the top of the file and append the adapter and bootstrap adapter to the corresponding switch statements in `ShmemSession::Impl::open`. Modify the switch statement at the bottom of `detectCompatProtocol` so corresponding application versions are mapped to the added protocol version. +Finally, register the adapter with `ShmemSession`. Add `#include .h>` and `#include .h>` near the top of the file and append cases for the new `CentralVersion` values to both switch statements in `ShmemSession::Impl::open` (one selects the `BootstrapAdapter`, the other selects the `Adapter`). The `CURRENT` case uses the `central::` alias, so the added version is reached through it; add an explicit case for the previously-current version. + +```bash +editor src/cbshm/src/shmem_session.cpp +``` #### 8. Add the adapter implementation to CMakeLists.txt @@ -114,6 +136,14 @@ The types in cbproto must match the most recent protocol version, `CBPROTO_PROTO All translators and adapters use the cbproto types, so these methods must be fixed to translate to the added version instead. +#### 11. Add the version to the adapter unit tests + +```bash +editor tests/unit/test_central_adapters.cpp +``` + +Add `#include .h>` near the top of the file, define a `VersionTraits` alias for the version (e.g. `using V7_9 = VersionTraits;`), and add that alias to the `AllVersions` type list so the round-trip invariants run against it. If the added version's protocol has the NSP-status and Gemini fields (protocol 4.0+), also add the alias to the `NspWritableVersions` type list; otherwise leave it out and cover its divergent behavior with dedicated tests. The test file has no entry in `tests/unit/CMakeLists.txt` to update — it already compiles every version through these type lists. + ### Add an older protocol version @@ -167,13 +197,25 @@ editor src/cbshm/src/central_adapters/.cpp Verify your changes by diffing the existing version header with the added version header. -#### 7. Add the version to ShmemSession::Impl +#### 7. Register the version + +First, add a value for the version to the `CentralVersion` enum. ```bash -editor src/cbshm/src/shmem_session.cpp +editor src/cbshm/include/cbshm/central_version.h +``` + +Map the application version to the added `CentralVersion` value in `detectCentralVersion`, and map the added `CentralVersion` value to its protocol version in `getProtocolVersion`. + +```bash +editor src/cbshm/src/central_version.cpp ``` -Add `#include .h>` at the top of the file and append the adapter and bootstrap adapter to the corresponding switch statements in `ShmemSession::Impl::open`. Modify the switch statement at the bottom of `detectCompatProtocol` so corresponding application versions are mapped to the added protocol version. +Finally, register the adapter with `ShmemSession`. Add `#include .h>` and `#include .h>` near the top of the file and append a case for the added `CentralVersion` value to both switch statements in `ShmemSession::Impl::open` (one selects the `BootstrapAdapter`, the other selects the `Adapter`). + +```bash +editor src/cbshm/src/shmem_session.cpp +``` #### 8. Add the adapter implementation to CMakeLists.txt @@ -183,6 +225,14 @@ editor src/cbshm/CMakeLists.txt Append `src/central_adapters/.cpp` to the `CBSHMEM_SOURCES` environment variable. +#### 9. Add the version to the adapter unit tests + +```bash +editor tests/unit/test_central_adapters.cpp +``` + +Add `#include .h>` near the top of the file, define a `VersionTraits` alias for the version (e.g. `using V7_1 = VersionTraits;`), and add that alias to the `AllVersions` type list so the round-trip invariants run against it. If the added version's protocol has the NSP-status and Gemini fields (protocol 4.0+), also add the alias to the `NspWritableVersions` type list; otherwise leave it out and cover its divergent behavior with dedicated tests. The test file has no entry in `tests/unit/CMakeLists.txt` to update — it already compiles every version through these type lists. + ## Remove a protocol version diff --git a/docs/shared_memory_architecture.md b/docs/shared_memory_architecture.md index 88f4168b..01cc4302 100644 --- a/docs/shared_memory_architecture.md +++ b/docs/shared_memory_architecture.md @@ -85,12 +85,12 @@ auto session = SdkSession::open(DeviceType::HUB1); || NATIVE SHARED MEMORY (per device) || || Named: cbshm_{device}_{segment} || || || - || 1. cbshm_hub1_cfg | Config for 1 device (284 channels, ~1 MB) || - || 2. cbshm_hub1_rec | Receive ring buffer (~256 MB) || - || 3. cbshm_hub1_xmt | Transmit queue (~5 MB) || + || 1. cbshm_hub1_config | Config for 1 device (284 channels, ~1 MB) || + || 2. cbshm_hub1_receive | Receive ring buffer (~256 MB) || + || 3. cbshm_hub1_xmt_global | Transmit queue (~5 MB) || || 4. cbshm_hub1_xmt_local | Local transmit queue (~2 MB) || || 5. cbshm_hub1_status | Device status (~few KB) || - || 6. cbshm_hub1_spk | Spike cache (272 analog channels) || + || 6. cbshm_hub1_spike | Spike cache (272 analog channels) || || 7. cbshm_hub1_signal | Data availability signal || || || || All packets stored in CURRENT protocol format (translation at cbdev layer) || @@ -126,16 +126,16 @@ Each device gets its own set of shared memory segments: cbshm_{device}_{segment} Examples: - cbshm_nsp_cfg cbshm_hub1_cfg cbshm_hub2_cfg - cbshm_nsp_rec cbshm_hub1_rec cbshm_hub2_rec - cbshm_nsp_xmt cbshm_hub1_xmt cbshm_hub2_xmt + cbshm_nsp_config cbshm_hub1_config cbshm_hub2_config + cbshm_nsp_receive cbshm_hub1_receive cbshm_hub2_receive + cbshm_nsp_xmt_global cbshm_hub1_xmt_global cbshm_hub2_xmt_global cbshm_nsp_xmt_local cbshm_hub1_xmt_local cbshm_hub2_xmt_local cbshm_nsp_status cbshm_hub1_status cbshm_hub2_status - cbshm_nsp_spk cbshm_hub1_spk cbshm_hub2_spk + cbshm_nsp_spike cbshm_hub1_spike cbshm_hub2_spike cbshm_nsp_signal cbshm_hub1_signal cbshm_hub2_signal ``` -On POSIX, names are prefixed with `/` (e.g., `/cbshm_hub1_rec`). +On POSIX, names are prefixed with `/` (e.g., `/cbshm_hub1_receive`). ### Per-Device Config Buffer (Native) @@ -267,12 +267,13 @@ When CereLink attaches to Central's shared memory, Central may be running an old (3.11, 4.0, or 4.1). Central stores raw device packets in `cbRECbuffer` without translation. CereLink detects the protocol version and translates packets on-the-fly. -**Protocol detection** (`detectCompatProtocol`) cannot rely on Central's shared memory: +**Version detection** (`detectCentralVersion`) cannot rely on Central's shared memory: the `version` field in `cbCFGBUFF` is a magic number (`96`), not a meaningful version, and `procinfo[].version` is unusable because its byte offset shifts between protocol versions. Instead, detection inspects the **application version** of the running `Central.exe` -(`VersionInfo.ProductVersion`) and maps it to a protocol version. This is **Windows-only**; -on other platforms compat mode is unavailable. +(`VersionInfo.ProductVersion`) and maps it to a `CentralVersion` enum value. A companion +function, `getProtocolVersion`, converts that `CentralVersion` to its protocol version. This +is **Windows-only**; on other platforms compat mode is unavailable. The application-version → protocol-version mapping: - Central 7.0 → Protocol 3.11 (8-byte headers, 32-bit timestamps) @@ -282,7 +283,8 @@ The application-version → protocol-version mapping: - Central major version < 7 → unsupported (caller must upgrade Central) This indirect approach is brittle: a future Central with a different executable name or -version-string format would defeat it. See `detectCompatProtocol` in `shmem_session.cpp`. +version-string format would defeat it. See `detectCentralVersion` and `getProtocolVersion` +in `central_version.cpp`. **Receive path** (`readReceiveBuffer`): Parses the protocol-specific header to extract `dlen`, copies raw bytes from the ring buffer, translates header + payload to current diff --git a/src/cbsdk/src/sdk_session.cpp b/src/cbsdk/src/sdk_session.cpp index 71ba720d..6554d864 100644 --- a/src/cbsdk/src/sdk_session.cpp +++ b/src/cbsdk/src/sdk_session.cpp @@ -611,7 +611,10 @@ static int32_t getCentralInstrumentIndex(DeviceType type) { case DeviceType::HUB3: return 2; case DeviceType::NSP: return 3; case DeviceType::LEGACY_NSP: return 0; // Non-Gemini, single instrument - default: return -1; // No filter + // No CENTRAL instrument mapping (e.g. NPLAY). -1 yields an invalid + // InstrumentId, so CENTRAL-mode create() fails and the caller falls + // back to NATIVE. This is NOT a "match all instruments" sentinel. + default: return -1; } } diff --git a/src/cbshm/src/shmem_session.cpp b/src/cbshm/src/shmem_session.cpp index fb8138f3..379d571d 100644 --- a/src/cbshm/src/shmem_session.cpp +++ b/src/cbshm/src/shmem_session.cpp @@ -110,26 +110,27 @@ struct SegmentNames { // "cbshm__", where name_qualifier is the device token // (e.g. "hub1"), matching the names a CereLink STANDALONE publishes. inline SegmentNames makeSegmentNames(ShmemLayout layout, const std::string& name_qualifier) { - const std::string& s = name_qualifier; // instance suffix if (layout == ShmemLayout::NATIVE) { + const std::string& device = name_qualifier; return SegmentNames{ - "cbshm_config_" + s, - "cbshm_receive_" + s, - "cbshm_xmt_global_" + s, - "cbshm_xmt_local_" + s, - "cbshm_status_" + s, - "cbshm_spike_" + s, - "cbshm_signal_" + s + "cbshm_" + device + "_config", + "cbshm_" + device + "_receive", + "cbshm_" + device + "_xmt_global", + "cbshm_" + device + "_xmt_local", + "cbshm_" + device + "_status", + "cbshm_" + device + "_spike", + "cbshm_" + device + "_signal" }; } else { + const std::string& suffix = name_qualifier; return SegmentNames{ - "cbCFGbuffer" + s, - "cbRECbuffer" + s, - "XmtGlobal" + s, - "XmtLocal" + s, - "cbSTATUSbuffer" + s, - "cbSPKbuffer" + s, - "cbSIGNALevent" + s + "cbCFGbuffer" + suffix, + "cbRECbuffer" + suffix, + "XmtGlobal" + suffix, + "XmtLocal" + suffix, + "cbSTATUSbuffer" + suffix, + "cbSPKbuffer" + suffix, + "cbSIGNALevent" + suffix }; } } @@ -843,7 +844,7 @@ Result ShmemSession::isInstrumentActive() const { bool active = (m_impl->nativeCfg()->instrument_status == static_cast(InstrumentStatus::ACTIVE)); return Result::ok(active); } else { - // CentralLegacyCFGBUFF has no instrument_status field; + // cbCFGBUFF has no instrument_status field; // if the shared memory exists, instruments are as Central configured them return Result::ok(true); } @@ -1942,6 +1943,7 @@ Result ShmemSession::readReceiveBuffer(cbPKT_GENERIC* packets, size_t max_ m_impl->rec_tailwrap++; } + // Filter packets so only those from the selected instrument are read. uint8_t pkt_instrument = packets[packets_read].cbpkt_header.instrument; if (pkt_instrument != m_impl->inst.toIndex()) { continue; // Skip this packet, don't increment packets_read From c9aac1f940c95bb4d4f24c73cc05982ae37a4b75 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Wed, 8 Jul 2026 15:23:32 -0600 Subject: [PATCH 54/62] FIX: check result of device_session->getChanInfo --- src/cbsdk/src/sdk_session.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/cbsdk/src/sdk_session.cpp b/src/cbsdk/src/sdk_session.cpp index 06483bca..5f99f5e5 100644 --- a/src/cbsdk/src/sdk_session.cpp +++ b/src/cbsdk/src/sdk_session.cpp @@ -317,8 +317,13 @@ struct SdkSession::Impl { return shmem_session->getChanInfo(chan_id - 1); } // Fallback to device_config (no shmem available) - if (device_session) - return Result::ok(*device_session->getChanInfo(chan_id)); + if (device_session) { + const auto* chaninfo = device_session->getChanInfo(chan_id); + if (!chaninfo) { + return Result::error("Failed to get channel information"); + } + return Result::ok(*chaninfo); + } return Result::error("Channel information not available"); } From a6a34eec1e8f74acbc6a41c4a8648fdda516fd9f Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Wed, 8 Jul 2026 15:57:23 -0600 Subject: [PATCH 55/62] FIX: Shared memory names too long for MacOS --- tests/unit/test_shmem_session.cpp | 50 ++++++++++++++++--------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/tests/unit/test_shmem_session.cpp b/tests/unit/test_shmem_session.cpp index 56cfc634..9f9becdf 100644 --- a/tests/unit/test_shmem_session.cpp +++ b/tests/unit/test_shmem_session.cpp @@ -32,7 +32,8 @@ class ShmemSessionTest : public ::testing::Test { protected: void SetUp() override { // Use unique names for each test to avoid conflicts - test_name = "test_shmem_" + std::to_string(test_counter++); + // s = shmem + test_name = "s" + std::to_string(test_counter++); } void TearDown() override { @@ -787,12 +788,13 @@ TEST_F(ShmemSessionTest, StorePacket_NM_TrackableObject) { class NativeShmemSessionTest : public ::testing::Test { protected: void SetUp() override { - test_name = "test_native_" + std::to_string(test_counter++); + // n = native + test_name = "n" + std::to_string(test_counter++); } // Helper to create a native STANDALONE session Result createNativeSession() { - return ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); + return ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); } std::string test_name; @@ -1186,12 +1188,13 @@ TEST_F(NativeShmemSessionTest, NumTotalChans) { class CentralCompatShmemSessionTest : public ::testing::Test { protected: void SetUp() override { - test_name = "test_compat_" + std::to_string(test_counter++); + // c = compat + test_name = "c" + std::to_string(test_counter++); } // Helper to create a CENTRAL STANDALONE session (for testing) Result createCompatSession() { - return ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); + return ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); } std::string test_name; @@ -1252,8 +1255,7 @@ TEST_F(CentralCompatShmemSessionTest, SetInstrumentActive_ReturnsError) { TEST_F(CentralCompatShmemSessionTest, SetAndGetProcInfo) { // A CENTRAL session targets a single instrument; create one for instrument 2. - auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, - test_name + "_cfg", InstrumentId::fromOneBased(2)); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, test_name, InstrumentId::fromOneBased(2)); ASSERT_TRUE(result.isOk()) << result.error(); auto& session = result.value(); @@ -1346,8 +1348,7 @@ TEST_F(CentralCompatShmemSessionTest, SetAndGetChanInfo) { TEST_F(CentralCompatShmemSessionTest, InstrumentFilter_ReturnsOwnInstrument) { // A session bound to instrument 2 should only see instrument-2 packets when // reading the (shared) receive buffer. - auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, - test_name + "_cfg", InstrumentId::fromIndex(2)); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, test_name, InstrumentId::fromIndex(2)); ASSERT_TRUE(result.isOk()) << result.error(); auto& session = result.value(); @@ -1415,11 +1416,12 @@ TEST_F(CentralCompatShmemSessionTest, TransmitQueueRoundTrip) { class CentralCompatProtocolTest : public ::testing::Test { protected: void SetUp() override { - test_name = "test_proto_" + std::to_string(test_counter++); + // p = proto + test_name = "p" + std::to_string(test_counter++); } Result createCompatSession() { - return ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); + return ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); } std::string test_name; @@ -1490,8 +1492,7 @@ TEST_F(CentralCompatProtocolTest, ReadCurrentFormat_WithRealisticTimestamps) { /// @brief Test readReceiveBuffer's implicit per-instrument filtering with current-format packets TEST_F(CentralCompatProtocolTest, InstrumentFilterWithCurrentProtocol) { // Bind the session to instrument 3; readReceiveBuffer returns only its packets. - auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, - test_name + "_cfg", InstrumentId::fromIndex(3)); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, test_name, InstrumentId::fromIndex(3)); ASSERT_TRUE(result.isOk()) << result.error(); auto& session = result.value(); @@ -1555,7 +1556,7 @@ TEST_F(CentralCompatProtocolTest, TransmitRoundTrip_CurrentProtocol) { /// @brief Non-compat layout always detects CURRENT protocol TEST_F(CentralCompatProtocolTest, NativeLayout_AlwaysCurrent) { std::string name = test_name; - auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()) << result.error(); EXPECT_EQ(result.value().getCompatProtocolVersion(), CBPROTO_PROTOCOL_CURRENT); } @@ -1563,7 +1564,7 @@ TEST_F(CentralCompatProtocolTest, NativeLayout_AlwaysCurrent) { /// @brief CENTRAL layout always detects CURRENT protocol TEST_F(CentralCompatProtocolTest, CentralLayout_AlwaysCurrent) { std::string name = test_name; - auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::CENTRAL, name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()) << result.error(); EXPECT_EQ(result.value().getCompatProtocolVersion(), CBPROTO_PROTOCOL_CURRENT); } @@ -1577,7 +1578,8 @@ TEST_F(CentralCompatProtocolTest, CentralLayout_AlwaysCurrent) { class OwnerLivenessTest : public ::testing::Test { protected: void SetUp() override { - test_name = "test_liveness_" + std::to_string(test_counter++); + // l = liveness + test_name = "l" + std::to_string(test_counter++); } std::string test_name; @@ -1587,7 +1589,7 @@ class OwnerLivenessTest : public ::testing::Test { int OwnerLivenessTest::test_counter = 0; TEST_F(OwnerLivenessTest, StandaloneWritesOwnerPid) { - auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()) << result.error(); auto* cfg = result.value().getNativeConfigBuffer(); @@ -1600,7 +1602,7 @@ TEST_F(OwnerLivenessTest, StandaloneWritesOwnerPid) { } TEST_F(OwnerLivenessTest, StandaloneAlwaysReturnsTrue) { - auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); + auto result = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(result.isOk()) << result.error(); // isOwnerAlive() is only meaningful for CLIENT — STANDALONE always returns true @@ -1609,11 +1611,11 @@ TEST_F(OwnerLivenessTest, StandaloneAlwaysReturnsTrue) { TEST_F(OwnerLivenessTest, ClientDetectsLiveOwner) { // Create STANDALONE (sets owner_pid to current process) - auto standalone = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); + auto standalone = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(standalone.isOk()) << standalone.error(); // Create CLIENT on same segments - auto client = ShmemSession::create(Mode::CLIENT, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); + auto client = ShmemSession::create(Mode::CLIENT, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(client.isOk()) << client.error(); // Owner (this process) is alive @@ -1622,7 +1624,7 @@ TEST_F(OwnerLivenessTest, ClientDetectsLiveOwner) { TEST_F(OwnerLivenessTest, ClientDetectsDeadOwner) { // Create STANDALONE, then set a fake dead PID - auto standalone = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); + auto standalone = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(standalone.isOk()) << standalone.error(); // Overwrite owner_pid with a PID that (almost certainly) doesn't exist @@ -1631,7 +1633,7 @@ TEST_F(OwnerLivenessTest, ClientDetectsDeadOwner) { cfg->owner_pid = 4000000000u; // Well above any real PID // Create CLIENT on same segments - auto client = ShmemSession::create(Mode::CLIENT, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); + auto client = ShmemSession::create(Mode::CLIENT, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(client.isOk()) << client.error(); // Owner PID doesn't exist — should detect as dead @@ -1640,7 +1642,7 @@ TEST_F(OwnerLivenessTest, ClientDetectsDeadOwner) { TEST_F(OwnerLivenessTest, ClientTreatsZeroPidAsAlive) { // Create STANDALONE, then clear owner_pid to simulate pre-liveness segments - auto standalone = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); + auto standalone = ShmemSession::create(Mode::STANDALONE, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(standalone.isOk()) << standalone.error(); auto* cfg = standalone.value().getNativeConfigBuffer(); @@ -1648,7 +1650,7 @@ TEST_F(OwnerLivenessTest, ClientTreatsZeroPidAsAlive) { cfg->owner_pid = 0; // Create CLIENT on same segments - auto client = ShmemSession::create(Mode::CLIENT, ShmemLayout::NATIVE, test_name + "_cfg", cbproto::InstrumentId::fromOneBased(cbNSP1)); + auto client = ShmemSession::create(Mode::CLIENT, ShmemLayout::NATIVE, test_name, cbproto::InstrumentId::fromOneBased(cbNSP1)); ASSERT_TRUE(client.isOk()) << client.error(); // PID 0 = unknown — assume alive (backward compat) From 1d2cc65f0c4f023be9280104b8c5d4970c4f7982 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Thu, 9 Jul 2026 14:50:25 -0600 Subject: [PATCH 56/62] FIX: channel, group, and filter labels fetched with cbsdk Label strings were previously returned as const char* types. With multi-version-central-compat, the API for fetching certain configuration structs was changed to return copies instead of pointers. This resulted in the getter methods for labels (const char*) pointing to objects allocated on the stack instead of shared memory, so the pointers were left dangling after the getter returned. This fix requires callers of cbsdk to provide an allocated char buffer in order to fetch a label string. --- pycbsdk/src/pycbsdk/_cdef.py | 9 ++-- pycbsdk/src/pycbsdk/session.py | 21 ++++---- src/cbsdk/include/cbsdk/cbsdk.h | 34 +++++++++--- src/cbsdk/src/cbsdk.cpp | 53 +++++++++++++------ tests/integration/test_capi_configuration.cpp | 33 ++++++++---- tests/unit/test_cbsdk_c_api.cpp | 24 ++++++--- 6 files changed, 121 insertions(+), 53 deletions(-) diff --git a/pycbsdk/src/pycbsdk/_cdef.py b/pycbsdk/src/pycbsdk/_cdef.py index fdc44cbd..6994515b 100644 --- a/pycbsdk/src/pycbsdk/_cdef.py +++ b/pycbsdk/src/pycbsdk/_cdef.py @@ -200,10 +200,12 @@ uint32_t cbsdk_get_max_chans(void); uint32_t cbsdk_get_num_fe_chans(void); uint32_t cbsdk_get_num_analog_chans(void); -const char* cbsdk_session_get_channel_label(cbsdk_session_t session, uint32_t chan_id); +uint32_t cbsdk_session_get_channel_label_length(void); +int32_t cbsdk_session_get_channel_label(cbsdk_session_t session, uint32_t chan_id, char* buf, uint32_t buf_size); uint32_t cbsdk_session_get_channel_smpgroup(cbsdk_session_t session, uint32_t chan_id); uint32_t cbsdk_session_get_channel_chancaps(cbsdk_session_t session, uint32_t chan_id); -const char* cbsdk_session_get_group_label(cbsdk_session_t session, uint32_t group_id); +uint32_t cbsdk_session_get_group_label_length(void); +int32_t cbsdk_session_get_group_label(cbsdk_session_t session, uint32_t group_id, char* buf, uint32_t buf_size); cbsdk_result_t cbsdk_session_get_group_list(cbsdk_session_t session, uint32_t group_id, uint16_t* list, uint32_t* count); @@ -297,7 +299,8 @@ // Bulk configuration access uint32_t cbsdk_session_get_sysfreq(cbsdk_session_t session); uint32_t cbsdk_get_num_filters(void); -const char* cbsdk_session_get_filter_label(cbsdk_session_t session, uint32_t filter_id); +uint32_t cbsdk_session_get_filter_label_length(void); +int32_t cbsdk_session_get_filter_label(cbsdk_session_t session, uint32_t filter_id, char* buf, uint32_t buf_size); uint32_t cbsdk_session_get_filter_hpfreq(cbsdk_session_t session, uint32_t filter_id); uint32_t cbsdk_session_get_filter_hporder(cbsdk_session_t session, uint32_t filter_id); uint32_t cbsdk_session_get_filter_lpfreq(cbsdk_session_t session, uint32_t filter_id); diff --git a/pycbsdk/src/pycbsdk/session.py b/pycbsdk/src/pycbsdk/session.py index ece0d22b..4ddaf174 100644 --- a/pycbsdk/src/pycbsdk/session.py +++ b/pycbsdk/src/pycbsdk/session.py @@ -718,10 +718,11 @@ def num_analog_chans() -> int: def get_channel_label(self, chan_id: int) -> Optional[str]: """Get a channel's label (1-based channel ID).""" _lib = _get_lib() - ptr = _lib.cbsdk_session_get_channel_label(self._session, chan_id) - if ptr == ffi.NULL: + buf_len = _lib.cbsdk_session_get_channel_label_length() + buf = ffi.new(f"char[{buf_len}]") + if _lib.cbsdk_session_get_channel_label(self._session, chan_id, buf, buf_len) < 0: return None - return ffi.string(ptr).decode() + return ffi.string(buf).decode() def get_channel_smpgroup(self, chan_id: int) -> int: """Get a channel's sample group (0 = disabled, 1-6).""" @@ -825,10 +826,11 @@ def get_channel_field(self, chan_id: int, field: ChanInfoField) -> int: def get_group_label(self, group_id: int) -> Optional[str]: """Get a sample group's label (group_id 1-6).""" _lib = _get_lib() - ptr = _lib.cbsdk_session_get_group_label(self._session, group_id) - if ptr == ffi.NULL: + buf_len = _lib.cbsdk_session_get_group_label_length() + buf = ffi.new(f"char[{buf_len}]") + if _lib.cbsdk_session_get_group_label(self._session, group_id, buf, buf_len) < 0: return None - return ffi.string(ptr).decode() + return ffi.string(buf).decode() def get_group_channels(self, group_id: int) -> list[int]: """Get the list of channel IDs in a sample group.""" @@ -1928,11 +1930,12 @@ def get_filter_info(self, filter_id: int) -> Optional[dict]: ``lporder``. Frequencies are in milliHertz. Returns None if invalid. """ _lib = _get_lib() - ptr = _lib.cbsdk_session_get_filter_label(self._session, filter_id) - if ptr == ffi.NULL: + buf_len = _lib.cbsdk_session_get_filter_label_length() + buf = ffi.new(f"char[{buf_len}]") + if _lib.cbsdk_session_get_filter_label(self._session, filter_id, buf, buf_len) < 0: return None return { - "label": ffi.string(ptr).decode(), + "label": ffi.string(buf).decode(), "hpfreq": _lib.cbsdk_session_get_filter_hpfreq(self._session, filter_id), "hporder": _lib.cbsdk_session_get_filter_hporder(self._session, filter_id), "lpfreq": _lib.cbsdk_session_get_filter_lpfreq(self._session, filter_id), diff --git a/src/cbsdk/include/cbsdk/cbsdk.h b/src/cbsdk/include/cbsdk/cbsdk.h index 96673608..499b818a 100644 --- a/src/cbsdk/include/cbsdk/cbsdk.h +++ b/src/cbsdk/include/cbsdk/cbsdk.h @@ -442,12 +442,18 @@ CBSDK_API uint32_t cbsdk_get_num_fe_chans(void); /// @return cbNUM_ANALOG_CHANS (compile-time constant) CBSDK_API uint32_t cbsdk_get_num_analog_chans(void); +/// Get the buffer size required to store a channel label. +/// @return cbLEN_STR_LABEL + 1 (label field width plus the null terminator) +CBSDK_API uint32_t cbsdk_session_get_channel_label_length(void); + /// Get a channel's label /// @param session Session handle (must not be NULL) /// @param chan_id 1-based channel ID (1 to cbMAXCHANS) -/// @return Pointer to null-terminated label string, or NULL if invalid. -/// Pointer is valid for the lifetime of the session. -CBSDK_API const char* cbsdk_session_get_channel_label(cbsdk_session_t session, uint32_t chan_id); +/// @param buf Output buffer for the label string (null-terminated on success) +/// @param buf_size Size of the output buffer in bytes +/// @return Number of bytes written (excluding null terminator), or -1 if unavailable +CBSDK_API int32_t cbsdk_session_get_channel_label( + cbsdk_session_t session, uint32_t chan_id, char* buf, uint32_t buf_size); /// Get a channel's sample group assignment /// @param session Session handle (must not be NULL) @@ -539,11 +545,18 @@ CBSDK_API int64_t cbsdk_session_get_channel_field( uint32_t chan_id, cbsdk_chaninfo_field_t field); +/// Get the buffer size required to store a group label. +/// @return cbLEN_STR_LABEL + 1 (label field width plus the null terminator) +CBSDK_API uint32_t cbsdk_session_get_group_label_length(void); + /// Get a sample group's label /// @param session Session handle (must not be NULL) /// @param group_id Group ID (1-6) -/// @return Pointer to null-terminated label string, or NULL if invalid -CBSDK_API const char* cbsdk_session_get_group_label(cbsdk_session_t session, uint32_t group_id); +/// @param buf Output buffer for the label string (null-terminated on success) +/// @param buf_size Size of the output buffer in bytes +/// @return Number of bytes written (excluding null terminator), or -1 if unavailable +CBSDK_API int32_t cbsdk_session_get_group_label( + cbsdk_session_t session, uint32_t group_id, char* buf, uint32_t buf_size); /// Get the list of channels in a sample group /// @param session Session handle (must not be NULL) @@ -819,11 +832,18 @@ CBSDK_API uint32_t cbsdk_session_get_sysfreq(cbsdk_session_t session); /// @return cbMAXFILTS (compile-time constant) CBSDK_API uint32_t cbsdk_get_num_filters(void); +/// Get the buffer size required to store a filter label. +/// @return cbLEN_STR_FILT_LABEL + 1 (label field width plus the null terminator) +CBSDK_API uint32_t cbsdk_session_get_filter_label_length(void); + /// Get a filter's label /// @param session Session handle (must not be NULL) /// @param filter_id Filter ID (0 to cbMAXFILTS-1) -/// @return Pointer to label string, or NULL if invalid -CBSDK_API const char* cbsdk_session_get_filter_label(cbsdk_session_t session, uint32_t filter_id); +/// @param buf Output buffer for the label string (null-terminated on success) +/// @param buf_size Size of the output buffer in bytes +/// @return Number of bytes written (excluding null terminator), or -1 if unavailable +CBSDK_API int32_t cbsdk_session_get_filter_label( + cbsdk_session_t session, uint32_t filter_id, char* buf, uint32_t buf_size); /// Get a filter's high-pass corner frequency /// @param session Session handle (must not be NULL) diff --git a/src/cbsdk/src/cbsdk.cpp b/src/cbsdk/src/cbsdk.cpp index dc93f375..b8bad9a3 100644 --- a/src/cbsdk/src/cbsdk.cpp +++ b/src/cbsdk/src/cbsdk.cpp @@ -16,6 +16,7 @@ #include "cbsdk/sdk_session.h" #include #include +#include #include #include #include @@ -694,15 +695,21 @@ uint32_t cbsdk_get_num_analog_chans(void) { return cbNUM_ANALOG_CHANS; } -const char* cbsdk_session_get_channel_label(cbsdk_session_t session, uint32_t chan_id) { - if (!session || !session->cpp_session) { - return nullptr; - } +uint32_t cbsdk_session_get_channel_label_length(void) { + return cbLEN_STR_LABEL + 1; // + null terminator +} + +int32_t cbsdk_session_get_channel_label( + cbsdk_session_t session, uint32_t chan_id, char* buf, uint32_t buf_size) { + if (!session || !session->cpp_session || !buf || buf_size == 0) return -1; try { auto info = session->cpp_session->getChanInfo(chan_id); - return info.isOk() ? info.value().label : nullptr; + if (info.isError()) return -1; + auto written = std::snprintf(buf, buf_size, "%.*s", static_cast(std::size(info.value().label)), info.value().label); + if (written < 0) return -1; + return written < buf_size ? written : buf_size - 1; // clamp if truncated } catch (...) { - return nullptr; + return -1; } } @@ -872,15 +879,21 @@ int64_t cbsdk_session_get_channel_field( } catch (...) { return 0; } } -const char* cbsdk_session_get_group_label(cbsdk_session_t session, uint32_t group_id) { - if (!session || !session->cpp_session) { - return nullptr; - } +uint32_t cbsdk_session_get_group_label_length(void) { + return cbLEN_STR_LABEL + 1; // + null terminator +} + +int32_t cbsdk_session_get_group_label( + cbsdk_session_t session, uint32_t group_id, char* buf, uint32_t buf_size) { + if (!session || !session->cpp_session || !buf || buf_size == 0) return -1; try { auto info = session->cpp_session->getGroupInfo(group_id); - return info.isOk() ? info.value().label : nullptr; + if (info.isError()) return -1; + auto written = std::snprintf(buf, buf_size, "%.*s", static_cast(std::size(info.value().label)), info.value().label); + if (written < 0) return -1; + return written < buf_size ? written : buf_size - 1; // clamp if truncated } catch (...) { - return nullptr; + return -1; } } @@ -1236,12 +1249,20 @@ uint32_t cbsdk_get_num_filters(void) { return cbMAXFILTS; } -const char* cbsdk_session_get_filter_label(cbsdk_session_t session, uint32_t filter_id) { - if (!session || !session->cpp_session) return nullptr; +uint32_t cbsdk_session_get_filter_label_length(void) { + return cbLEN_STR_FILT_LABEL + 1; // + null terminator +} + +int32_t cbsdk_session_get_filter_label( + cbsdk_session_t session, uint32_t filter_id, char* buf, uint32_t buf_size) { + if (!session || !session->cpp_session || !buf || buf_size == 0) return -1; try { auto info = session->cpp_session->getFilterInfo(filter_id); - return info.isOk() ? info.value().label : nullptr; - } catch (...) { return nullptr; } + if (info.isError()) return -1; + auto written = std::snprintf(buf, buf_size, "%.*s", static_cast(std::size(info.value().label)), info.value().label); + if (written < 0) return -1; + return written < buf_size ? written : buf_size - 1; // clamp if truncated + } catch (...) { return -1; } } uint32_t cbsdk_session_get_filter_hpfreq(cbsdk_session_t session, uint32_t filter_id) { diff --git a/tests/integration/test_capi_configuration.cpp b/tests/integration/test_capi_configuration.cpp index d835ef66..8f2164b1 100644 --- a/tests/integration/test_capi_configuration.cpp +++ b/tests/integration/test_capi_configuration.cpp @@ -177,9 +177,10 @@ TEST_F(CApiChannelInfoTest, GetChannelLabel) { SessionGuard sg; ASSERT_TRUE(sg.create()); - const char* label = cbsdk_session_get_channel_label(sg.session, 1); - EXPECT_NE(label, nullptr); - EXPECT_GT(strlen(label), 0u); + std::vector label(cbsdk_session_get_channel_label_length()); + int32_t len = cbsdk_session_get_channel_label(sg.session, 1, label.data(), label.size()); + EXPECT_GT(len, 0); + EXPECT_EQ(strlen(label.data()), static_cast(len)); } TEST_F(CApiChannelInfoTest, GetChannelType) { @@ -242,8 +243,17 @@ TEST_F(CApiChannelInfoTest, GetGroupLabel) { SessionGuard sg; ASSERT_TRUE(sg.create()); - const char* label = cbsdk_session_get_group_label(sg.session, CBPROTO_GROUP_RATE_30000Hz); - EXPECT_NE(label, nullptr); + std::vector label(cbsdk_session_get_group_label_length()); + int32_t len = cbsdk_session_get_group_label(sg.session, CBPROTO_GROUP_RATE_30000Hz, + label.data(), label.size()); + // The label may be empty or unavailable (nPlayServer need not send GROUPREP), + // so -1 (failure) and 0 (empty) are both acceptable. But the return value must + // always be a valid contract value, and on success it must match the buffer. + EXPECT_GE(len, -1); + EXPECT_LT(len, static_cast(label.size())); + if (len >= 0) { + EXPECT_EQ(strlen(label.data()), static_cast(len)); + } } TEST_F(CApiChannelInfoTest, GetChannelField) { @@ -332,9 +342,9 @@ TEST_F(CApiPerChannelTest, SetChannelLabel) { CBSDK_RESULT_SUCCESS); EXPECT_EQ(cbsdk_session_sync(sg.session, 5000), CBSDK_RESULT_SUCCESS); - const char* label = cbsdk_session_get_channel_label(sg.session, 1); - ASSERT_NE(label, nullptr); - EXPECT_STREQ(label, "TestCh"); + std::vector label(cbsdk_session_get_channel_label_length()); + cbsdk_session_get_channel_label(sg.session, 1, label.data(), label.size()); + EXPECT_STREQ(label.data(), "TestCh"); } TEST_F(CApiPerChannelTest, SetChannelSmpfilter) { @@ -374,14 +384,17 @@ TEST_F(CApiFilterTest, GetFilterLabel) { ASSERT_TRUE(sg.create()); // Filter 0 — may or may not have a label, but should not crash - cbsdk_session_get_filter_label(sg.session, 0); + std::vector label(cbsdk_session_get_filter_label_length()); + cbsdk_session_get_filter_label(sg.session, 0, label.data(), label.size()); } TEST_F(CApiFilterTest, GetFilterLabelInvalid) { SessionGuard sg; ASSERT_TRUE(sg.create()); - EXPECT_EQ(cbsdk_session_get_filter_label(sg.session, 9999), nullptr); + // Invalid filter id reports failure via a negative return; buffer contents are undefined. + std::vector label(cbsdk_session_get_filter_label_length()); + EXPECT_LT(cbsdk_session_get_filter_label(sg.session, 9999, label.data(), label.size()), 0); } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/tests/unit/test_cbsdk_c_api.cpp b/tests/unit/test_cbsdk_c_api.cpp index 729e46a3..dfda9e17 100644 --- a/tests/unit/test_cbsdk_c_api.cpp +++ b/tests/unit/test_cbsdk_c_api.cpp @@ -12,6 +12,7 @@ #include #include "cbsdk/cbsdk.h" #include +#include /// Test fixture for C API tests class CbsdkCApiTest : public ::testing::Test { @@ -339,7 +340,8 @@ TEST_F(CbsdkCApiTest, GetRunlevel_NullSession) { } TEST_F(CbsdkCApiTest, GetChannelLabel_NullSession) { - EXPECT_EQ(cbsdk_session_get_channel_label(nullptr, 1), nullptr); + std::vector buf(cbsdk_session_get_channel_label_length()); + EXPECT_LT(cbsdk_session_get_channel_label(nullptr, 1, buf.data(), buf.size()), 0); } TEST_F(CbsdkCApiTest, GetChannelSmpgroup_NullSession) { @@ -351,7 +353,8 @@ TEST_F(CbsdkCApiTest, GetChannelChancaps_NullSession) { } TEST_F(CbsdkCApiTest, GetGroupLabel_NullSession) { - EXPECT_EQ(cbsdk_session_get_group_label(nullptr, 1), nullptr); + std::vector buf(cbsdk_session_get_group_label_length()); + EXPECT_LT(cbsdk_session_get_group_label(nullptr, 1, buf.data(), buf.size()), 0); } TEST_F(CbsdkCApiTest, GetConstants) { @@ -359,6 +362,10 @@ TEST_F(CbsdkCApiTest, GetConstants) { EXPECT_GT(cbsdk_get_num_fe_chans(), 0); EXPECT_GT(cbsdk_get_num_analog_chans(), 0); EXPECT_GE(cbsdk_get_max_chans(), cbsdk_get_num_analog_chans()); + // Label buffer sizes: at least one char + null terminator. + EXPECT_GT(cbsdk_session_get_channel_label_length(), 1u); + EXPECT_GT(cbsdk_session_get_group_label_length(), 1u); + EXPECT_GT(cbsdk_session_get_filter_label_length(), 1u); } TEST_F(CbsdkCApiTest, ConfigAccess_WithSession) { @@ -367,14 +374,15 @@ TEST_F(CbsdkCApiTest, ConfigAccess_WithSession) { cbsdk_session_t session = nullptr; ASSERT_EQ(cbsdk_session_create(&session, &config), CBSDK_RESULT_SUCCESS); - // These may return NULL/0 without a device, but must not crash - cbsdk_session_get_channel_label(session, 1); - cbsdk_session_get_channel_label(session, 0); // Invalid channel - cbsdk_session_get_channel_label(session, 99999); // Out of range + // These may return a negative value without a device, but must not crash + std::vector buf(cbsdk_session_get_channel_label_length()); + cbsdk_session_get_channel_label(session, 1, buf.data(), buf.size()); + cbsdk_session_get_channel_label(session, 0, buf.data(), buf.size()); // Invalid channel + cbsdk_session_get_channel_label(session, 99999, buf.data(), buf.size()); // Out of range cbsdk_session_get_channel_smpgroup(session, 1); cbsdk_session_get_channel_chancaps(session, 1); - cbsdk_session_get_group_label(session, 1); - cbsdk_session_get_group_label(session, 0); // Invalid group + cbsdk_session_get_group_label(session, 1, buf.data(), buf.size()); + cbsdk_session_get_group_label(session, 0, buf.data(), buf.size()); // Invalid group cbsdk_session_get_runlevel(session); cbsdk_session_destroy(session); From ad57321f865a59d07babd42e661fd65a7085f82e Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Thu, 9 Jul 2026 15:46:04 -0600 Subject: [PATCH 57/62] FIX: Formatting in pycbsdk/session.py --- pycbsdk/src/pycbsdk/session.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/pycbsdk/src/pycbsdk/session.py b/pycbsdk/src/pycbsdk/session.py index 4ddaf174..208e67b8 100644 --- a/pycbsdk/src/pycbsdk/session.py +++ b/pycbsdk/src/pycbsdk/session.py @@ -720,7 +720,10 @@ def get_channel_label(self, chan_id: int) -> Optional[str]: _lib = _get_lib() buf_len = _lib.cbsdk_session_get_channel_label_length() buf = ffi.new(f"char[{buf_len}]") - if _lib.cbsdk_session_get_channel_label(self._session, chan_id, buf, buf_len) < 0: + written = _lib.cbsdk_session_get_channel_label( + self._session, chan_id, buf, buf_len + ) + if written < 0: return None return ffi.string(buf).decode() @@ -828,7 +831,10 @@ def get_group_label(self, group_id: int) -> Optional[str]: _lib = _get_lib() buf_len = _lib.cbsdk_session_get_group_label_length() buf = ffi.new(f"char[{buf_len}]") - if _lib.cbsdk_session_get_group_label(self._session, group_id, buf, buf_len) < 0: + written = _lib.cbsdk_session_get_group_label( + self._session, group_id, buf, buf_len + ) + if written < 0: return None return ffi.string(buf).decode() @@ -1932,7 +1938,10 @@ def get_filter_info(self, filter_id: int) -> Optional[dict]: _lib = _get_lib() buf_len = _lib.cbsdk_session_get_filter_label_length() buf = ffi.new(f"char[{buf_len}]") - if _lib.cbsdk_session_get_filter_label(self._session, filter_id, buf, buf_len) < 0: + written = _lib.cbsdk_session_get_filter_label( + self._session, filter_id, buf, buf_len + ) + if written < 0: return None return { "label": ffi.string(buf).decode(), From f35872ae5671d8dfc4eac87794476e9948bd5f58 Mon Sep 17 00:00:00 2001 From: Caden Shmookler Date: Fri, 10 Jul 2026 10:59:50 -0600 Subject: [PATCH 58/62] FIX: Populate missing cbPcStatus fields for v7.0 Fields m_nNspStatus, m_nNumNTrodesPerInstrument, and m_nGeminiSystem are now calculated according to Central's 7.0.6 source. Versions 7.0, 7.5, 7.6, 7.7, and 7.8 have been tested with Central+NPLAY. Versions 7.6, 7.7, and 7.8 have been tested with Central+LEGACY_NSP, Central+NSP or Central+Hub1. --- src/cbshm/src/central_adapters/v7_0.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/cbshm/src/central_adapters/v7_0.cpp b/src/cbshm/src/central_adapters/v7_0.cpp index 0b684153..10ed3569 100644 --- a/src/cbshm/src/central_adapters/v7_0.cpp +++ b/src/cbshm/src/central_adapters/v7_0.cpp @@ -461,9 +461,17 @@ void Adapter::fromLegacy(NativePCStatus& cur, const cbPcStatus& leg) const { cur.m_nNumSerialChans = leg.m_nNumSerialChans; cur.m_nNumDigoutChans = leg.m_nNumDigoutChans; cur.m_nNumTotalChans = leg.m_nNumTotalChans; - cur.m_nNspStatus = NativeNSPStatus::NSP_FOUND; // TODO: VERIFY - cur.m_nNumNTrodesPerInstrument = cbMAXNTRODES; // TODO: VERIFY - cur.m_nGeminiSystem = 1; // TODO: VERIFY + // Central considers the NSP "found" once the corresponding sysinfo packet is received. + cur.m_nNspStatus = cfg->sysinfo.cbpkt_header.chid == 0 + ? NativeNSPStatus::NSP_INIT + : NativeNSPStatus::NSP_FOUND; + cur.m_nNumNTrodesPerInstrument = 0; + for (uint32_t n = 0; n < cbMAXNTRODES; ++n) { + // Central considers an N-Trode slot valid when its packet header chid is non-zero. + if (cfg->isNTrodeInfo[n].cbpkt_header.chid != 0) + ++cur.m_nNumNTrodesPerInstrument; + } + cur.m_nGeminiSystem = 0; // 7.0.x predates Gemini hardware. } void Adapter::fromLegacy(NativeReceiveBuffer& cur, const cbRECBUFF& leg) const { From 49044ceefe9e0dba7a6246a4c35daf0292944e58 Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Fri, 10 Jul 2026 17:41:50 -0400 Subject: [PATCH 59/62] Remove duplicate line --- src/cbshm/src/central_adapters/v7_0.cpp | 1 - src/cbshm/src/central_adapters/v7_5.cpp | 1 - src/cbshm/src/central_adapters/v7_6.cpp | 1 - src/cbshm/src/central_adapters/v7_7.cpp | 1 - src/cbshm/src/central_adapters/v7_8.cpp | 1 - 5 files changed, 5 deletions(-) diff --git a/src/cbshm/src/central_adapters/v7_0.cpp b/src/cbshm/src/central_adapters/v7_0.cpp index 10ed3569..5d9ba526 100644 --- a/src/cbshm/src/central_adapters/v7_0.cpp +++ b/src/cbshm/src/central_adapters/v7_0.cpp @@ -546,7 +546,6 @@ void Adapter::toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const { toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.idcode = cur.idcode; - leg.idcode = cur.idcode; copyArr(leg.ident, cur.ident); leg.chanbase = cur.chanbase; leg.chancount = cur.chancount; diff --git a/src/cbshm/src/central_adapters/v7_5.cpp b/src/cbshm/src/central_adapters/v7_5.cpp index a675009c..ee7a3be8 100644 --- a/src/cbshm/src/central_adapters/v7_5.cpp +++ b/src/cbshm/src/central_adapters/v7_5.cpp @@ -539,7 +539,6 @@ void Adapter::toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const { toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.idcode = cur.idcode; - leg.idcode = cur.idcode; copyArr(leg.ident, cur.ident); leg.chanbase = cur.chanbase; leg.chancount = cur.chancount; diff --git a/src/cbshm/src/central_adapters/v7_6.cpp b/src/cbshm/src/central_adapters/v7_6.cpp index 2f2741d9..e96a24cc 100644 --- a/src/cbshm/src/central_adapters/v7_6.cpp +++ b/src/cbshm/src/central_adapters/v7_6.cpp @@ -539,7 +539,6 @@ void Adapter::toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const { toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.idcode = cur.idcode; - leg.idcode = cur.idcode; copyArr(leg.ident, cur.ident); leg.chanbase = cur.chanbase; leg.chancount = cur.chancount; diff --git a/src/cbshm/src/central_adapters/v7_7.cpp b/src/cbshm/src/central_adapters/v7_7.cpp index c334c978..29c3696f 100644 --- a/src/cbshm/src/central_adapters/v7_7.cpp +++ b/src/cbshm/src/central_adapters/v7_7.cpp @@ -540,7 +540,6 @@ void Adapter::toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const { toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.idcode = cur.idcode; - leg.idcode = cur.idcode; copyArr(leg.ident, cur.ident); leg.chanbase = cur.chanbase; leg.chancount = cur.chancount; diff --git a/src/cbshm/src/central_adapters/v7_8.cpp b/src/cbshm/src/central_adapters/v7_8.cpp index 77d86567..571045e7 100644 --- a/src/cbshm/src/central_adapters/v7_8.cpp +++ b/src/cbshm/src/central_adapters/v7_8.cpp @@ -540,7 +540,6 @@ void Adapter::toLegacy(cbPKT_PROCINFO& leg, const ::cbPKT_PROCINFO& cur) const { toLegacy(leg.cbpkt_header, cur.cbpkt_header); leg.proc = cur.proc; leg.idcode = cur.idcode; - leg.idcode = cur.idcode; copyArr(leg.ident, cur.ident); leg.chanbase = cur.chanbase; leg.chancount = cur.chancount; From 3f650fbef1bb7347a7ef0ee02d974dcf474fbeea Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Fri, 10 Jul 2026 17:42:34 -0400 Subject: [PATCH 60/62] Fix error message --- src/cbshm/src/central_adapters/v7_0.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cbshm/src/central_adapters/v7_0.cpp b/src/cbshm/src/central_adapters/v7_0.cpp index 5d9ba526..d6255cf5 100644 --- a/src/cbshm/src/central_adapters/v7_0.cpp +++ b/src/cbshm/src/central_adapters/v7_0.cpp @@ -1112,11 +1112,11 @@ cbutil::Result Adapter::setGroupInfo(uint32_t group_idx, const ::cbPKT_GRO } cbutil::Result Adapter::setNspStatus(const NativeNSPStatus& status) const { - return cbutil::Result::error("Central v3.11 does not have fields for NSP status"); + return cbutil::Result::error("Central v7.0 (protocol 3.11) does not have fields for NSP status"); } cbutil::Result Adapter::setGeminiSystem(bool is_gemini) const { - return cbutil::Result::error("Central v3.11 does not recognize Gemini systems"); + return cbutil::Result::error("Central v7.0 (protocol 3.11) does not recognize Gemini systems"); } } // namespace central_v7_0 From 716274fc845c73d6bc6b52a9260c933b06ed7099 Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Fri, 10 Jul 2026 18:03:47 -0400 Subject: [PATCH 61/62] FIX: CLIENT reader fails safe on rec-buffer overrun instead of emitting garbage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rec ring publishes head_index and head_wrap as two separate words, and on a wrap the producer bumps head_wrap before republishing head_index. No ordering of two independent stores keeps the combined position (wrap*buflen + index) monotonic across a wrap, so the CLIENT reader could observe a torn pair (old index + new wrap). That corrupted the overrun check, dropped tail off a packet boundary, and the bad-size path then byte-scanned through garbage, delivering misinterpreted bytes to user callbacks — the intermittent "malformed packets after a buffer wrap" failure seen on Windows under load. Make the reader fail safe: - Read (head_index, head_wrap) as a seqlock-style snapshot to shrink (but not fully close) the torn-pair window. - On overrun, an implausible packet size, or a header that cannot belong to a real packet (type high byte set, or chid outside a channel / config range), resync tail to the current head and report data loss, instead of advancing by a garbage size and scanning more garbage. Because the two-word update is fundamentally non-atomic (and the Central- compatible layout forbids merging the fields), validation is the real safety net: torn snapshots and genuine overruns now drop data cleanly and never reach user callbacks. Verified against nPlayServer 7.8.0 (CLIENT data-reception integration tests pass); no change on the normal path. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/cbshm/src/shmem_session.cpp | 71 ++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/src/cbshm/src/shmem_session.cpp b/src/cbshm/src/shmem_session.cpp index 7e45ebca..7f8b5fc2 100644 --- a/src/cbshm/src/shmem_session.cpp +++ b/src/cbshm/src/shmem_session.cpp @@ -1767,12 +1767,42 @@ Result ShmemSession::readReceiveBuffer(cbPKT_GENERIC* packets, size_t max_ uint32_t* buf = m_impl->adapter->getRecBufferPtr(); uint32_t buflen = m_impl->rec_buffer_len; - // Acquire-load: pairs with the producer's release-store of head_index in - // writeToReceiveBuffer. Without this, on weak memory architectures - // (ARM/Apple Silicon) we can observe an advanced head_index but stale or - // partial packet bytes, leading to misaligned reads of the ring buffer. - uint32_t head_index = shm_load_acquire_u32(&m_impl->adapter->getRecHeadindexPtr()); - uint32_t head_wrap = shm_load_relaxed_u32(&m_impl->adapter->getRecHeadwrapPtr()); + // Read a (head_index, head_wrap) snapshot. + // + // The producer publishes these as two separate words and, on a wrap, bumps + // head_wrap *before* republishing head_index (see writeToReceiveBuffer). + // There is no ordering of two independent stores that keeps the combined + // position (head_wrap * buflen + head_index) monotonic across a wrap, so a + // naive read can observe a torn pair (e.g. the old index with the new wrap), + // which corrupts the overrun math and drops tail off a packet boundary. + // + // The acquire-load on head_index also pairs with the producer's + // release-store, so on weak memory architectures (ARM/Apple Silicon) we + // don't observe an advanced index with stale packet bytes. The seqlock- + // style retry shrinks the torn-pair window; because it cannot close it + // entirely, the loop below additionally validates every packet and resyncs + // to head on any anomaly instead of trusting the pair (see resyncToHead). + auto loadHeadSnapshot = [&](uint32_t& idx_out, uint32_t& wrap_out) { + for (;;) { + uint32_t i1 = shm_load_acquire_u32(&m_impl->adapter->getRecHeadindexPtr()); + uint32_t w = shm_load_acquire_u32(&m_impl->adapter->getRecHeadwrapPtr()); + uint32_t i2 = shm_load_acquire_u32(&m_impl->adapter->getRecHeadindexPtr()); + if (i1 == i2) { idx_out = i1; wrap_out = w; return; } + } + }; + + // Fail-safe recovery: our tail no longer points at a packet boundary + // (the producer lapped us, or we observed a torn head snapshot across a + // wrap). Jump tail to the current head and report the loss, rather than + // advancing by a garbage size and delivering misinterpreted bytes to user + // callbacks. + auto resyncToHead = [&](const char* msg) -> Result { + loadHeadSnapshot(m_impl->rec_tailindex, m_impl->rec_tailwrap); + return Result::error(msg); + }; + + uint32_t head_index, head_wrap; + loadHeadSnapshot(head_index, head_wrap); if (m_impl->rec_tailwrap == head_wrap && m_impl->rec_tailindex == head_index) { return Result::ok(); @@ -1809,9 +1839,7 @@ Result ShmemSession::readReceiveBuffer(cbPKT_GENERIC* packets, size_t max_ if ((m_impl->rec_tailwrap + 1 == head_wrap && m_impl->rec_tailindex < head_index) || (m_impl->rec_tailwrap + 1 < head_wrap)) { - m_impl->rec_tailindex = head_index; - m_impl->rec_tailwrap = head_wrap; - return Result::error("Receive buffer overrun - data lost"); + return resyncToHead("Receive buffer overrun - data lost"); } // Parse the packet header to determine packet size based on protocol version. @@ -1851,12 +1879,9 @@ Result ShmemSession::readReceiveBuffer(cbPKT_GENERIC* packets, size_t max_ uint32_t pkt_size_dwords = raw_header_32size + raw_dlen; if (pkt_size_dwords == 0 || pkt_size_dwords > (sizeof(cbPKT_GENERIC) / sizeof(uint32_t))) { - m_impl->rec_tailindex++; - if (m_impl->rec_tailindex >= buflen) { - m_impl->rec_tailindex = 0; - m_impl->rec_tailwrap++; - } - continue; + // Implausible size => tail is off a packet boundary. Fail safe + // rather than byte-scanning through garbage. + return resyncToHead("Receive buffer desync - data lost"); } if (needs_translation) { @@ -1936,6 +1961,22 @@ Result ShmemSession::readReceiveBuffer(cbPKT_GENERIC* packets, size_t max_ packets[packets_read].cbpkt_header.time * ts_num / ts_den; } + // Fail-safe validation: a header that can't belong to a real packet + // means tail drifted off a packet boundary (producer lapped us, or a + // torn head snapshot across a wrap). Real packets have the high byte of + // `type` clear, and chid is a channel (0 group sample, up to 0x0FFF) or + // the configuration channel (0x8000). Resync to head and drop instead + // of advancing by a garbage size and scanning more garbage into the + // user callbacks. + { + const uint16_t vchid = packets[packets_read].cbpkt_header.chid; + const uint16_t vtype = packets[packets_read].cbpkt_header.type; + if ((vtype & 0xFF00) != 0 || + (vchid > 0x0FFF && vchid != cbPKTCHAN_CONFIGURATION)) { + return resyncToHead("Receive buffer desync - data lost"); + } + } + // Advance tail past this packet (consumed from ring buffer regardless of filter) m_impl->rec_tailindex += pkt_size_dwords; if (m_impl->rec_tailindex >= buflen) { From 22685bc57f403c25a9a19259d3f2893a1a8eff0e Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Fri, 10 Jul 2026 21:57:58 -0400 Subject: [PATCH 62/62] FIX: virtual dtor for CentralBootstrapAdapterBase; drop bogus const on copyArr2D CentralBootstrapAdapterBase is held and deleted through a std::unique_ptr but had no virtual destructor, so deleting a derived BootstrapAdapter through the base pointer was undefined behavior (-Wdelete-abstract-non-virtual-dtor). Give it a virtual default destructor, matching CentralAdapterBase. Also drop the meaningless `const` on the `void` return type of the templated copyArr2D overload (-Wignored-qualifiers). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/cbshm/include/cbshm/central_adapters/base.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cbshm/include/cbshm/central_adapters/base.h b/src/cbshm/include/cbshm/central_adapters/base.h index 02ce0ff8..64465902 100644 --- a/src/cbshm/include/cbshm/central_adapters/base.h +++ b/src/cbshm/include/cbshm/central_adapters/base.h @@ -25,6 +25,8 @@ namespace cbshm { /// class CentralBootstrapAdapterBase { public: + virtual ~CentralBootstrapAdapterBase() = default; + // Buffer sizes virtual size_t getConfigBufferSize() const = 0; virtual size_t getReceiveBufferSize() const = 0; @@ -89,7 +91,7 @@ class CentralAdapterBase { } template - static const void copyArr2D(LHS_T(&lhs)[lhs_ny][lhs_nx], const RHS_T(&rhs)[rhs_ny][rhs_nx], const A* adapter, void(A::*translation_func)(LHS_T&, const RHS_T&) const) { + static void copyArr2D(LHS_T(&lhs)[lhs_ny][lhs_nx], const RHS_T(&rhs)[rhs_ny][rhs_nx], const A* adapter, void(A::*translation_func)(LHS_T&, const RHS_T&) const) { if (lhs_ny <= rhs_ny) { for (size_t i = 0; i < lhs_ny; ++i) { copyArr(lhs[i], rhs[i], adapter, translation_func);