Changelog#
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
0.1.0a15 - 2026-10-23#
Added#
FlexIO channels (Bpod Finite State Machine r2+):
Bpod.flex_ioconfigures each channel as digital or analog input or output, with analog thresholds and the sampling rate, andBpod.get_analog_datareturns the sampled analog input in millivolts. State machines can use Flex events and outputs, and global timers can drive Flex outputs.Bpod.action_names: the actions a state machine can currently set, likeBpod.input_event_namesfor events.ExtendedSerial.temporary_timeout: a context manager that changes the read timeout temporarily.ipc.iter_services,ipc.discoverandipc.ServiceIteratoraccept regex and collection criteria forproperties, likecom.find_ports(seemisc.Filter).misc.SuggestionMapping: a read-only mapping that suggests similar keys on failed lookups.
Changed#
com.find_portstakes explicit keyword-only filters instead of**filtersand raises aTypeErrorfor unknown ones. It and service discovery ignore filters set toNone.Bpod.inputs,Bpod.outputsandBpod.modulesare read-onlymisc.SuggestionMappings, so misspelled module names get a suggestion, too.FlexIO channels are no longer listed in
Bpod.inputsandBpod.outputs; useBpod.flex_io.methods that query or reconfigure the Bpod (e.g.,
set_status_led,update_modules,Input.read,Module.load_serial_message) raise aBpodErrorwhile a state machine is running, instead of corrupting the trial's data.send_softcodeandInput.overridesend nothing while no state machine is running, since the Bpod would ignore it; they log a warning instead.trial data columns are named in title case (
Time,Trial,State Machine,State,Type,Event,Channel,Value).TrialisUInt32instead ofUInt16, andValueisUInt16instead ofUInt8, to hold FlexIO analog-output values in millivolts.lower CPU load: trial data is read from the Bpod in chunks, and live trial events are published in batches.
RemoteBpod'sevent_callbackstill receives single events.building, validating and compiling state machines is faster, and takes about half the time for large ones.
polars 2 is supported (
polars>=1.32.3,<3), and most dependencies accept versions down to the oldest ones tested. pydantic requires 2.8 or newer, since older 2.x versions failed on import.
Removed#
misc.SuggestionDict(usemisc.SuggestionMapping) andcom.FilterValue(usemisc.Filter).the
rechunkparameter ofget_data: call.rechunk()on the result instead.Bpod.serial2: the FlexIO serial connection is now private.the unused
qtpydependency.
Fixed#
module events and softcodes never reached the state machine. Serial events are now allocated to modules as in Bpod's MATLAB software, which also fixes misnumbered input events with modules requesting a non-default number of events.
events in the same state machine cycle as a transition were evaluated in the new state, so trial data could attribute them to the wrong state or record transitions the Bpod never made.
GlobalTimerTrigandGlobalTimerCancelacted on the wrong global timers for indices of 2 or more.trial data showed valves and wire outputs as staying on when a state began that didn't set them, although the Bpod switches them off.
the
TrialEndtime of a queued trial was one state machine cycle late (100 µs on a Bpod 2+).state machine validation missed values the Bpod can't receive: softcodes above 254, references to global timers and counters that haven't been set (
GlobalTimerTrig,GlobalTimerCancel,GlobalCounterReset, onset triggers), and unknown global counter events and condition channels.a trial number above 65535 or below 0 made
get_data()fail, losing the collected trials.run()now rejects trial numbers outside 0 to 4,294,967,295.a
run()that raised before sending, e.g., for an invalid state machine, still used up a trial number, so the next trial skipped one.run()without a state machine reran the last one even after the hardware configuration had changed, e.g., throughupdate_modules(). It now raises aRuntimeError.get_data()right afterstop_state_machine()could raise "No trial data available" while the stopped trial was still being processed.Input.overridedidn't send the input's index, so the Bpod took the next command's first byte as the override state.is_runningwas brieflyFalsewhile a queued state machine was starting, sostop_state_machine()could do nothing.unplugging the Bpod during a trial went unnoticed.
wait()now raises aBpodError.a blocking
peek_data()could, rarely, hang when its trial ended without reaching a trigger state.closing a
Bpodcould wait forever for the Bpod to confirm the disconnect, or disconnect before the last softcodes were handled.leaving a
Bpodcontext didn't close its IPC service or end its softcode thread, and aBpodthat failed to connect kept its serial port open. Objects dropped without closing (aBpod, a subscribedRemoteBpod, an unfinishediter_servicesiterator, or anything a handler refers back to), a failedRemoteBpodhandshake and a failed Zeroconf start left connections and threads running.closing a
Bpod,ServiceHostorServiceClientfrom within its own handler hung or raised aRuntimeError.starting a service could fail with
FileNotFoundErrorwhile another process closed its last service, and closing aServiceHostorLocalServiceAdvertisementcould remove the files of a newer one with the same UUID.validating or compiling state machines in several threads at once (e.g., two Bpods in one process, or a
RemoteBpodnext to the host's own script) could fail or corrupt the caches they share.RemoteBpod.get_dataraised aDeprecationWarningwith polars 1.43.2 or newer.
0.1.0a14 - 2026-07-24#
Added#
Bpodpublishes live trial events over the PUB/SUB channel as a tagged union of typed messages.RemoteBpodaccepts anevent_callbackthat receives each live trial-event message.ServiceHost.get_metadatafor accessing per-request connection metadata from within a request handler.ServiceHost.publishfor broadcasting events over the PUB/SUB channel;ServiceClientdecodes them per its newevent_typeparameter.ServiceHostremembers the TCP ports last bound for a caller-supplieduuid(stored in the user state directory) and reuses them on restart; explicitport_rep/port_pubarguments take precedence.ServiceHost.has_subscribers: the host tracks PUB/SUB subscriptions andpublishdrops messages before encoding while nobody is listening.ServiceClient.requestaccepts an optionaltimeout; the client recovers cleanly after a timed-out request.
Changed#
Add UTC timezone to trial DataFrame timestamps.
ServiceClientadopts the host's serialization format during the handshake, replacing the per-request trial-and-error fallback.the WELCOME handshake carries the PUB channel's TCP port instead of full TCP addresses.
errors raised by
bpod_core.ipcare now uniformlyServiceErrorsubclassesremote method calls (
BpodRequestCall/BpodRequestData) are validated against an explicit allowlist instead of dispatching to arbitrary attributes.
Fixed#
ServiceClientno longer blocks indefinitely when the host dies mid-request.exceptions with non-serializable attributes no longer break error replies from
ServiceHost.resolved several shutdown races between
close()and the event threads /publish().ServiceIterator.close()now terminates an iteration blocked in__next__(e.g., withtimeout=None) instead of leaving the consumer waiting forever.
0.1.0a13 - 2026-06-18#
Changed#
further work on bringing
RemoteBpodto parity withBpod.ExtendedSerial.read_structandwrite_structmethods accept precompiled structs.reduced public interface of
bpod_core.ipc.improved documentation.
0.1.0a12 - 2026-04-30#
Just some minor improvements …
Changed#
further refinements to documentation.
cleaned up rendering of Graphviz graphs.
Removed#
removed unused
misc.DocstringInheritanceMixin
0.1.0a11 - 2026-04-24#
Added#
ExtendedSerial.read_struct_iterandExtendedSerial.stream_structmethods.misc.SuggestionDictfor key lookup with typo suggestions.added optional
trial_numberparameter toBpod.runmethod.
Changed#
replaced
NamedTupleswithmisc.SuggestionDictforBpod.inputsandBpod.outputsrefactored Sphinx documentation and API reference.
0.1.0a10 - 2026-04-16#
Added#
Bpod.address property — exposes the ZeroMQ address of the running instance.
Bpod.peek_data- read trial data before trial end.misc.ByteEnum- an extendedIntEnumthat caches its values as bytes.Timer fields in StateMachine now accept timedelta values in addition to floats.
bpodCLI entry point for launching a Bpod instance that can be connected to via TCP Unix Sockets.state machinecolumn added to trial data output (hash of the FSM)
Changed#
renamed
Bpod.send_state_machinetoBpod.run.removed
Bpod.run_state_machine.switched to Polars
LazyFramefor storing trial data.replaced use of
QueuewithSimpleQueue.switched
Bpod.modulefield fromNamedTupletodict.replaced hashlib.blake2b with xxhash for state machine hashing.
cache validation and compilation of state machines.
StateMachine.hashnow returnsbytesinstead ofstr.
0.1.0a9 - 2026-04-02#
Added#
bpod.is_readyproperty indicating whether a compiled FSM is loaded and ready to runbpod.is_queuedproperty indicating whether an FSM is queued to run after the current onebpod.get_datafor returning trial data after a state machine run.
Changed#
renamed
BNCinput events and output actions toTTLInandTTLOut.replaced MD5 hashing of
fsm.StateMachinewith blake2b.improved readability of
ValidationErrormessages infsm.StateMachine.state machine runs are now handled by three separate threads:
ReadThreadfor serial communication with the Bpod,EventThreadfor handling and structuring the incoming data, andSoftcodeThreadfor executing soft-codes.
Fixed#
reorganization of finalizers for better garbage collection.
0.1.0a8 - 2026-03-04#
Just a quick bugfix release …
Changed#
ipc.ServiceHost: set Zeroconf to listen on all interfaces, reorderWelcomeDatafields, and improve type hints.event handler callback type hint to return
Noneinstead ofAny.refactor CI workflows.
0.1.0a7 - 2026-03-01#
Added#
com.find_portsfor finding serial ports that match given filter criteria.com.verify_serial_discoveryfor checking if a serial device sends an expected discovery message.convenience functions for reading and writing integers in
com.ExtendedSerial.misc.extend_packedfor extending a bytearray by multiple values of the same format.misc.DocstringInheritanceMixinfor inheriting docstrings from base classes.ipc.LocalServiceAdvertisement: local service advertisement and discoveryipc.iter_servicesandipc.ServiceIteratorfor discovering services.bpod.discover_remote_bpodfor discovering remote Bpod instances.more examples.
Changed#
more verbose debug logging during state machine runs.
replace unmaintained
appdirsdependency withplatformdirs.switch to zero-based indexing for global counters, timers, conditions and soft-codes.
added file locking to
misc.SettingsDict.switch to using ZMQ multipart messages for communication.
renamed
ipc.DualChannelHost/ipc.DualChannelClienttoipc.ServiceHost/ipc.ServiceClient.restructured
bpodmodule into several submodules.zero-copy behavior on send path of
ipc.ServiceClientand receive path ofipc.ServiceHost.
Fixed#
decoupled finalizers and event loops from instance references.
0.1.0a6 - 2025-10-29#
Added#
Initial work on cached state machine validation:
fsm.StateMachine.check
Changed#
com.ExtendedSerialno longer supports NumPy types, integers, strings and iterables.refactoring of
com.ChunkedSerialReader
Removed#
com.to_bytesdependency on Pandas
0.1.0a5 - 2025-09-03#
Added#
fsm.to_fileandfsm.from_filefor export/import of state machines.YAML import/export for state machines
Work on documentation: Finite-State Machines
Changed#
moved state machine structure from msgspec Struct back to Pydantic Model
merged
fsm_typesmodule back intofsmrenamed parameters for
add_statemethod:state_change_conditions->transitionsandoutput_actions->actions
0.1.0a4 - 2025-08-25#
Added#
ipc.DualChannelHostandipc.DualChannelClientJSON import/export for state machines
example state machines
Changed#
improved export of state machines to graphviz
improved settings management
moved state machine structure from Pydantic Model to msgspec Struct
0.1.0a3 - 2025-08-04#
Added#
state machine assembly
state machine thread
ZMQ communication module
basic settings management
Changed#
switched package management from PDM to uv.
0.1.0a2 - 2025-05-07#
Added#
pydantic model for state machine
Changed#
further refactoring of the code
renamed
serialmodule tocomto avoid confusion with PySerial.
0.1.0a1 - 2025-04-22#
Changed#
major reorganization of the existing codebase.
renamed
serial_extensionsmodule toserial.
Removed#
removed
SerialSingletonclass.
0.1.0a0 - 2025-04-17#
First alpha release. Nothing works.