Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
d307189
draft poke manager
Poofjunior Apr 9, 2025
4495988
Draft poke manager tests
Prattbuw Apr 10, 2025
3fbc4b0
Poke manager test bed
Prattbuw Apr 16, 2025
f0f8f22
FSM logic for delphi controller
Prattbuw Apr 28, 2025
23dc424
Detect pokes and update FSM
Prattbuw Apr 29, 2025
ef03216
Updated transition duration values
Prattbuw Apr 30, 2025
b9d8cb6
Added poke manager test files and started to add registers and harp p…
Prattbuw May 2, 2025
b775ca5
Added poke detection functionality into poke manager
Prattbuw May 5, 2025
7298d58
Started implementing harp registers and protocol functionality
Prattbuw May 29, 2025
db93488
get project compiling; fix harp write fns
Poofjunior Jun 9, 2025
7dad877
draft device.yml
Poofjunior Jun 9, 2025
f4764eb
update device.yaml
Poofjunior Jun 9, 2025
ea8a647
inline short setters; fix pass sub-array-by-reference
Poofjunior Jun 9, 2025
e569481
split writing config into separate registers
Poofjunior Jun 10, 2025
d7e8b09
update pyharp registers
Poofjunior Jun 11, 2025
09d8ad9
cleanup reset state
Poofjunior Jun 11, 2025
5a86bf3
add request-next-odor callback
Poofjunior Jun 11, 2025
7db171f
update poke-manager test; get gpio inversion working
Poofjunior Aug 8, 2025
1026be5
get next-odor event request working
Poofjunior Aug 8, 2025
d2d1856
add wait for pokes script
Poofjunior Aug 8, 2025
b73deb4
fixed setting some state duration registers
Prattbuw Sep 12, 2025
5d948a9
made remaining valves odor valves
Prattbuw Sep 15, 2025
770e522
fixed odor queue functionality and poke state
Prattbuw Sep 15, 2025
b9fb8dd
fixed poke state register and added events for pokes
Prattbuw Sep 17, 2025
fe581ce
added min and max odor delivery time functionality
Prattbuw Sep 17, 2025
988bbdb
added raw poke state register and rise and fall events
Prattbuw Sep 17, 2025
d953206
added camera driver firmware
Prattbuw Sep 19, 2025
0e37762
fixed camera triggering
Prattbuw Sep 22, 2025
62e07a8
added pwm events and updated register documentation
Prattbuw Sep 23, 2025
dfce105
added register for enabling or disabling valve LEDs
Prattbuw Sep 26, 2025
3802221
Fixed event-based odor indexing and minor documentation errors
Prattbuw Oct 10, 2025
9e56b62
Pokes are only registered during the pre-odor delivery state
Prattbuw Oct 29, 2025
c4a9647
Fixed raw poke state read register
Prattbuw Oct 29, 2025
c8ad681
Fixed GPIO masking
Prattbuw Nov 19, 2025
629d07d
Updated GPIO indices in device.yaml
Prattbuw Nov 20, 2025
5901c5c
Refactorization for queuing an arbitrary number of odors
Prattbuw Nov 20, 2025
07248d6
Event for valve state changes
Prattbuw Nov 26, 2025
a92b267
Update register descriptions and access
Prattbuw Dec 1, 2025
5e4b96f
Fix device id
Prattbuw Dec 9, 2025
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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "firmware/lib/rp2040.pwm"]
path = firmware/lib/rp2040.pwm
url = [email protected]:AllenNeuralDynamics/rp2040.pwm.git
[submodule "firmware/lib/etl"]
path = firmware/lib/etl
url = https://github.com/ETLCPP/etl.git
278 changes: 274 additions & 4 deletions device.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,277 @@
%YAML 1.1
---
# yaml-language-server: $schema=https://harp-tech.org/draft-02/schema/device.json
device: ValveController
whoAmI: 1406
firmwareVersion: "0.0.0"
hardwareTargets: "1.0.0"
device: DelphiController
whoAmI: 1409
firmwareVersion: "0.0"
hardwareTargets: "1.0"
registers:
ValveState:
address: 32
type: U16
access: Event
description: "Set the enabled/disabled state (enabled = 1) of all valves"
ValvesSet:
address: 33
type: U16
maskType: ValveMask
access: Write
description: "Write a 1 to any bit to enable the corresponding valve."
ValvesClear:
address: 34
type: U16
maskType: ValveMask
access: Write
description: "Write a 1 to any bit to disable the corresponding valve."
ValveConfig0: &valveConfig
address: 35
type: U8
length: 12
access: Write
description: "the hit duty cycle (float: 0 - 1.0), hold duty cycle (float: 0 - 1.0), and hit duration in microseconds (U32) for Valve0."
ValveConfig1:
<<: *valveConfig
address: 36
description: "the hit duty cycle (float: 0 - 1.0), hold duty cycle (float: 0 - 1.0), and hit duration in microseconds (U32) for Valve1."
ValveConfig2:
<<: *valveConfig
address: 37
description: "the hit duty cycle (float: 0 - 1.0), hold duty cycle (float: 0 - 1.0), and hit duration in microseconds (U32) for Valve2."
ValveConfig3:
<<: *valveConfig
address: 38
description: "the hit duty cycle (float: 0 - 1.0), hold duty cycle (float: 0 - 1.0), and hit duration in microseconds (U32) for Valve3."
ValveConfig4:
<<: *valveConfig
address: 39
description: "the hit duty cycle (float: 0 - 1.0), hold duty cycle (float: 0 - 1.0), and hit duration in microseconds (U32) for Valve4."
ValveConfig5:
<<: *valveConfig
address: 40
description: "the hit duty cycle (float: 0 - 1.0), hold duty cycle (float: 0 - 1.0), and hit duration in microseconds (U32) for Valve5."
ValveConfig6:
<<: *valveConfig
address: 41
description: "the hit duty cycle (float: 0 - 1.0), hold duty cycle (float: 0 - 1.0), and hit duration in microseconds (U32) for Valve6."
ValveConfig7:
<<: *valveConfig
address: 42
description: "the hit duty cycle (float: 0 - 1.0), hold duty cycle (float: 0 - 1.0), and hit duration in microseconds (U32) for Valve7."
ValveConfig8:
<<: *valveConfig
address: 43
description: "the hit duty cycle (float: 0 - 1.0), hold duty cycle (float: 0 - 1.0), and hit duration in microseconds (U32) for Valve8."
ValveConfig9:
<<: *valveConfig
address: 44
description: "the hit duty cycle (float: 0 - 1.0), hold duty cycle (float: 0 - 1.0), and hit duration in microseconds (U32) for Valve9."
ValveConfig10:
<<: *valveConfig
address: 45
description: "the hit duty cycle (float: 0 - 1.0), hold duty cycle (float: 0 - 1.0), and hit duration in microseconds (U32) for Valve10."
ValveConfig11:
<<: *valveConfig
address: 46
description: "the hit duty cycle (float: 0 - 1.0), hold duty cycle (float: 0 - 1.0), and hit duration in microseconds (U32) for Valve11."
ValveConfig12:
<<: *valveConfig
address: 47
description: "the hit duty cycle (float: 0 - 1.0), hold duty cycle (float: 0 - 1.0), and hit duration in microseconds (U32) for Valve12."
ValveConfig13:
<<: *valveConfig
address: 48
description: "the hit duty cycle (float: 0 - 1.0), hold duty cycle (float: 0 - 1.0), and hit duration in microseconds (U32) for Valve13."
ValveConfig14:
<<: *valveConfig
address: 49
description: "the hit duty cycle (float: 0 - 1.0), hold duty cycle (float: 0 - 1.0), and hit duration in microseconds (U32) for Valve14."
ValveConfig15:
<<: *valveConfig
address: 50
description: "the hit duty cycle (float: 0 - 1.0), hold duty cycle (float: 0 - 1.0), and hit duration in microseconds (U32) for Valve15."
AuxGPIODir:
address: 51
type: U8
maskType: AuxGPIOMask
access: Write
description: "Specify each auxiliary GPIO pin as an input (0) or output (1)."
AuxGPIOState:
address: 52
type: U8
maskType: AuxGPIOMask
access: Write
description: "Set the state (on or off) of any auxiliary GPIO pins specified as outputs."
AuxGPIOSet:
address: 53
type: U8
maskType: AuxGPIOMask
access: Write
description: "When writing a 1 to any bit, turn on the specified auxiliary GPIO pins specified as outputs."
AuxGPIOClear:
address: 54
type: U8
maskType: AuxGPIOMask
access: Write
description: "When writing a 1 to any bit, Turn off the specified auxiliary GPIO pins specified as outputs."
AuxGPIOInputRiseEvent:
address: 55
type: U8
maskType: AuxGPIOMask
access: Event
description: ""
AuxGPIOInputFallEvent:
address: 56
type: U8
maskType: AuxGPIOMask
access: Event
description: ""
AuxGPIORisingInputs:
address: 57
type: U8
maskType: AuxGPIOMask
access: Write
description: ""
AuxGPIOFallingInputs:
address: 58
type: U8
maskType: AuxGPIOMask
access: Write
description: ""
PokePin:
address: 59
type: U8
access: Write
description: "which poke ports are active."
PokePinInverted:
address: 60
type: U8
access: Write
description: "Which poke ports are inverted (i.e: transition from HIGH to LOW when a poke occurs)."
PokeState:
address: 61
type: U8
access: Event
description: "The state of the poke port. An event will be triggered given a poke/ beam break that is greater than the min poke time."
RawPokeState:
address: 62
type: U8
access: Event
description: "The raw state of the poke pin. Events will be triggered at the onset of a beam break (1) and offset (0)."
PokeDometer:
address: 63
type: U32
access: Read
description: "number of mouse pokes per port since boot or reset."
FSMState:
address: 64
type: U8
access: Write
description: "Enable (1) (aka reset) or Disable (0) the poke handling state machine. Note that QueuedOdorIndex must be specified first. Disabling and then enabling a previously-enabled FSM will reset it to its starting state."
ForceFSM:
address: 65
type: U8
access: Write
description: "Force the poke handling state machine to iterate as if handling a mouse poke. PokeDometers are not incremented."
QueuedOdorMask:
address: 66
type: U16
access: Event
description: "Queued odors (value: odor valve mask) that will be delivered to the odor port given a register poke. After odors have been dispensed, the register will be set to 0, which indicates that new odors are needed"
VacuumCloseTimeUS:
address: 67
type: U32
access: Write
description: "Time alotted (in microseconds) for the vacuum valve to close."
MinOdorDeliveryTimeUS:
address: 68
type: U32
access: Write
description: "Minimum time alotted (in microseconds) for the odor delivery state."
MaxOdorDeliveryTimeUS:
address: 69
type: U32
access: Write
description: "Maximum time alotted (in microseconds) for the odor delivery state."
OdorTransitionTimeUS:
address: 70
type: U32
access: Write
description: "Time alotted (in microseconds) before the vacuum turns on to remove the current odor."
VacuumSetupTimeUS:
address: 71
type: U32
access: Write
description: "Time alotted (in microseconds) for the vacuum to open."
FinalValveEnergizedTimeUS:
address: 72
type: U32
access: Write
description: "Time alotted (in microseconds) for the final valve to open and remain on."
MinimumPokeTimeUS:
address: 73
type: U32
access: Write
description: "Minimum time (in microseconds) necessary for a mouse poke port beam to be broken before being interpretted as a poke."
CamPin:
address: 74
type: U8
access: Write
description: "The GPIO output pin used for camera triggering. Default pin is 26."
CamPinState:
address: 75
type: U8
access: Event
description: "Event is initiated when a rising edge of the camera triggered signal (PWM) is detected. The actual value of the pin doesn't change."
FrameRate:
address: 76
type: U32
access: Write
description: "Set the frame rate of the camera trigger/ frequency of the PWM signal."
DutyCycle:
address: 77
type: Float
access: Write
description: "Set the duty cycle of the PWM. Default and recommend is 0.5 for producing a square wave."
EnableCamTrigger:
address: 78
type: U8
access: Write
description: "Enable (1) and disable (0) camera triggering/ the PWM signal."
EnableValveLeds:
address: 79
type: U8
access: Write
description: "Enable (1) and disable (0) valve LEDs."

