Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,30 @@ jobs:

- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{ matrix.build_type }}

- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.10'

- name: Install mock dependencies
run: pip install websockets

- name: Start Mock CL1 WebSocket Server
run: |
python tests/mock_cl1_server.py &
echo $! > mock_server.pid
sleep 2

- name: Run Tests
working-directory: ${{github.workspace}}/build
run: ctest -C ${{ matrix.build_type }} --output-on-failure

- name: Tear Down Mock Server
if: always()
run: |
kill $(cat mock_server.pid) || true

- name: Run Benchmarks
working-directory: ${{github.workspace}}/build
run: ./cl_sdk_benchmark
40 changes: 40 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: "CodeQL"

on:
push:
branches: [ "main", "master" ]
pull_request:
branches: [ "main", "master" ]
schedule:
- cron: '30 2 * * 0'

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write

strategy:
fail-fast: false
matrix:
language: [ 'c-cpp' ]

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}

- name: Autobuild
uses: github/codeql-action/autobuild@v3

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
49 changes: 49 additions & 0 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Deploy WASM Demo to Pages

on:
push:
branches: ["main"]
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: "pages"
cancel-in-progress: false

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Emscripten
uses: mymindstorm/setup-emsdk@v14

- name: Build WASM
run: |
cd wasm
emcc cl_wasm.cpp -o cl_sdk.js -O3 -s WASM=1 -s EXPORTED_FUNCTIONS='["_init_sdk", "_process_telemetry", "_get_channel_voltage", "_malloc", "_free"]'

- name: Setup Pages
uses: actions/configure-pages@v5

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: 'wasm'

deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
83 changes: 83 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: Release Pipeline

on:
push:
tags:
- 'v*'

jobs:
build_and_release:
name: Build and Release
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: ubuntu-latest
artifact_name: libclsdk-linux.zip
lib_file: libclsdk.so
cmake_args: ''
- os: windows-latest
artifact_name: libclsdk-windows.zip
lib_file: clsdk.dll
cmake_args: '-DBUILD_SHARED_LIBS=ON'
- os: macos-latest
artifact_name: libclsdk-macos.zip
lib_file: libclsdk.dylib
cmake_args: ''

steps:
- name: Checkout Code
uses: actions/checkout@v3

- name: Configure CMake
run: cmake -B build -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_args }}

- name: Build
run: cmake --build build --config Release

- name: Prepare Package (Linux/macOS)
if: matrix.os != 'windows-latest'
run: |
mkdir package
cp -r include package/
find build -type f \( -name "*.so" -o -name "*.dylib" \) -exec cp {} package/ \;
cd package
zip -r ../${{ matrix.artifact_name }} .

- name: Prepare Package (Windows)
if: matrix.os == 'windows-latest'
run: |
mkdir package
cp -r include package/
find build -name "*.dll" -exec cp {} package/ \;
cd package
Compress-Archive -Path * -DestinationPath ../${{ matrix.artifact_name }}

- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.artifact_name }}
path: ${{ matrix.artifact_name }}

release:
name: Create GitHub Release
needs: build_and_release
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout Code
uses: actions/checkout@v3

- name: Download Artifacts
uses: actions/download-artifact@v3
with:
path: artifacts

- name: Create Release and Upload Assets
uses: softprops/action-gh-release@v1
with:
files: artifacts/**/*.zip
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
12 changes: 11 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,14 @@ target_link_libraries(CorticalLabsCpp PUBLIC clsdk_c_core)

# C++ Example Binary
add_executable(cl_sdk_example src/example.cpp)
target_link_libraries(cl_sdk_example PRIVATE CorticalLabsCpp)
target_link_libraries(cl_sdk_example PRIVATE CorticalLabsCpp)

# Tests & Benchmarks
enable_testing()

add_executable(cl_sdk_tests tests/test_runner.cpp)
target_link_libraries(cl_sdk_tests PRIVATE CorticalLabsCpp)
add_test(NAME CLSDKTests COMMAND cl_sdk_tests)

add_executable(cl_sdk_benchmark benchmarks/benchmark.cpp)
target_link_libraries(cl_sdk_benchmark PRIVATE CorticalLabsCpp)
94 changes: 65 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,49 +1,92 @@
# 🧠 cl-sdk-cpp

**⚡️ High-Performance C/C++ SDK for Cortical Labs HD-MEA ⚡️**

