Skip to content
Closed
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
9 changes: 9 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
Language: Cpp
BasedOnStyle: Google

# Headstage differences
ColumnLimit: 100
SortIncludes: false
DerivePointerAlignment: false
PointerAlignment: Left
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
*.pb.cc
*.pb.h
*_pb2.py
*.pyc

.cache/
.vscode/
Expand Down Expand Up @@ -76,4 +78,7 @@ Testing/
*.deb

# cached permissions
.synapse_deploy_cache.json
.synapse_deploy_cache.json
app-sdk/
vcpkg_installed/
*.desc
45 changes: 45 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: check-added-large-files
- id: check-executables-have-shebangs
- id: check-json
- id: check-shebang-scripts-are-executable
- id: check-yaml
- id: detect-private-key
- id: end-of-file-fixer
- id: mixed-line-ending
- id: trailing-whitespace

- repo: https://github.com/pocc/pre-commit-hooks
rev: v1.3.5
hooks:
- id: clang-format
args:
- --style=file
- -i
- id: cppcheck
name: cppcheck
language: system
entry: cppcheck
args: [
"--enable=style,performance,warning",
"--check-level=exhaustive",
"--suppress=missingInclude",
"--suppress=missingIncludeSystem",
"--suppress=unusedFunction",
"--suppress=useStlAlgorithm",
"--inconclusive",
"--error-exitcode=1",
"--std=c++20",
"--platform=unix64",
"--language=c++"
]
files: \.(c|cpp)$

- repo: https://github.com/koalaman/shellcheck-precommit
rev: v0.10.0
hooks:
- id: shellcheck
20 changes: 15 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ include("cmake/protos.cmake")
option(BUILD_FOR_ARM64 "Build for ARM64 architecture" OFF)
option(USE_LOCAL_SDK "Use locally built SDK instead of system installation" OFF)
set(LOCAL_SDK_PATH "app-sdk" CACHE PATH "Path to local SDK build directory")