groupMasks:
ValveMask:
description: "Valve that can be configured/enabled/disabled"
values:
Valve0: 0x0
Valve1: 0x1
Valve2: 0x2
Valve3: 0x3
Valve4: 0x4
Valve5: 0x5
Valve6: 0x6
Valve7: 0x7
Valve8: 0x8
Valve9: 0x9
Valve10: 0xA
Valve11: 0xB
Valve12: 0xC
Valve13: 0xD
Valve14: 0xE
Valve15: 0xF
AllValves: 0xFFFF
AuxGPIOMask:
description: "Auxiliary GPIO index."
values:
AuxGPIO0: 0x01
AuxGPIO1: 0x02
AuxGPIO2: 0x04
AuxGPIO3: 0x08
AuxGPIO4: 0x10
AuxGPIO5: 0x20
AuxGPIO6: 0x40
AuxGPIO7: 0x80
46 changes: 38 additions & 8 deletions firmware/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work ==
if(WIN32)
set(USERHOME $ENV{USERPROFILE})
else()
set(USERHOME $ENV{HOME})
endif()
set(sdkVersion 2.2.0)
set(toolchainVersion 14_2_Rel1)
set(picotoolVersion 2.2.0)
set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake)
if (EXISTS ${picoVscode})
include(${picoVscode})
endif()
# ====================================================================================
set(PICO_BOARD pico CACHE STRING "Board type")

