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/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. - - - +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 @@ - - - -cbSdkOpencbSdkOpeninstantiate app;app.SdkOpeninstantiate a...No?UDPNo?...Yes?CentralYes?...SharedMutexExists?Shared...OpenOpenRegister `this`IntNetworkEventCallbackRegister `this`...Register `this`ProcessIncomingPacketdelegateRegister `this`...SdkApp : InstNetwork < QThread, InstNetwork:ListenerSdkApp : InstNetwork < QThread, InstNetwo...QAppPriv::pAppQCoreApplicationQAppPriv::pApp...start(highPriority)start(highPriority)wait(connect mutex);wait(connect mut...return error codereturn error codeInstNetwork::runInstNetwork::runNET_EVENTINITNET_EVENT...cbOpencbOpenYesYesstandalone?standalone?OpenCentral'sbuffersOpen...NoNoCreatesharedbuffersCreate...NET_EVENTNETSTANDALONENET_EVENT...NET_EVENTNETCLIENTNET_EVENT...Instrument.Reset()(clear cache)Instrument...InstrumentOpen()(open UDP)Instrument...startTimer(10)startTimer(10)exec()(wait for quit();)exec()...while!m_bDonewhile...cbWaitForData();cbWaitForData();OnWaitEvent();OnWaitEvent();Monitor semaphore in shared bufferMonitor semaphor...cbCheckForDatacbCheckForDataProcessIncomingPacketProcess...handle config packetshandle config pa...listener->ProcessIncomingPacketlistener->...NET_EVENTCLOSENET_EVENT...InstrumentCloseInstrument...cbClosecbCloseInstNetwork::timerEventInstNetwork::timerEventyesyesnonom_bDone?m_bDone?killTimer()QThread::quit()killTimer()...continue handshakecontinue handsha...yesyesfirst 5 secs?first 5 secs?InstrumentTick()Instrument...InstrumentRecv()Instrument...ProcessIncomingPacketProcess...InstrumentSend()Instrument...process packet cacheprocess packet c...cbSdkClosecbSdkCloseDeallocate Trial constructsDeallocate Trial con...NULL callbacksNULL callbacksm_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 @@ - - - -cbSdkClosecbSdkCloseDeallocate Trial constructsDeallocate Trial con...NULL callbacksNULL callbacksm_bDone = true;m_bDone = true;cbSdkOpencbSdkOpeninstantiate app;app.SdkOpeninstantiate a...No?ConType UDPNo?...Yes?conType CentralYes?...SdkAppOpenSdkApp...Register `this`IntNetworkEventCallbackRegister `this`...Register `this`ProcessIncomingPacketdelegateRegister `this`...SdkApp : InstNetwork, InstNetwork:ListenerSdkApp : InstNetwork, InstNetwork...return error codereturn error codeSharedMutexExists?Shared...NET_EVENTINITNET_EVENT...cbOpencbOpenyesyesstandalone?standalone?wait for device_iomutexwait for device_i...std::thread device_iostd::thread device_ioCreatesharedbuffersCreate...Instrument.Reset()(clear cache)Instrument...InstrumentOpen()(open UDP)Instrument...m_bDone?m_bDone?first 5 secs?first 5 secs?nonoInstrumentRecv()Instrument...InstrumentSend()Instrument...continue handshakecontinue handsha...if no datasleep(1 ms)if no data...cleanupthreadcleanup...bufferbufferbufferbufferstd::thread buffer_iostd::thread buffer_ioOpensharedbuffersOpen...NET_EVENTCLOSENET_EVENT...InstrumentCloseInstrument...cbClosecbClosem_bDone?m_bDone?cbWaitForData();cbWaitForData();OnWaitEvent();OnWaitEvent();Monitor semaphore in shared bufferMonitor semaphor...cbCheckForDatacbCheckForDataProcessIncomingPacketProcess...handle config packetshandle config pa...listener->ProcessIncomingPacketlistener->...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..19e23c99 --- /dev/null +++ b/docs/client_mode_sequence_diagrams.md @@ -0,0 +1,275 @@ +# 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 segmentsinit 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 +``` + +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) + +```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_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 + 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 devicepackets 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 sysfreqthen FILTER: instrument != selected idx (0 for HUB1) → 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, 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 + 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 sysfreqthen 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 (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 new file mode 100644 index 00000000..63ed7e41 --- /dev/null +++ b/docs/multi_version_central_compat/README.md @@ -0,0 +1,239 @@ +# 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 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 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. + +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 + +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. 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/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 +``` + +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 + +```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. + +#### 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 + +#### 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. Register the version + +First, add a value for the version to the `CentralVersion` enum. + +```bash +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 +``` + +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 + +```bash +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 + +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..01cc4302 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) | @@ -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) || @@ -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 | | +| | } | | +| | } | | | +-------------------------------------------------------------------------------------+ | +-----------------------------------------------------------------------------------------+ ``` @@ -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) @@ -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,42 @@ 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) +**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 `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) +- 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 `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 @@ -297,30 +300,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 +334,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 +351,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 +448,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 +459,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 +487,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 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 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(); diff --git a/examples/ClearConfigRepro/clear_config_repro.cpp b/examples/ClearConfigRepro/clear_config_repro.cpp index 71adac51..954b413b 100644 --- a/examples/ClearConfigRepro/clear_config_repro.cpp +++ b/examples/ClearConfigRepro/clear_config_repro.cpp @@ -49,8 +49,9 @@ int main(int argc, char* argv[]) { auto session = std::move(result.value()); std::cout << " connected. protocol code=" << session.getProtocolVersion() << " ident=\"" << session.getProcIdent() << "\""; - if (const auto* si = session.getSysInfo()) { - std::cout << " sysfreq=" << si->sysfreq; + auto sysinfo = session.getSysInfo(); + if (sysinfo.isOk()) { + std::cout << " sysfreq=" << sysinfo.value().sysfreq; } std::cout << "\n"; @@ -59,7 +60,7 @@ int main(int argc, char* argv[]) { // Gather all analog-in channels (mirrors Orion's allChannels). std::vector allChannels; for (uint32_t ch = 1; ch <= cbNUM_ANALOG_CHANS; ++ch) { - if (session.getChanInfo(ch) != nullptr) allChannels.push_back(ch); + if (session.getChanInfo(ch).isOk()) allChannels.push_back(ch); } std::cout << " discovered " << allChannels.size() << " analog channels\n"; if (allChannels.empty()) return 2; @@ -86,9 +87,9 @@ int main(int argc, char* argv[]) { }; for (uint32_t ch : allChannels) { // clear LNC - const auto* base = session.getChanInfo(ch); - if (!base) return false; - cbPKT_CHANINFO ci = *base; + auto base = session.getChanInfo(ch); + if (base.isError()) return false; + auto& ci = base.value(); ci.chan = ch; ci.cbpkt_header.type = cbPKTTYPE_CHANSETAINP; ci.ainpopts &= ~(cbAINP_LNC_MASK | cbAINP_RAWSTREAM); @@ -99,9 +100,9 @@ int main(int argc, char* argv[]) { paced(); } for (uint32_t ch : allChannels) { // clear spike processing - const auto* base = session.getChanInfo(ch); - if (!base) return false; - cbPKT_CHANINFO ci = *base; + auto base = session.getChanInfo(ch); + if (base.isError()) return false; + auto& ci = base.value(); ci.chan = ch; ci.cbpkt_header.type = cbPKTTYPE_CHANSETSPK; ci.spkopts &= ~SPIKE_PROCESSING_OPTION_MASK; 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..208e67b8 100644 --- a/pycbsdk/src/pycbsdk/session.py +++ b/pycbsdk/src/pycbsdk/session.py @@ -718,10 +718,14 @@ 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}]") + written = _lib.cbsdk_session_get_channel_label( + self._session, chan_id, buf, buf_len + ) + if written < 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 +829,14 @@ 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}]") + written = _lib.cbsdk_session_get_group_label( + self._session, group_id, buf, buf_len + ) + if written < 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 +1936,15 @@ 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}]") + written = _lib.cbsdk_session_get_filter_label( + self._session, filter_id, buf, buf_len + ) + if written < 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/cbproto/include/cbproto/config.h b/src/cbproto/include/cbproto/config.h index 284a6866..cc67e320 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 { /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -41,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/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..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 @@ -23,15 +25,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; /// @} @@ -40,6 +40,7 @@ extern "C" { /// @{ /// @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 @@ -55,38 +56,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 +81,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; + +/// @} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @name Maximum Entity Ranges #2 +/// +/// Ground truth from upstream/cbproto/cbproto.h lines 237-262 +/// These define the maximum number of instruments, channels, etc. +/// @{ -#define SCALE_LNC_COUNT 17 -#define SCALE_CONTINUOUS_COUNT 17 -#define SCALE_SPIKE_COUNT 23 +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 +151,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 +184,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 +199,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 +240,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 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 } 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 +273,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 +288,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 +308,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 +430,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 // 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 +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 // VER: 4.2+, changed to 0x84 from 0x81 // 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 +592,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 +603,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 +620,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 +651,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 +692,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 +728,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 +759,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 +780,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 +797,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 +808,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 +816,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 +833,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 +849,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 +868,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 +888,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 +900,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 +926,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 +942,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); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -958,11 +967,11 @@ 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; -#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 +986,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 +1015,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 +1032,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 +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.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 @@ -1068,8 +1078,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 +1105,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 +1114,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 +1131,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 +1171,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 +1211,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 @@ -1208,9 +1219,11 @@ 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); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1219,10 +1232,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 @@ -1245,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 @@ -1264,6 +1273,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 +1283,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 +1303,8 @@ typedef struct { } cbPKT_ADAPTFILTINFO; +constexpr uint32_t cbPKTDLEN_ADAPTFILTINFO = ((sizeof(cbPKT_ADAPTFILTINFO) / 4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1304,14 +1313,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 +1330,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 +1340,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 +1352,8 @@ typedef struct uint32_t lncGlobalMode; ///< reserved } cbPKT_LNC; +constexpr uint32_t cbPKTDLEN_LNC = ((sizeof(cbPKT_LNC) / 4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1357,10 +1362,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 +1375,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 +1386,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 +1418,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 +1431,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 // VER: 4.2+, changed to 130 from 128 /// @brief PKT Set:0xE3 Rep:0x63 - Log packet /// @@ -1460,6 +1457,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 +1468,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 +1484,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 +1494,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 +1501,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 +1511,8 @@ typedef struct { ///< on response -> 1 initiated } cbPKT_INITIMPEDANCE; +constexpr uint32_t cbPKTDLEN_INITIMPEDANCE = ((sizeof(cbPKT_INITIMPEDANCE)/4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1528,21 +1522,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 +1546,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 +1556,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 +1565,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 +1576,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 +1598,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 +1627,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 +1641,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 +1654,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 +1668,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 +1698,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 +1711,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 +1722,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 +1733,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 +1756,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 +1767,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 +1782,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 +1801,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 +1816,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 - -#define cbNM_FLAG_NONE 0 ///< No flags +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 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 +1852,8 @@ typedef struct { }; } cbPKT_NM; +constexpr uint32_t cbPKTDLEN_NM = ((sizeof(cbPKT_NM)/4) - cbPKT_HEADER_32SIZE); + /// @} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1904,10 +1870,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 +1884,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 +1894,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 +1918,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 /// @@ -1987,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 @@ -1999,6 +1961,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 +1972,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 +1981,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 +1992,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 +2042,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 +2053,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 +2063,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 +2073,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 +2084,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 +2102,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 +2151,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 +2165,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 +2185,11 @@ typedef struct { uint8_t block[512]; ///< block data } cbPKT_UPDATE_OLD; +constexpr uint32_t cbPKTDLEN_UPDATE_OLD = (sizeof(cbPKT_UPDATE_OLD)/4)-2; // VER: 4.2+ ONLY + /// @} -#ifdef __cplusplus -} -#endif +#endif // __cplusplus #pragma pack(pop) 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) 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/include/cbsdk/sdk_session.h b/src/cbsdk/include/cbsdk/sdk_session.h index 1066f92c..3f3203e4 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 7e7a9080..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 { - const cbPKT_CHANINFO* info = session->cpp_session->getChanInfo(chan_id); - return info ? info->label : nullptr; + auto info = session->cpp_session->getChanInfo(chan_id); + 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; } } @@ -711,8 +718,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 +730,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 +742,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 +755,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 +776,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 +851,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)); @@ -870,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 { - const cbPKT_GROUPINFO* info = session->cpp_session->getGroupInfo(group_id); - return info ? info->label : nullptr; + auto info = session->cpp_session->getGroupInfo(group_id); + 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; } } @@ -956,9 +971,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 +1009,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 +1240,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; } } @@ -1234,43 +1249,51 @@ 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 { - const cbPKT_FILTINFO* info = session->cpp_session->getFilterInfo(filter_id); - return info ? info->label : nullptr; - } catch (...) { return nullptr; } + auto info = session->cpp_session->getFilterInfo(filter_id); + 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) { 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 19256fc0..5f99f5e5 100644 --- a/src/cbsdk/src/sdk_session.cpp +++ b/src/cbsdk/src/sdk_session.cpp @@ -302,14 +302,30 @@ 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; + // 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 - 1); + } + // Fallback to device_config (no shmem available) + 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"); + } // Clock sync periodic probing std::chrono::steady_clock::time_point last_clock_probe_time{}; @@ -631,97 +647,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}" @@ -756,7 +681,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; } } @@ -770,43 +698,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( - central_cfg, central_rec, central_xmt, central_xmt_local, - central_status, central_spk, central_signal, - cbshm::Mode::CLIENT, cbshm::ShmemLayout::CENTRAL_COMPAT); - - 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); - } + 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( - 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; @@ -820,9 +727,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( - 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()); @@ -982,9 +888,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); @@ -993,9 +897,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) { @@ -1518,57 +1420,29 @@ 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 { - // 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]; - } - // Fallback to device_config (no shmem available) - if (m_impl->device_session) - return m_impl->device_session->getChanInfo(chan_id); - return nullptr; +Result SdkSession::getChanInfo(const uint32_t chan_id) const { + return m_impl->getChanInfo(chan_id); } -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]; - } + return m_impl->shmem_session->getGroupInfo(group_id - 1); } - 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 { @@ -1582,19 +1456,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; + cbPKT_CHANINFO ci{}; + if (m_impl->device_session) { + const auto* res = m_impl->device_session->getChanInfo(chan); + if (!res) continue; + ci = *res; + } else { + auto res = getChanInfo(chan); + if (res.isError()) continue; + 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); @@ -1602,25 +1479,17 @@ 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]; - } + return m_impl->shmem_session->getFilterInfo(filter_id + 1); } - return nullptr; + return Result::error("Filter information not available"); } uint32_t SdkSession::getRunLevel() const { @@ -1629,7 +1498,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; } @@ -1644,12 +1514,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; } @@ -1662,35 +1528,35 @@ 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 { + auto procinfo = m_impl->shmem_session->getProcInfo(); + 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; @@ -1735,29 +1601,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( @@ -1765,9 +1615,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++; } @@ -1779,10 +1629,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)); @@ -1793,10 +1643,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)); @@ -1807,13 +1657,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)); @@ -1850,8 +1700,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); } } @@ -1873,9 +1723,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; @@ -1910,8 +1760,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)); } @@ -1956,9 +1806,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)); @@ -2125,12 +1975,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); @@ -2253,17 +2103,17 @@ Result SdkSession::loadChannelMap( { std::lock_guard lock(m_impl->cmp_mutex); for (uint32_t chan_id = 1; chan_id <= cbMAXCHANS; ++chan_id) { - const cbPKT_CHANINFO* info = getChanInfo(chan_id); - if (!info || info->chan == 0) continue; - auto it = m_impl->cmp_entries.find(cmpKey(info->bank, info->term)); + 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) { - 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); @@ -2284,9 +2134,9 @@ Result SdkSession::clearChannelMap() { std::lock_guard lock(m_impl->cmp_mutex); if (!m_impl->cmp_entries.empty()) { for (uint32_t chan_id = 1; chan_id <= cbMAXCHANS; ++chan_id) { - const cbPKT_CHANINFO* info = getChanInfo(chan_id); - if (!info || info->chan == 0) continue; - if (m_impl->cmp_entries.count(cmpKey(info->bank, info->term))) { + 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); } } @@ -2313,9 +2163,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]; @@ -2562,7 +2412,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(); } @@ -2577,7 +2427,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(); } @@ -2595,7 +2445,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/CMakeLists.txt b/src/cbshm/CMakeLists.txt index b5456a7e..bca29984 100644 --- a/src/cbshm/CMakeLists.txt +++ b/src/cbshm/CMakeLists.txt @@ -9,6 +9,12 @@ 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 + src/central_adapters/v7_5.cpp + src/central_adapters/v7_0.cpp ) # Build as STATIC library @@ -34,7 +40,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 Kernel32 Version) elseif(APPLE) # macOS shared memory APIs target_link_libraries(cbshm PRIVATE pthread) 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 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..64465902 --- /dev/null +++ b/src/cbshm/include/cbshm/central_adapters/base.h @@ -0,0 +1,167 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @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: + virtual ~CentralBootstrapAdapterBase() = default; + + // 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; + virtual size_t getTransmitBufferLen() const = 0; + virtual size_t getTransmitBufferLocalLen() 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 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/v7_0.h b/src/cbshm/include/cbshm/central_adapters/v7_0.h new file mode 100644 index 00000000..ea94e932 --- /dev/null +++ b/src/cbshm/include/cbshm/central_adapters/v7_0.h @@ -0,0 +1,192 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v7_0.h +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Adapter for Central-compatible shared memory access +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef CBSHM_CENTRAL_ADAPTERS_V7_0_H +#define CBSHM_CENTRAL_ADAPTERS_V7_0_H + +#include +#include + +namespace cbshm { + +namespace central_v7_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; + size_t getTransmitBufferLen() const override; + size_t getTransmitBufferLocalLen() 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_0 + +} // namespace cbshm + +#endif // CBSHM_CENTRAL_ADAPTERS_V7_0_H diff --git a/src/cbshm/include/cbshm/central_adapters/v7_5.h b/src/cbshm/include/cbshm/central_adapters/v7_5.h new file mode 100644 index 00000000..b7420177 --- /dev/null +++ b/src/cbshm/include/cbshm/central_adapters/v7_5.h @@ -0,0 +1,192 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v7_5.h +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Adapter for Central-compatible shared memory access +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef CBSHM_CENTRAL_ADAPTERS_V7_5_H +#define CBSHM_CENTRAL_ADAPTERS_V7_5_H + +#include +#include + +namespace cbshm { + +namespace central_v7_5 { + +/// +/// @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; + size_t getTransmitBufferLen() const override; + size_t getTransmitBufferLocalLen() 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_5 + +} // namespace cbshm + +#endif // CBSHM_CENTRAL_ADAPTERS_V7_5_H diff --git a/src/cbshm/include/cbshm/central_adapters/v7_6.h b/src/cbshm/include/cbshm/central_adapters/v7_6.h new file mode 100644 index 00000000..afcd7b42 --- /dev/null +++ b/src/cbshm/include/cbshm/central_adapters/v7_6.h @@ -0,0 +1,192 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v7_6.h +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Adapter for Central-compatible shared memory access +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef CBSHM_CENTRAL_ADAPTERS_V7_6_H +#define CBSHM_CENTRAL_ADAPTERS_V7_6_H + +#include +#include + +namespace cbshm { + +namespace central_v7_6 { + +/// +/// @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; + size_t getTransmitBufferLen() const override; + size_t getTransmitBufferLocalLen() 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_6 + +} // namespace cbshm + +#endif // CBSHM_CENTRAL_ADAPTERS_V7_6_H diff --git a/src/cbshm/include/cbshm/central_adapters/v7_7.h b/src/cbshm/include/cbshm/central_adapters/v7_7.h new file mode 100644 index 00000000..deb0b59f --- /dev/null +++ b/src/cbshm/include/cbshm/central_adapters/v7_7.h @@ -0,0 +1,192 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @file v7_7.h +/// @author Caden Shmookler +/// @date 2026-05-22 +/// +/// @brief Adapter for Central-compatible shared memory access +/// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef CBSHM_CENTRAL_ADAPTERS_V7_7_H +#define CBSHM_CENTRAL_ADAPTERS_V7_7_H + +#include +#include + +namespace cbshm { + +namespace central_v7_7 { + +/// +/// @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; + size_t getTransmitBufferLen() const override; + size_t getTransmitBufferLocalLen() 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_7 + +} // namespace cbshm + +#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..9be34334 --- /dev/null +++ b/src/cbshm/include/cbshm/central_adapters/v7_8.h @@ -0,0 +1,192 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// @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; + size_t getTransmitBufferLen() const override; + size_t getTransmitBufferLocalLen() 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