[![Build Status](https://github.com/ROE-Defense/cl-sdk-cpp/actions/workflows/build.yml/badge.svg)](https://github.com/ROE-Defense/cl-sdk-cpp/actions/workflows/build.yml)
[![Security](https://github.com/ROE-Defense/cl-sdk-cpp/actions/workflows/codeql.yml/badge.svg)](https://github.com/ROE-Defense/cl-sdk-cpp/actions/workflows/codeql.yml)
[![Latest Release](https://img.shields.io/github/v/release/ROE-Defense/cl-sdk-cpp)](https://github.com/ROE-Defense/cl-sdk-cpp/releases/latest)
[![Live Demo](https://img.shields.io/badge/Live-WASM_Demo-success.svg)](https://ROE-Defense.github.io/cl-sdk-cpp/)
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![C Standard](https://img.shields.io/badge/C-C99-blue.svg)](https://en.wikipedia.org/wiki/C99)
[![C++ Standard](https://img.shields.io/badge/C%2B%2B-C%2B%2B17-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B17)

`cl-sdk-cpp` is a zero-overhead 🏎️, bare-metal C/C++ SDK designed specifically for interfacing with Cortical Labs' 59-channel High-Density Microelectrode Arrays (HD-MEA) 🧫. Engineered for AAA game developers 🎮, engine programmers ⚙️, and robotics researchers 🤖, this SDK provides an ultra-low latency bridge between synthetic neural environments and modern game engines 🌉.
**⚡️ High-Performance C/C++ SDK for Cortical Labs HD-MEA ⚡️**

`cl-sdk-cpp` is a C/C++ SDK designed for interfacing with Cortical Labs' 59-channel High-Density Microelectrode Arrays (HD-MEA). It provides a low-latency network bridge for connecting simulations or engines to the CL1 array.

---

### 🔥 Killer Feature: Asynchronous Telemetry Downsampling Buffer (25kHz -> 90Hz)

Bypass runtime bottlenecks! The SDK utilizes a fully detached threading model and an **Asynchronous Telemetry Downsampling Buffer** that seamlessly scales the raw 25kHz biological sampling rate down to engine-friendly update loops (e.g., 90Hz for VR or 144Hz for high-refresh rendering), without dropping critical high-frequency spike potentials.

---

## 🌐 Live Interactive WebAssembly Demo

Experience the C-core running natively in your browser! We've compiled the high-performance telemetry downsampling engine to WebAssembly.

[👉 **Click here to view the live 59-channel telemetry demo.**](https://ROE-Defense.github.io/cl-sdk-cpp/)

---

## 🏗️ Dual-Engine Architecture

Developers love diagrams. Here is how the high-performance pipeline flows from synthetic environments, to the biological substrate, and back:

```text
+-----------------------+ +-------------------------+
| Synthetic Workspace | Optical Flow | CL1 / Simulator |
| (UE5 / Nim Engine) | ----------------------> | (59-Channel Array) |
+-----------------------+ +-------------------------+
^ |
| |
| SNN Spikes |
| (UDP Firehose / REST) |
| |
| +-------------------------+ |
+-------------| cl-sdk-cpp C Core |<----------+
| (Downsampling Buffer) |
+-------------------------+
```

## 🔗 Official Documentation & Integration

## 🤔 Why C/C++?
For authoritative API references, visit the [Cortical Labs Documentation](https://docs.corticallabs.com/) and [Cortical Labs GitHub](https://github.com/Cortical-Labs).

The Cortical Labs Python simulator and API are fantastic for data science 📊, but they introduce unacceptable latency in real-time simulations ⏱️. `cl-sdk-cpp` solves this by bypassing the Python Global Interpreter Lock (GIL) entirely 🚀:
## 🧠 Architecture Highlights

- **Zero GIL Overhead:** Bypasses Python runtime bottlenecks to deliver true deterministic execution 🎯.
- **Detached Threading Model:** Implements an asynchronous, detached threading architecture for the WebSocket and REST network layers, ensuring that simulation ticks in your game engine are never blocked by network I/O 🕸️.
- **Asynchronous Telemetry Downsampling for High-Refresh Engines:** Configurable 25kHz aggregation buffer designed for the CL1 Simulator and physical CL1 hardware, capturing an ultra-high frequency biological sampling rate and delivering it seamlessly to high-refresh game loops 🏎️ (e.g., 60fps DOOM 👹, 90fps VR 🥽, 144fps Unreal 🕹️) without dropping critical high-frequency spike potentials ⚡️.
- **59-Channel HD-MEA Optimization:** Native C-struct serialization directly mapped to the 59-channel architecture of Cortical Labs' hardware, drastically reducing JSON parsing overhead 📦.
- **Engine-Ready bindings:** Designed to be directly dropped into Unreal Engine, custom C++ engines, or bound seamlessly to other compiled languages via FFI 🔌.
1. **C Core (`libclsdk`):** A C99 library managing socket connections, threading, and JSON serialization.
2. **C++ OOP Layer (`CorticalLabs.hpp`):** A C++17 wrapper offering RAII semantics and STL abstractions.
3. **Unreal Engine 5 Plugin (`CorticalLabs.uplugin`):** Native Blueprint Plugin support mapping the SDK into Blueprint nodes (`GetLatestSpikes`, `SendOpticalFlow`) and C++ modules.
4. **Nim FFI (`cl_sdk.nim`):** Bindings for Nim integration.

## 👑 Nim Engine Compatibility
## 🔌 Supported Integration Layers

For developers using the Nim programming language (highly favored in high-performance simulation), `cl-sdk-cpp` provides first-class FFI bindings 🤝. Nim's deterministic memory management pairs perfectly with the C-core, offering Python-like syntax with C-like speed 🐍⚡. See `examples/cl_sdk.nim` for a complete example of connecting to the dish via Nim 🍽️.
- [x] Native C/C++ ABI
- [x] Nim FFI
- [x] Unreal Engine 5 (.uplugin)
- [ ] Python 3.12 (ctypes / pybind11) [Coming Soon]

## 🏛️ Architecture Highlights
## 🗺️ Roadmap

1. **C Core (`libclsdk`):** A strictly bounded, `malloc`-minimal C99 library managing raw socket connections, threading, and JSON serialization 🧱.
2. **C++ OOP Layer (`CorticalLabs.hpp`):** A modern C++17 wrapper offering RAII semantics, exception handling, and `std::vector` abstractions for developers who prefer modern C++ 🏗️.
3. **Nim FFI (`cl_sdk.nim`):** Zero-cost bindings for Nim integrations 🚀.
- **Multi-Dish Orchestrator for distributed biology:** Manage and cluster multiple HD-MEA dishes efficiently.
- **Hardware-Agnostic Encoder Templates:** Out-of-the-box sensor encoding for (LiDAR, Optical Flow, Spectrogram).

## 🏁 Getting Started

### 📋 Prerequisites
- CMake 3.10+ 🛠️
- A C++17 compatible compiler 🖥️
- Cortical Labs API Key 🔑
- CMake 3.10+
- A C++17 compatible compiler
- Cortical Labs API Key

### 🔨 Build Instructions
### 🛠️ Build Instructions

```bash
mkdir build && cd build
cmake ..
make -j4
```

### Quick Start (C++ Wrapper)
### 🚀 Quick Start (C++ Wrapper)

```cpp
#include "CorticalLabs.hpp"
Expand All @@ -53,16 +96,13 @@ using namespace cortical_labs;

int main() {
try {
// Initialize detached WebSocket connection
DishConnection dish("wss://api.corticallabs.com/v1/dish", "YOUR_API_KEY");
dish.connect();

// Send Optical Flow Data (59 Channels)
std::vector<float> flow_x(59, 0.5f);
std::vector<float> flow_y(59, -0.2f);
dish.sendOpticalFlow(1005, flow_x, flow_y);

// Receive Spikes
auto spikes = dish.receiveSpikes(100);
for (const auto& s : spikes) {
std::cout << "Spike on Ch " << (int)s.channel_id << " Amp: " << s.amplitude << "\n";
Expand All @@ -74,9 +114,5 @@ int main() {
}
```

## 🐍 Cortical Labs Python Simulator Interoperability

The `cl-sdk-cpp` JSON serialization logic has been extensively tested against the Cortical Labs Python simulator 🧪. The C-core seamlessly injects generic API keys into the REST/WebSocket payload to ensure drop-in compatibility for researchers migrating from the Python-based workflow to this high-performance C/C++ stack 🔄.

---
*Created and maintained under Roe Defense. 🛡️*
*Maintained under Roe Defense.*
Loading
Loading