Skip to content

Commit d201ee4

Browse files
authored
Merge pull request #30 from CerebusOSS/dev
Various QoL fixes and fix for too many chaninfo packets from Gemini
2 parents 318376f + df630e5 commit d201ee4

File tree

4 files changed

+50
-18
lines changed

4 files changed

+50
-18
lines changed

src/pycbsdk/cbhw/device/nsp.py

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,13 @@ def _register_basic_callbacks(self):
346346

347347
self.register_config_callback(CBPacketType.CHANREPAINP, self._handle_chaninfo)
348348
self.register_config_callback(CBPacketType.CHANREPSPKTHR, self._handle_chaninfo)
349+
self.register_config_callback(
350+
CBPacketType.CHANREPNTRODEGROUP, self._handle_chaninfo
351+
)
352+
self.register_config_callback(CBPacketType.CHANREPDISP, self._handle_chaninfo)
353+
self.register_config_callback(
354+
CBPacketType.CHANREPUNITOVERRIDES, self._handle_chaninfo
355+
)
349356

350357
self.register_config_callback(CBPacketType.GROUPREP, self._handle_groupinfo)
351358
self.register_config_callback(CBPacketType.PROCREP, self._handle_procinfo)
@@ -397,8 +404,10 @@ def _handle_sysrep(self, pkt):
397404
def _handle_chaninfo(self, pkt):
398405
# If this config packet is limited in scope then it might have some garbage data in its out-of-scope payload.
399406
# We should update our config, but only the parts that this REP packet is scoped to.
400-
if pkt.header.instrument != self._config["instrument"]:
401-
# Gemini system returns channel info for all instruments.
407+
if (pkt.header.instrument != self._config["instrument"]) or (
408+
pkt.chan > self._config["proc_chans"]
409+
):
410+
# Drop channels that do not belong to this instrument
402411
pass
403412
elif pkt.header.type in [CBPacketType.CHANREP]:
404413
# Full scope; overwrite our config.
@@ -430,8 +439,8 @@ def _handle_chaninfo(self, pkt):
430439
# self._config["channel_infos"][pkt.chan].union.a.moninst = pkt.moninst
431440
# self._config["channel_infos"][pkt.chan].union.a.monchan = pkt.monchan
432441
elif pkt.header.type == CBPacketType.CHANREPSCALE:
433-
self._config["channel_infos"][pkt.chan].scalein = pkt.scalein
434-
self._config["channel_infos"][pkt.chan].scaleout = pkt.scaleout
442+
self._config["channel_infos"][pkt.chan].scalin = pkt.scalin
443+
self._config["channel_infos"][pkt.chan].scalout = pkt.scalout
435444
elif pkt.header.type == CBPacketType.CHANREPDINP:
436445
# TODO: NOTE: Need extra check if this is for serial or digital?
437446
self._config["channel_infos"][pkt.chan].dinpopts = pkt.dinpopts
@@ -443,14 +452,21 @@ def _handle_chaninfo(self, pkt):
443452
elif pkt.header.type == CBPacketType.CHANREPLABEL:
444453
self._config["channel_infos"][pkt.chan].label = pkt.label
445454
self._config["channel_infos"][pkt.chan].userflags = pkt.userflags
446-
elif pkt.header.type == CBPacketType.CHANSETSPKTHR:
447-
# TODO: from CHANREPSPKTHR, .spkthrlevel
455+
elif pkt.header.type in [
456+
CBPacketType.CHANSETSPKTHR,
457+
CBPacketType.CHANREPSPKTHR,
458+
]:
448459
self._config["channel_infos"][pkt.chan].spkthrlevel = pkt.spkthrlevel
449-
460+
elif pkt.header.type == CBPacketType.CHANREPNTRODEGROUP:
461+
# TODO: from use pkt.spkgroup
462+
pass
463+
elif pkt.header.type == CBPacketType.CHANREPDISP:
464+
# TODO: Use .smpdispmin, .smpdispmax, .spkdispmax, .lncdispmax
465+
pass
466+
elif pkt.header.type == CBPacketType.CHANREPUNITOVERRIDES:
467+
# TODO: Use .unitmapping
468+
pass
450469
else:
451-
# TODO: from CHANREPNTRODEGROUP, .spkgroup
452-
# TODO: from CHANREPDISP, .smpdispmin, .smpdispmax, .spkdispmax, .lncdispmax
453-
# TODO: from CHANREPUNITOVERRIDES, .unitmapping
454470
pass
455471
# print(f"handled chaninfo {pkt.chan} of type {hex(pkt.header.type)}")
456472
self._config_events["chaninfo"].set()
@@ -479,6 +495,8 @@ def _handle_nplay(self, pkt):
479495

