diff --git a/pycbsdk/cbhw/device/nsp.py b/pycbsdk/cbhw/device/nsp.py index f1ef898..3037890 100644 --- a/pycbsdk/cbhw/device/nsp.py +++ b/pycbsdk/cbhw/device/nsp.py @@ -45,6 +45,7 @@ CBNPlayMode, CBNPlayFlag, CBSpecialChan, + CBHoop ) from pycbsdk.cbhw.params import Params from pycbsdk.cbhw.consts import CBError @@ -528,6 +529,29 @@ def _configure_channel_autothreshold(self, chid: int, attr_value: int): pkt.spkopts |= CBAInpSpk.THRAUTO.value if attr_value else 0 self._send_packet(pkt) + def _configure_channel_hoops(self, chid: int, attr_value: dict): + """ + Args: + chid: 1-based channel index + attr_value: a dictionary of dictionaries of dictionaries. + The outer dictionary keys are the 1-based unit ids. + The middle dictionary keys are the 1-based hoop ids. + The inner dictionary has fields 'time', 'min', and 'max'. + e.g. attr_value = {1: { + 1: {'time': 13, 'min': -975, 'max': -646}, + 2: {'time': 6, 'min': 108, 'max': 342} + } + This will set the first two hoops for unit-1. + """ + pkt = copy.copy(self._config["channel_infos"][chid]) + pkt.header.type = CBPacketType.CHANSETSPKHPS + for un_id, hoop_dicts in attr_value.items(): + for hp_id, hp in hoop_dicts.items(): + pkt.spkhoops[un_id-1][hp_id-1] = CBHoop( + valid=1, time=hp["time"], min=hp["min"], max=hp["max"] + ) + self._send_packet(pkt) + def _configure_channel_label(self, chid: int, attr_value: str): pkt = copy.copy(self._config["channel_infos"][chid]) pkt.header.type = CBPacketType.CHANSETLABEL @@ -556,7 +580,11 @@ def _configure_channel_enable_spike(self, chid: int, attr_value: bool): pkt = copy.copy(self._config["channel_infos"][chid]) pkt.header.type = CBPacketType.CHANSETSPK pkt.spkopts &= ~CBAInpSpk.EXTRACT.value - pkt.spkopts |= CBAInpSpk.EXTRACT.value if attr_value else 0 + if attr_value: + pkt.spkopts |= CBAInpSpk.EXTRACT.value if attr_value else 0 + # Also reset sorting. Enable hoops by default. + pkt.spkopts &= ~CBAInpSpk.ALLSORT.value + pkt.spkopts |= CBAInpSpk.HOOPSORT.value self._send_packet(pkt, self._config_events["chaninfo"]) def configure_channel(self, chid: int, attr_name: str, attr_value): @@ -582,6 +610,8 @@ def configure_channel_spike(self, chid: int, attr_name: str, attr_value): self._configure_channel_enable_spike(chid, attr_value) elif attr_name.lower().startswith("autothresh"): self._configure_channel_autothreshold(chid, attr_value) + elif attr_name.lower().startswith("hoops"): + self._configure_channel_hoops(chid, attr_value) # self._config_events["chaninfo"].wait(timeout=0.02) def configure_all_channels_spike( diff --git a/pycbsdk/cbhw/packet/packets.py b/pycbsdk/cbhw/packet/packets.py index ae3361d..755066e 100644 --- a/pycbsdk/cbhw/packet/packets.py +++ b/pycbsdk/cbhw/packet/packets.py @@ -377,7 +377,7 @@ class CBPacketNTrodeInfo(CBPacketConfigFixed): "_label", c_char * 16, ), # Label of the Ntrode (null terminated if < 16 characters) - ("ellipses", CBManualUnitMapping * 6 * 5), + ("ellipses", CBManualUnitMapping * 5 * 6), ( "nSite", c_uint16, diff --git a/pycbsdk/cbhw/packet/v311.py b/pycbsdk/cbhw/packet/v311.py index ebe431e..af430ac 100644 --- a/pycbsdk/cbhw/packet/v311.py +++ b/pycbsdk/cbhw/packet/v311.py @@ -107,7 +107,7 @@ class CBPacketChanInfo(CBPacketConfigFixed): ("amplrejneg", c_int16), # Amplitude rejection negative value ("refelecchan", c_uint32), # Software reference electrode channel ("unitmapping", CBManualUnitMapping * 5), # manual unit mapping - ("spkhoops", CBHoop * 5 * 4), # spike hoop sorting set + ("spkhoops", CBHoop * 4 * 5), # spike hoop sorting set ] @property diff --git a/pycbsdk/cbhw/packet/v41.py b/pycbsdk/cbhw/packet/v41.py index 41122cf..0ff7ed8 100644 --- a/pycbsdk/cbhw/packet/v41.py +++ b/pycbsdk/cbhw/packet/v41.py @@ -104,7 +104,7 @@ class CBPacketChanInfo(CBPacketConfigFixed): ("amplrejneg", c_int16), # Amplitude rejection negative value ("refelecchan", c_uint32), # Software reference electrode channel ("unitmapping", CBManualUnitMapping * 5), # manual unit mapping - ("spkhoops", CBHoop * 5 * 4), # spike hoop sorting set + ("spkhoops", CBHoop * 4 * 5), # spike hoop sorting set ] @property diff --git a/pycbsdk/examples/print_rates.py b/pycbsdk/examples/print_rates.py index a118f6c..ee15b78 100644 --- a/pycbsdk/examples/print_rates.py +++ b/pycbsdk/examples/print_rates.py @@ -64,6 +64,7 @@ def main( loglevel: str = "debug", skip_startup: bool = False, update_interval: float = 1.0, + set_hoops: bool = False ): """ Run the application: @@ -87,6 +88,7 @@ def main( :param loglevel: debug, info, or warning :param skip_startup: Skip the initial handshake as well as the attempt to set the device to RUNNING. :param update_interval: Interval between updates. This determines how big the queues can grow. + :param set_hoops: set True to enable hoop-based sorting on channel 2. :return: """ # Handle logger arguments @@ -152,6 +154,23 @@ def main( cbsdk.set_all_channels_disable(nsp_obj, ch_type) cbsdk.set_all_channels_spk_config(nsp_obj, ch_type, "enable", True) + if set_hoops: + spk_hoops = { + 1: { + 1: {"time": 13, "min": -975, "max": -646}, + 2: {"time": 6, "min": 108, "max": 342}, + }, + 2: { + 1: {"time": 21, "min": 675, "max": 1033}, + 2: {"time": 31, "min": -538, "max": -185}, + }, + 3: { + 1: {"time": 17, "min": 481, "max": 820}, + 2: {"time": 35, "min": -23, "max": 262}, + }, + } + cbsdk.set_channel_spk_config(nsp_obj, 2, "hoops", spk_hoops) + # Count the number of FrontEnd | AnalogIn channels. b_spk = [ _ in [CBChannelType.FrontEnd, CBChannelType.AnalogIn]