cmake_minimum_required(VERSION 3.13)
find_package(Git REQUIRED)
execute_process(COMMAND "${GIT_EXECUTABLE}" rev-parse --short HEAD OUTPUT_VARIABLE COMMIT_ID OUTPUT_STRIP_TRAILING_WHITESPACE)
Expand All @@ -6,42 +22,56 @@ add_definitions(-DGIT_HASH="${COMMIT_ID}") # Usable in source code.

#add_definitions(-DDEBUG) # Uncomment for debugging
add_definitions(-DUSBD_MANUFACTURER="Allen Institute")
add_definitions(-DUSBD_PRODUCT="valve-controller")
add_definitions(-DUSBD_PRODUCT="delphi-controller")

# PICO_SDK_PATH must be defined.
include(${PICO_SDK_PATH}/pico_sdk_init.cmake)

# Use modern conventions like std::invoke
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 23)

project(valve-controller)
project(delphi-controller)

pico_sdk_init()
add_subdirectory(lib/harp.core.rp2040/firmware) # Path to harp.core.rp2040.
add_subdirectory(lib/rp2040.pwm)
add_subdirectory(lib/etl build/etl) # etl library path


add_executable(${PROJECT_NAME}
src/main.cpp
src/valve_controller_app.cpp
src/delphi_controller_app.cpp
)