if (BUILD_FOR_ARM64 AND NOT CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64|arm64")
message(STATUS "Cross compiling for ARM64")
set(CMAKE_SYSTEM_NAME Linux)
Expand All @@ -27,13 +26,12 @@ if(USE_LOCAL_SDK)
message(FATAL_ERROR "USE_LOCAL_SDK is ON but LOCAL_SDK_PATH is not set")
endif()
message(STATUS "Using local SDK from: ${LOCAL_SDK_PATH}")

set(SDK_LIB_PATH "${LOCAL_SDK_PATH}")
set(SDK_LIB_NAME "synapse-app-sdk")
link_directories(${SDK_LIB_PATH})

set(SYNAPSE_APP_SDK_LIB ${SDK_LIB_NAME})

include_directories("${LOCAL_SDK_PATH}/include")
else()
find_library(SYNAPSE_APP_SDK_LIB NAMES synapse-app-sdk libsynapse-app-sdk.so.0.1.0)
Expand All @@ -45,9 +43,20 @@ add_executable(synapse-example-app
${CMAKE_CURRENT_SOURCE_DIR}/src/fixed_weight_decoder.cpp
)

# Generate synapse sdk api protobufs
generate_protobufs(
TARGET synapse-example-app
OUT_PROTO_DIR PROTO_OUT_DIR
PROTO_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/external/sciencecorp/synapse-api"
)

# And also generate your custom app configuration protobuf
generate_protobufs(
TARGET synapse-example-app
OUT_PROTO_DIR APP_PROTO_OUT_DIR
PROTO_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/proto"
GENERATE_PYTHON
PYTHON_OUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/proto"
)

# Be strict about the standard
Expand All @@ -61,8 +70,9 @@ set_target_properties(synapse-example-app PROPERTIES
target_include_directories(synapse-example-app
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
PRIVATE
PRIVATE
${PROTO_OUT_DIR}
${APP_PROTO_OUT_DIR}
)

# Link dependencies
Expand Down
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ RUN git clone https://github.com/microsoft/vcpkg.git "${VCPKG_ROOT}" && \

# copy project-specific ports and manifest before installing
COPY vcpkg.json "${VCPKG_ROOT}/vcpkg.json"
COPY external "${VCPKG_ROOT}/external/"
COPY external/sciencecorp/vcpkg "${VCPKG_ROOT}/external/sciencecorp/vcpkg"

RUN cd "${VCPKG_ROOT}" && \
./vcpkg install \
Expand All @@ -109,7 +109,7 @@ RUN cd "${VCPKG_ROOT}" && \
# -----------------------------------------------------------------------------
# Install Synapse SDK from internal repository (same steps on both)
# -----------------------------------------------------------------------------
ARG SDK_VERSION=0.3.0
ARG SDK_VERSION=0.4.4
COPY keys/science-repo-public.asc /usr/share/keyrings/scifi-repo-science-public.asc
RUN set -eux; \
apt-get update && apt-get install -y --no-install-recommends ca-certificates; \
Expand All @@ -128,4 +128,4 @@ ENV VCPKG_INSTALLED_DIR="${VCPKG_ROOT}/build/host/vcpkg_installed"
# Final workspace & entrypoint
# -----------------------------------------------------------------------------
WORKDIR /home/workspace
CMD ["/bin/bash"]
CMD ["/bin/bash"]
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,16 @@ To listen to joystick output:
```bash
python3 ${REPO_ROOT}/client/listen_to_joystick.py --device-ip <your-device-ip>
```

## Development
If you want, it is recommended to install and configure pre-commit to auto lint your files.

```bash
pip install pre-commit

pre-commit install

# Now this will be run when you commit
# However, you can also run it manually like this
pre-commit run
```
Empty file modified client/listen_to_joystick.py
100644 → 100755
Empty file.
98 changes: 92 additions & 6 deletions cmake/protos.cmake
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
function(generate_protobufs)
cmake_parse_arguments(PARSE_ARGV 0 "arg"
""
"TARGET;OUT_PROTO_DIR"
""
"GENERATE_PYTHON"
"TARGET;OUT_PROTO_DIR;PYTHON_OUT_DIR"
"PROTO_DIRS;PROTO_FILES"
)

if(DEFINED arg_UNPARSED_ARGUMENTS)
Expand All @@ -14,16 +14,56 @@ function(generate_protobufs)
if(NOT DEFINED arg_TARGET)
message(FATAL_ERROR "TARGET must be specified.")
endif()
if(NOT DEFINED arg_PROTO_DIRS AND NOT DEFINED arg_PROTO_FILES)
message(FATAL_ERROR "At least one of PROTO_DIRS or PROTO_FILES must be specified.")
endif()
if(arg_GENERATE_PYTHON AND NOT DEFINED arg_PYTHON_OUT_DIR)
message(FATAL_ERROR "PYTHON_OUT_DIR must be specified when GENERATE_PYTHON is enabled.")
endif()

set(PROTO_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/include)
file(MAKE_DIRECTORY ${PROTO_OUT_DIR})

# Initialize empty lists for proto include dirs and proto files
set(PROTO_INCLUDE_DIRS "")
set(PROTOS "")

# Include Synapse API proto directory in the include path
get_filename_component(SYNAPSE_PROTO_INCLUDE_DIR ./external/sciencecorp/synapse-api REALPATH)
file(GLOB_RECURSE SYNAPSE_PROTOS ${SYNAPSE_PROTO_INCLUDE_DIR}/*.proto)
list(APPEND PROTO_INCLUDE_DIRS ${SYNAPSE_PROTO_INCLUDE_DIR})
if(DEFINED SCIFI_PROTO_INCLUDE_DIR)
list(APPEND PROTO_INCLUDE_DIRS ${SCIFI_PROTO_INCLUDE_DIR})
endif()

# Add custom proto directories and files if provided
if(DEFINED arg_PROTO_DIRS)
foreach(DIR ${arg_PROTO_DIRS})
get_filename_component(ABS_DIR ${DIR} REALPATH)
list(APPEND PROTO_INCLUDE_DIRS ${ABS_DIR})
# If specific files not provided, include all protos in the directory
if(NOT DEFINED arg_PROTO_FILES)
file(GLOB_RECURSE DIR_PROTOS ${ABS_DIR}/*.proto)
list(APPEND PROTOS ${DIR_PROTOS})
endif()
endforeach()
endif()

# Add specific proto files if provided
if(DEFINED arg_PROTO_FILES)
foreach(PROTO_FILE ${arg_PROTO_FILES})
get_filename_component(ABS_PROTO_FILE ${PROTO_FILE} REALPATH)
list(APPEND PROTOS ${ABS_PROTO_FILE})

# Also add the directory containing this proto file to include dirs
get_filename_component(PROTO_DIR ${ABS_PROTO_FILE} DIRECTORY)
list(APPEND PROTO_INCLUDE_DIRS ${PROTO_DIR})
endforeach()
endif()

set(PROTO_INCLUDE_DIRS ${SYNAPSE_PROTO_INCLUDE_DIR} ${SCIFI_PROTO_INCLUDE_DIR})
set(PROTOS ${SYNAPSE_PROTOS} ${SCIFI_PROTOS})
# Remove duplicates from PROTO_INCLUDE_DIRS
list(REMOVE_DUPLICATES PROTO_INCLUDE_DIRS)

# Generate C++ protobufs (existing functionality)
protobuf_generate(
TARGET ${arg_TARGET}
LANGUAGE cpp
Expand All @@ -33,6 +73,52 @@ function(generate_protobufs)
OUT_VAR PROTO_SOURCES
)

# Generate Python protobufs if requested
if(arg_GENERATE_PYTHON)
file(MAKE_DIRECTORY ${arg_PYTHON_OUT_DIR})

# Generate Python bindings
protobuf_generate(
TARGET ${arg_TARGET}
LANGUAGE python
IMPORT_DIRS ${PROTO_INCLUDE_DIRS}
PROTOS ${PROTOS}
PROTOC_OUT_DIR ${arg_PYTHON_OUT_DIR}
OUT_VAR PYTHON_PROTO_SOURCES
)

# Convert PROTO_INCLUDE_DIRS to --proto_path arguments BEFORE using them
set(PROTO_INCLUDE_DIRS_ARGS "")
foreach(INCLUDE_DIR ${PROTO_INCLUDE_DIRS})
list(APPEND PROTO_INCLUDE_DIRS_ARGS --proto_path=${INCLUDE_DIR})
endforeach()

# Generate descriptor sets (.desc files) for runtime loading
set(DESC_OUT_DIR ${arg_PYTHON_OUT_DIR})
foreach(PROTO_FILE ${PROTOS})
get_filename_component(PROTO_NAME ${PROTO_FILE} NAME_WE)
set(DESC_FILE ${DESC_OUT_DIR}/${PROTO_NAME}.desc)

add_custom_command(
OUTPUT ${DESC_FILE}
COMMAND ${Protobuf_PROTOC_EXECUTABLE}
ARGS --descriptor_set_out=${DESC_FILE}
--include_imports
${PROTO_INCLUDE_DIRS_ARGS}
${PROTO_FILE}
DEPENDS ${PROTO_FILE}
COMMENT "Generating descriptor set for ${PROTO_NAME}"
VERBATIM
)

# Add to target dependencies
add_custom_target(${arg_TARGET}_${PROTO_NAME}_desc DEPENDS ${DESC_FILE})
add_dependencies(${arg_TARGET} ${arg_TARGET}_${PROTO_NAME}_desc)
endforeach()

message(STATUS "Python protobufs and descriptors will be generated in: ${arg_PYTHON_OUT_DIR}")
endif()

# NOTE: Uncomment this to generate the gRPC code if we ever need it
# protobuf_generate(
# TARGET ${arg_TARGET}
Expand Down
14 changes: 13 additions & 1 deletion config/simulator_32ch.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,19 @@
"type": "kApplication",
"id": 2,
"application": {
"name": "synapse-example-app"
"name": "synapse-example-app",
"parameters": {
"@type": "type.googleapis.com/app.ExampleAppConfig",
"low_cutoff_hz": 200.0,
"high_cutoff_hz": 5000.0,
"spike_threshold_uv": 50.0,
"waveform_size": 50,
"refractory_period_us": 1000,
"window_size": 5,
"max_expected_rate": 10.0,
"cursor_channels": [0, 7, 16, 30],
"enable_function_profiling": false
}
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion external/sciencecorp/synapse-api
4 changes: 3 additions & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{
"name": "synapse-example-app"
"name": "synapse-example-app",
"proto_files": ["proto/example_app.proto"],
"device_config_path": "config/simulator_32ch.json"
}
29 changes: 29 additions & 0 deletions proto/example_app.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
syntax = "proto3";

package app;

message ExampleAppConfig {
float low_cutoff_hz = 1;
float high_cutoff_hz = 2;

// Threshold in microvolts
float spike_threshold_uv = 3;

// Samples per waveform
uint32 waveform_size = 4;

// Refractory Period, in microseconds
uint32 refractory_period_us = 5;

// Number of bins to use for firing rate estimation
uint32 window_size = 6;

// max expected rate, used for normalization
float max_expected_rate = 7;

// Cursor control channels to use, we expect there to be four channels
repeated int32 cursor_channels = 8;

// Should we be enabling the function profiling and readouts
bool enable_function_profiling = 9;
}
Loading