480496
def _handle_procmon(self, pkt):
481497
arrival_time = time.time()
498+
# Note: There's about 0.57 msec from when procmon is sent to when it is received.
499+
# so we could make sys_time = arrival_time - 570_000e-9
482500
update_interval = max(pkt.header.time - self._monitor_state["time"], 1)
483501
pkt_delta = self.pkts_received - self._monitor_state["pkts_received"]
484502

@@ -493,7 +511,7 @@ def _handle_procmon(self, pkt):
493511
f";\tcounter - {pkt.counter if has_counter else 'N/A'}"
494512
f";\tdelta - {pkt_delta}"
495513
f";\tsent - {pkt.sentpkts}"
496-
f";\trate (pkt/samp) - {pkt_delta/update_interval}"
514+
f";\trate (pkt/samp) - {pkt_delta / update_interval}"
497515
)
498516
self._monitor_state = {
499517
"counter": pkt.counter if has_counter else -1,

src/pycbsdk/cbhw/packet/packets.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ def sizes(self) -> list[int]:
530530
# Convert coords from uint16 to half as many uint32
531531
# TODO: Use numpy from buffer
532532
return struct.unpack(
533-
f"<{len(self.coords)//2}L",
533+
f"<{len(self.coords) // 2}L",
534534
struct.pack(f"<{len(self.coords)}H", self._array),
535535
)
536536

@@ -540,7 +540,7 @@ def sizes(self, insizes: list[int]):
540540
assert n_elems <= (self.max_elements // 2)
541541
# TODO: Use numpy buffer
542542
self.coords = struct.unpack(
543-
f"<{len(insizes)*2}H", struct.pack(f"<{len(insizes)}L", insizes)
543+
f"<{len(insizes) * 2}H", struct.pack(f"<{len(insizes)}L", insizes)
544544
)
545545

546546
@property

src/pycbsdk/examples/group_sample_intervals.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def __init__(self, nchans: int, duration=21.0, t_step=1 / 30_000):
2323

2424
def handle_frame(self, pkt):
2525
if self._write_index < self._buffer.shape[0]:
26-
self._buffer[self._write_index, :] = memoryview(pkt.data[:self._nchans])
26+
self._buffer[self._write_index, :] = memoryview(pkt.data[: self._nchans])
2727
self._ts[self._write_index] = pkt.header.time
2828
self._write_index += 1
2929

@@ -35,7 +35,7 @@ def finish(self):
3535
s_elapsed = ts_elapsed * self._t_step
3636
n_samps = np.sum(b_ts)
3737
print(
38-
f"Collected {n_samps} samples in {s_elapsed} s\t({n_samps/s_elapsed:.2f} Hz)."
38+
f"Collected {n_samps} samples in {s_elapsed} s\t({n_samps / s_elapsed:.2f} Hz)."
3939
)
4040

4141

@@ -83,12 +83,19 @@ def main(
8383
for chtype in [CBChannelType.FrontEnd, CBChannelType.AnalogIn]:
8484
cbsdk.set_all_channels_disable(nsp_obj, chtype)
8585

86-
# Enable channels 1 & 2 at smpgroup. For smpgroup < 5, this also updates the smpfilter.
86+
# Enable first nchans at smpgroup. For smpgroup < 5, this also updates the smpfilter.
8787
for ch in range(1, nchans + 1):
8888
_ = cbsdk.set_channel_config(nsp_obj, ch, "smpgroup", smpgroup)
8989

90+
# Calculate the clock step (I hate this)
91+
if inst_addr and int(inst_addr.split(".")[-1]) in [200, 201, 202, 203, 203]:
92+
# Note: This misses Gemini NSP!
93+
t_step = 1 / 1e9
94+
else:
95+
t_step = 1 / config["sysfreq"]
96+
9097
# Create a dummy app.
91-
app = DummyApp(nchans, duration=duration, t_step=1 / config["sysfreq"])
98+
app = DummyApp(nchans, duration=duration, t_step=t_step)
9299

93100
time.sleep(2.0)
94101

src/pycbsdk/examples/print_rates.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,15 @@ def main(
177177
]
178178
n_chans = sum(b_spk)
179179

180+
# Calculate the clock step (I hate this)
181+
if inst_addr and int(inst_addr.split(".")[-1]) in [200, 201, 202, 203, 203]:
182+
# Note: This misses Gemini NSP!
183+
t_step = 1 / 1e9
184+
else:
185+
t_step = 1 / config["sysfreq"]
186+
180187
# Create the dummy app.
181-
app = DummyApp(n_chans, history=update_interval, tstep=1 / config["sysfreq"])
188+
app = DummyApp(n_chans, history=update_interval, tstep=t_step)
182189
# Register callbacks to update the app's state when appropriate packets are received.
183190
_ = cbsdk.register_spk_callback(nsp_obj, app.update_state)
184191

0 commit comments

Comments
 (0)