add_library(valve_driver
src/valve_driver.cpp
)

add_library(poke_manager
src/poke_manager.cpp
)

add_library(pwm_pio
src/pwm_pio.cpp
)

include_directories(inc)

target_link_libraries(valve_driver rp2040_pwm pico_stdlib)
target_link_libraries(${PROJECT_NAME} harp_core harp_c_app rp2040_pwm
valve_driver harp_sync pico_stdlib)

pico_add_extra_outputs(${PROJECT_NAME})
target_link_libraries(poke_manager pico_stdlib valve_driver etl::etl)
target_link_libraries(pwm_pio hardware_pio pico_stdlib)
target_link_libraries(${PROJECT_NAME}
harp_core harp_c_app rp2040_pwm poke_manager hardware_pio hardware_gpio pwm_pio valve_driver harp_sync
pico_stdlib etl::etl) #pico_stdio_usb

if(DEBUG)
message(WARNING "Debug printf() messages from harp core to UART with baud \
rate 921600.")
pico_enable_stdio_uart(${PROJECT_NAME} 1) # UART stdio for printf.
pico_enable_stdio_uart(poke_manager 1)
pico_enable_stdio_uart(pwm_pio 1)
# Additional libraries need to have stdio init also.
endif()

pico_add_extra_outputs(${PROJECT_NAME})

Loading