legend-daq2lh5 1.5.0__py3-none-any.whl → 1.6.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,52 +1,145 @@
1
1
  from __future__ import annotations
2
2
 
3
- import fcutils
3
+ import copy
4
+ import logging
5
+ from typing import Any
6
+
7
+ import lgdo
8
+ from fcio import FCIO
4
9
 
5
10
  from ..data_decoder import DataDecoder
6
- from ..raw_buffer import RawBuffer
11
+
12
+ log = logging.getLogger(__name__)
13
+
14
+ # status.data[i].reqid contains the card type in 0xff00 and the index within
15
+ # a type group in 0xff
16
+ # 0 is readout master
17
+ # if bit 0x1000 is set: trigger card
18
+ # if bit 0x2000 is set: adc card
19
+ # if bit 0x4000 is set: submaster card
20
+
21
+ fc_status_decoded_values = {
22
+ "packet_id": {"dtype": "uint32", "description": "Packet index in file."},
23
+ "status": {
24
+ "dtype": "bool",
25
+ "description": "True: Ok, False: Errors occurred, check card-wise status.",
26
+ },
27
+ "fpga_time": {
28
+ "dtype": "float32",
29
+ "units": "s",
30
+ "description": "The clock in the fpga of the highest-level card.",
31
+ },
32
+ "server_time": {
33
+ "dtype": "float64",
34
+ "units": "s",
35
+ "description": "The server time when the status was checked.",
36
+ },
37
+ "fpga_start_time": {
38
+ "dtype": "float64",
39
+ "units": "s",
40
+ "description": "The start time of the run.",
41
+ },
42
+ # FC card-wise list DAQ errors during data taking
43
+ "id": {
44
+ "dtype": "uint32",
45
+ "description": "The card id (reqid) when checking the status. Don't confuse with the card address.",
46
+ },
47
+ "eventnumber": {
48
+ "dtype": "uint32",
49
+ "description": "The eventcounter when the status was requested.",
50
+ },
51
+ "fpga_time_nsec": {
52
+ "dtype": "uint32",
53
+ "units": "ns",
54
+ "description": "The clock in the fpga of the highest-level card.",
55
+ },
56
+ "n_total_errors": {
57
+ "dtype": "uint32",
58
+ "description": "The sum of all error counter of all cards.",
59
+ },
60
+ "n_environment_errors": {
61
+ "dtype": "uint32",
62
+ "description": "The sum of all environment sensor errors.",
63
+ },
64
+ "n_cti_errors": {
65
+ "dtype": "uint32",
66
+ "description": "The sum of all CTI connection errors.",
67
+ },
68
+ "n_link_errors": {
69
+ "dtype": "uint32",
70
+ "description": "The sum of all trigger link errors.",
71
+ },
72
+ "n_other_errors": {
73
+ "dtype": "uint32",
74
+ "datatype": "array_of_equalsized_arrays<1,1>{real}",
75
+ "length": 5,
76
+ "description": "The sum of other errors.",
77
+ },
78
+ "mb_temps": {
79
+ "dtype": "int32",
80
+ "units": "mC",
81
+ "datatype": "array_of_equalsized_arrays<1,1>{real}",
82
+ "length": 5,
83
+ "description": "The temperatures measured by sensors on the motherboard.",
84
+ },
85
+ "mb_voltages": {
86
+ "dtype": "int32",
87
+ "units": "mV",
88
+ "datatype": "array_of_equalsized_arrays<1,1>{real}",
89
+ "length": 6,
90
+ "description": "The supply voltages of the motherboard.",
91
+ },
92
+ "mb_current": {
93
+ "dtype": "int32",
94
+ "units": "mA",
95
+ "description": "The current draw of the motherboard.",
96
+ },
97
+ "mb_humidity": {
98
+ "dtype": "int32",
99
+ "units": "o/oo",
100
+ "description": "The humidity in permille measured on the motherboard.",
101
+ },
102
+ "adc_temps": {
103
+ "dtype": "int32",
104
+ "units": "mC",
105
+ "datatype": "array<1>{array<1>{real}}",
106
+ "length_guess": 2, # max number of daughter cards - only for adc cards
107
+ "description": "If the card has adc daughter (piggy) boards mounted, each daughter has a temperature sensor.",
108
+ },
109
+ "cti_links": {
110
+ "dtype": "uint32",
111
+ "datatype": "array<1>{array<1>{real}}", # vector of vectors
112
+ "length_guess": 4,
113
+ "description": "CTI debugging values, for experts only.",
114
+ },
115
+ "link_states": {
116
+ "dtype": "uint32",
117
+ "datatype": "array<1>{array<1>{real}}", # vector of vectors
118
+ "length_guess": 256, # 256*max number of boards
119
+ "description": "Trigger link debugging values, for experts only.",
120
+ },
121
+ }
122
+
123
+
124
+ def get_key(streamid, reqid):
125
+ return (streamid & 0xFFFF) * 1000000 + (reqid & 0xFFFF)
126
+
127
+
128
+ def get_fcid(key: int) -> int:
129
+ return int(key // 10000000)
130
+
131
+
132
+ def get_reqid(key: int) -> int:
133
+ return int(key % 1000000)
7
134
 
8
135
 
9
136
  class FCStatusDecoder(DataDecoder):
10
137
  """Decode FlashCam digitizer status data."""
11
138
 
12
139
  def __init__(self, *args, **kwargs) -> None:
13
- self.decoded_values = {
14
- # 0: Errors occurred, 1: no errors
15
- "status": {"dtype": "int32"},
16
- # fc250 seconds, microseconds, dummy, startsec startusec
17
- "statustime": {"dtype": "float32", "units": "s"},
18
- # CPU seconds, microseconds, dummy, startsec startusec
19
- "cputime": {"dtype": "float64", "units": "s"},
20
- # fc250 seconds, microseconds, dummy, startsec startusec
21
- "startoffset": {"dtype": "float32", "units": "s"},
22
- # Total number of cards (number of status data to follow)
23
- "cards": {"dtype": "int32"},
24
- # Size of each status data
25
- "size": {"dtype": "int32"},
26
- # FC card-wise environment status
27
- "environment": {
28
- # Array contents:
29
- # [0-4] Temps in mDeg
30
- # [5-10] Voltages in mV
31
- # 11 main current in mA
32
- # 12 humidity in o/oo
33
- # [13-14] Temps from adc cards in mDeg
34
- # FIXME: change to a table?
35
- "dtype": "uint32",
36
- "datatype": "array_of_equalsized_arrays<1,1>{real}",
37
- "length": 16,
38
- },
39
- # FC card-wise list DAQ errors during data taking
40
- "totalerrors": {"dtype": "uint32"},
41
- "enverrors": {"dtype": "uint32"},
42
- "ctierrors": {"dtype": "uint32"},
43
- "linkerrors": {"dtype": "uint32"},
44
- "othererrors": {
45
- "dtype": "uint32",
46
- "datatype": "array_of_equalsized_arrays<1,1>{real}",
47
- "length": 5,
48
- },
49
- }
140
+ self.key_list = []
141
+ self.max_rows_in_packet = 0
142
+ self.decoded_values = copy.deepcopy(fc_status_decoded_values)
50
143
  """Default FlashCam status decoded values.
51
144
 
52
145
  Warning
@@ -55,37 +148,112 @@ class FCStatusDecoder(DataDecoder):
55
148
  """
56
149
  super().__init__(*args, **kwargs)
57
150
 
151
+ def set_fcio_stream(self, fcio_stream: FCIO) -> None:
152
+ """Access ``FCIOConfig`` members once when each file is opened.
153
+
154
+ Parameters
155
+ ----------
156
+ fcio_stream
157
+ extracted via :meth:`~.fc_config_decoder.FCConfigDecoder.decode_config`.
158
+ """
159
+
160
+ n_cards = (
161
+ fcio_stream.config.mastercards
162
+ + fcio_stream.config.triggercards
163
+ + fcio_stream.config.adccards
164
+ )
165
+ self.max_rows_in_packet = n_cards
166
+
167
+ # the number of master cards is the sum of top and sub masters,
168
+ # if there is more than one, the first is the top master
169
+ # the rest is a sub master card.
170
+ for i in range(fcio_stream.config.mastercards):
171
+ if i == 0:
172
+ key = get_key(fcio_stream.config.streamid, 0)
173
+ else:
174
+ key = get_key(fcio_stream.config.streamid, 0x4000 + i - 1)
175
+ self.key_list.append(key)
176
+
177
+ for i in range(fcio_stream.config.triggercards):
178
+ key = get_key(fcio_stream.config.streamid, 0x1000 + i)
179
+ self.key_list.append(key)
180
+
181
+ for i in range(fcio_stream.config.adccards):
182
+ key = get_key(fcio_stream.config.streamid, 0x2000 + i)
183
+ self.key_list.append(key)
184
+
185
+ def get_key_lists(self) -> list[list[int | str]]:
186
+ return [copy.deepcopy(self.key_list)]
187
+
188
+ def get_decoded_values(self, key: int | str = None) -> dict[str, dict[str, Any]]:
189
+ # FC uses the same values for all channels
190
+ return self.decoded_values
191
+
192
+ def get_max_rows_in_packet(self) -> int:
193
+ return self.max_rows_in_packet
194
+
58
195
  def decode_packet(
59
- self, fcio: fcutils.fcio, status_rb: RawBuffer, packet_id: int
196
+ self,
197
+ fcio: FCIO,
198
+ status_rbkd: lgdo.Table | dict[int, lgdo.Table],
199
+ packet_id: int,
60
200
  ) -> bool:
61
- # aliases for brevity
62
- tbl = status_rb.lgdo
63
- ii = status_rb.loc
201
+ """Access ``FCIOStatus`` members for each status packet in the DAQ file.
64
202
 
65
- # status -- 0: Errors occurred, 1: no errors
66
- tbl["status"].nda[ii] = fcio.status
203
+ Parameters
204
+ ----------
205
+ fcio
206
+ The interface to the ``fcio`` data. Enters this function after a
207
+ call to ``fcio.get_record()`` so that data for `packet_id` ready to
208
+ be read out.
209
+ status_rbkd
210
+ A single table for reading out all data, or a dictionary of tables
211
+ keyed by card number.
212
+ packet_id
213
+ The index of the packet in the `fcio` stream. Incremented by
214
+ :class:`~.fc.fc_streamer.FCStreamer`.
67
215
 
68
- # times
69
- tbl["statustime"].nda[ii] = fcio.statustime[0] + fcio.statustime[1] / 1e6
70
- tbl["cputime"].nda[ii] = fcio.statustime[2] + fcio.statustime[3] / 1e6
71
- tbl["startoffset"].nda[ii] = fcio.statustime[5] + fcio.statustime[6] / 1e6
216
+ Returns
217
+ -------
218
+ any_full
219
+ TODO
220
+ """
221
+ any_full = False
222
+ for card_data in fcio.status.data:
223
+ key = get_key(fcio.config.streamid, card_data.reqid)
224
+ if key not in status_rbkd:
225
+ continue
72
226
 
73
- # Total number of cards (number of status data to follow)
74
- tbl["cards"].nda[ii] = fcio.cards
227
+ tbl = status_rbkd[key].lgdo
228
+ loc = status_rbkd[key].loc
75
229
 
76
- # Size of each status data
77
- tbl["size"].nda[ii] = fcio.size
230
+ tbl["packet_id"].nda[loc] = packet_id
231
+ tbl["status"].nda[loc] = fcio.status.status
78
232
 
79
- # FC card-wise environment status (temp., volt., hum., ...)
80
- tbl["environment"].nda[ii][:] = fcio.environment
233
+ # times
234
+ tbl["fpga_time"].nda[loc] = fcio.status.fpga_time_sec
235
+ tbl["server_time"].nda[loc] = fcio.status.unix_time_utc_sec
236
+ tbl["fpga_start_time"].nda[loc] = fcio.status.fpga_start_time_sec
81
237
 
82
- # FC card-wise list DAQ errors during data taking
83
- tbl["totalerrors"].nda[ii] = fcio.totalerrors
84
- tbl["linkerrors"].nda[ii] = fcio.linkerrors
85
- tbl["ctierrors"].nda[ii] = fcio.ctierrors
86
- tbl["enverrors"].nda[ii] = fcio.enverrors
87
- tbl["othererrors"].nda[ii][:] = fcio.othererrors
238
+ # per card information
239
+ tbl["id"].nda[loc] = card_data.reqid
240
+ tbl["eventnumber"].nda[loc] = card_data.eventno
241
+ tbl["fpga_time_nsec"].nda[loc] = card_data.fpga_time_nsec
242
+ tbl["n_total_errors"].nda[loc] = card_data.totalerrors
243
+ tbl["n_environment_errors"].nda[loc] = card_data.enverrors
244
+ tbl["n_cti_errors"].nda[loc] = card_data.ctierrors
245
+ tbl["n_other_errors"].nda[loc][:] = card_data.othererrors
246
+ tbl["mb_temps"].nda[loc][:] = card_data.mainboard_temperatures_mC
247
+ tbl["mb_voltages"].nda[loc][:] = card_data.mainboard_voltages_mV
248
+ tbl["mb_current"].nda[loc] = card_data.mainboard_current_mA
249
+ tbl["mb_humidity"].nda[loc] = card_data.mainboard_humiditiy_permille
250
+ tbl["adc_temps"]._set_vector_unsafe(
251
+ loc, card_data.daughterboard_temperatures_mC
252
+ )
253
+ tbl["cti_links"]._set_vector_unsafe(loc, card_data.ctilinks)
254
+ tbl["link_states"]._set_vector_unsafe(loc, card_data.linkstates)
88
255
 
89
- status_rb.loc += 1
256
+ status_rbkd[key].loc += 1
257
+ any_full |= status_rbkd[key].is_full()
90
258
 
91
- return status_rb.loc >= len(tbl)
259
+ return bool(any_full)
daq2lh5/fc/fc_streamer.py CHANGED
@@ -2,13 +2,16 @@ from __future__ import annotations
2
2
 
3
3
  import logging
4
4
 
5
- import fcutils
5
+ import lgdo
6
+ from fcio import FCIO, Tags
6
7
 
7
8
  from ..data_decoder import DataDecoder
8
9
  from ..data_streamer import DataStreamer
9
10
  from ..raw_buffer import RawBuffer, RawBufferLibrary
10
11
  from .fc_config_decoder import FCConfigDecoder
11
12
  from .fc_event_decoder import FCEventDecoder
13
+ from .fc_eventheader_decoder import FCEventHeaderDecoder
14
+ from .fc_fsp_decoder import FSPConfigDecoder, FSPEventDecoder, FSPStatusDecoder
12
15
  from .fc_status_decoder import FCStatusDecoder
13
16
 
14
17
  log = logging.getLogger(__name__)
@@ -16,30 +19,49 @@ log = logging.getLogger(__name__)
16
19
 
17
20
  class FCStreamer(DataStreamer):
18
21
  """
19
- Decode FlashCam data, using the ``fcutils`` package to handle file access,
22
+ Decode FlashCam data, using the ``fcio`` package to handle file access,
20
23
  and the FlashCam data decoders to save the results and write to output.
21
24
  """
22
25
 
23
26
  def __init__(self) -> None:
24
27
  super().__init__()
25
- self.fcio = None
28
+ self.fcio = FCIO()
26
29
  self.config_decoder = FCConfigDecoder()
27
30
  self.status_decoder = FCStatusDecoder()
28
31
  self.event_decoder = FCEventDecoder()
29
- self.event_tables = {}
32
+ self.eventheader_decoder = FCEventHeaderDecoder()
33
+
34
+ self.fsp_config_decoder = FSPConfigDecoder()
35
+ self.fsp_event_decoder = FSPEventDecoder()
36
+ self.fsp_status_decoder = FSPStatusDecoder()
37
+
30
38
  self.event_rbkd = None
31
- self.status_rb = None
39
+ self.eventheader_rbkd = None
40
+ self.status_rbkd = None
41
+
42
+ self.fsp_config_rbkd = None
43
+ self.fsp_event_rbkd = None
44
+ self.fsp_status_rbkd = None
45
+
46
+ self.fcio_bytes_read = 0
47
+ self.fcio_bytes_skipped = 0
32
48
 
33
49
  def get_decoder_list(self) -> list[DataDecoder]:
34
50
  dec_list = []
35
51
  dec_list.append(self.config_decoder)
36
52
  dec_list.append(self.status_decoder)
37
53
  dec_list.append(self.event_decoder)
54
+ dec_list.append(self.eventheader_decoder)
55
+
56
+ dec_list.append(self.fsp_config_decoder)
57
+ dec_list.append(self.fsp_event_decoder)
58
+ dec_list.append(self.fsp_status_decoder)
59
+
38
60
  return dec_list
39
61
 
40
62
  def open_stream(
41
63
  self,
42
- fcio_filename: str,
64
+ fcio_peer: str,
43
65
  rb_lib: RawBufferLibrary = None,
44
66
  buffer_size: int = 8192,
45
67
  chunk_mode: str = "any_full",
@@ -54,22 +76,28 @@ class FCStreamer(DataStreamer):
54
76
  Returns
55
77
  -------
56
78
  header_data
57
- a list of length 1 containing the raw buffer holding the
58
- :class:`~.fc_config_decoder.FCConfig` table.
79
+ a list of length 2 containing the raw buffer holding the
80
+ :class:`~.fc_config_decoder.FCConfig` table and
81
+ optionally the :class:`~.fsp_decoder.FSPConfig` table.
59
82
  """
60
- self.fcio = fcutils.fcio(fcio_filename)
61
- self.n_bytes_read = 0
83
+ self.fcio.open(fcio_peer) # using defaults
84
+ self.n_bytes_read = self.fcio.read_bytes() + self.fcio.skipped_bytes()
85
+
86
+ # read in file header (config) info, returns an lgdo.Struct
87
+ fc_config = self.config_decoder.decode_config(self.fcio)
88
+ config_lgdos = [fc_config]
89
+ if self.fcio.fsp:
90
+ config_lgdos.append(self.fsp_config_decoder.decode_config(self.fcio))
62
91
 
63
- # read in file header (config) info
64
- fc_config = self.config_decoder.decode_config(
65
- self.fcio
66
- ) # returns an lgdo.Struct
67
- self.event_decoder.set_file_config(fc_config)
68
- self.n_bytes_read += 11 * 4 # there are 11 ints in the fcio_config struct
92
+ self.status_decoder.set_fcio_stream(self.fcio)
93
+ self.event_decoder.set_fcio_stream(self.fcio)
94
+ self.eventheader_decoder.set_fcio_stream(self.fcio)
95
+ self.fsp_event_decoder.set_fcio_stream(self.fcio)
96
+ self.fsp_status_decoder.set_fcio_stream(self.fcio)
69
97
 
70
98
  # initialize the buffers in rb_lib. Store them for fast lookup
71
99
  super().open_stream(
72
- fcio_filename,
100
+ fcio_peer,
73
101
  rb_lib,
74
102
  buffer_size=buffer_size,
75
103
  chunk_mode=chunk_mode,
@@ -78,91 +106,140 @@ class FCStreamer(DataStreamer):
78
106
  if rb_lib is None:
79
107
  rb_lib = self.rb_lib
80
108
 
81
- # get the status rb_list and pull out its first element
82
- status_rb_list = (
83
- rb_lib["FCStatusDecoder"] if "FCStatusDecoder" in rb_lib else None
109
+ # event and status allow offer key_lists
110
+ self.status_rbkd = (
111
+ rb_lib["FCStatusDecoder"].get_keyed_dict()
112
+ if "FCStatusDecoder" in rb_lib
113
+ else None
84
114
  )
85
- if status_rb_list is not None:
86
- if len(status_rb_list) != 1:
87
- log.warning(
88
- f"status_rb_list had length {len(status_rb_list)}, ignoring all but the first"
89
- )
90
- if len(status_rb_list) == 0:
91
- self.status_rb = None
92
- else:
93
- self.status_rb = status_rb_list[0]
115
+
94
116
  self.event_rbkd = (
95
117
  rb_lib["FCEventDecoder"].get_keyed_dict()
96
118
  if "FCEventDecoder" in rb_lib
97
119
  else None
98
120
  )
99
121
 
122
+ self.eventheader_rbkd = (
123
+ rb_lib["FCEventHeaderDecoder"].get_keyed_dict()
124
+ if "FCEventHeaderDecoder" in rb_lib
125
+ else None
126
+ )
127
+
128
+ self.fsp_event_rbkd = (
129
+ rb_lib["FSPEventDecoder"].get_keyed_dict()
130
+ if "FSPEventDecoder" in rb_lib
131
+ else None
132
+ )
133
+
134
+ self.fsp_status_rbkd = (
135
+ rb_lib["FSPStatusDecoder"].get_keyed_dict()
136
+ if "FSPStatusDecoder" in rb_lib
137
+ else None
138
+ )
100
139
  # set up data loop variables
101
140
  self.packet_id = 0 # for storing packet order in output tables
102
141
 
103
- if "FCConfigDecoder" in rb_lib:
104
- config_rb_list = rb_lib["FCConfigDecoder"]
105
- if len(config_rb_list) != 1:
106
- log.warning(
107
- f"config_rb_list had length {len(config_rb_list)}, ignoring all but the first"
142
+ rbs = []
143
+ for config_decoder, config_lgdo in zip(
144
+ ["FCConfigDecoder", "FSPConfigDecoder"], config_lgdos
145
+ ):
146
+ if config_decoder in rb_lib:
147
+ config_rb_list = rb_lib[config_decoder]
148
+ if len(config_rb_list) != 1:
149
+ log.warning(
150
+ f"config_rb_list for {config_decoder} had length {len(config_rb_list)}, "
151
+ "ignoring all but the first"
152
+ )
153
+ rb = config_rb_list[0]
154
+ else:
155
+ rb = RawBuffer(lgdo=config_lgdo)
156
+
157
+ # TODO: not clear if this workaround is needed, or a bug:
158
+ # It seems like the `loc` of the RawBuffer is used as `len`
159
+ # for individual elements in a `lgdo.Struct` while writing.
160
+ # Search for longest and use as `loc` attr.
161
+ if isinstance(config_lgdo, lgdo.Struct):
162
+ max_length = max(
163
+ [
164
+ len(entry) if hasattr(entry, "__len__") else 1
165
+ for entry in config_lgdo.values()
166
+ ]
108
167
  )
109
- rb = config_rb_list[0]
110
- else:
111
- rb = RawBuffer(lgdo=fc_config)
112
- rb.loc = 1 # we have filled this buffer
113
- return [rb]
168
+ rb.loc = max_length
169
+ rbs.append(rb)
170
+ return rbs
114
171
 
115
172
  def close_stream(self) -> None:
116
- self.fcio = None # should cause close file in fcio.__dealloc__
173
+ self.fcio.close()
117
174
 
118
175
  def read_packet(self) -> bool:
119
- rc = self.fcio.get_record()
120
- if rc == 0:
121
- return False # no more data
122
-
123
- self.packet_id += 1
124
176
 
125
- if rc == 1: # config (header) data
126
- log.warning(
127
- f"got a header after start of run? n_bytes_read = {self.n_bytes_read}"
128
- )
129
- self.n_bytes_read += 11 * 4 # there are 11 ints in the fcio_config struct
130
- return True
177
+ if not self.fcio.get_record():
178
+ return False # no more data
131
179
 
132
- elif rc == 2: # calib record -- no longer supported
133
- log.warning(
134
- f"warning: got a calib record? n_bytes_read = {self.n_bytes_read}"
135
- )
136
- return True
180
+ # The fcio stream processor (FSP) prepends records to the corresponding
181
+ # FCIO records. The fcio library parses these separate records,
182
+ # which requires an additional call to get_record().
183
+ # Both records are treated as one packet, so their packet_id is shared.
184
+ if self.fcio.tag in [Tags.FSPConfig, Tags.FSPEvent, Tags.FSPStatus]:
185
+ if not self.fcio.get_record():
186
+ self.n_bytes_read = self.fcio.read_bytes() + self.fcio.skipped_bytes()
187
+ log.error(
188
+ f"FCIO stream ended early with a {Tags.str(self.fcio.tag)} and n_bytes_read = {self.n_bytes_read}"
189
+ )
190
+ return False
137
191
 
138
- # FIXME: push to a buffer of skipped packets?
139
- # FIXME: need to at least update n_bytes?
140
- elif rc == 5: # recevent
192
+ self.packet_id += 1
193
+ # records or fields in records unknown to fcio are read but not parsed,
194
+ # and tracked in skipped_bytes
195
+ self.n_bytes_read = self.fcio.read_bytes() + self.fcio.skipped_bytes()
196
+
197
+ # FCIOConfigs contains header data (lengths) required to access
198
+ # (Sparse)Event(Header) records.
199
+ # The protocol allows updates of these settings within a datastream.
200
+ # Concatenating of FCIO streams is supported here only if the FCIOConfig
201
+ # is the same.
202
+ if self.fcio.tag == Tags.Config or self.fcio.tag == Tags.FSPConfig:
141
203
  log.warning(
142
- f"got a RecEvent packet -- skipping? n_bytes_read = {self.n_bytes_read}"
204
+ f"got an {Tags.str(self.fcio.tag)} after start of run? "
205
+ f"n_bytes_read = {self.n_bytes_read}"
143
206
  )
144
- # sizeof(fcio_recevent): (6 + 3*10 + 1*2304 + 3*4000)*4
145
- self.n_bytes_read += 57360
146
- return True
147
207
 
148
- # Status record
149
- elif rc == 4:
150
- if self.status_rb is not None:
208
+ elif self.fcio.tag == Tags.Status:
209
+ if self.status_rbkd is not None:
151
210
  self.any_full |= self.status_decoder.decode_packet(
152
- self.fcio, self.status_rb, self.packet_id
211
+ self.fcio, self.status_rbkd, self.packet_id
212
+ )
213
+ if self.fcio.fsp and self.fsp_status_rbkd is not None:
214
+ self.any_full |= self.fsp_status_decoder.decode_packet(
215
+ self.fcio, self.fsp_status_rbkd, self.packet_id
153
216
  )
154
- # sizeof(fcio_status): (3 + 10 + 256*(10 + 9 + 16 + 4 + 256))*4
155
- self.n_bytes_read += 302132
156
- return True
157
217
 
158
- # Event or SparseEvent record
159
- elif rc == 3 or rc == 6:
218
+ elif self.fcio.tag == Tags.Event or self.fcio.tag == Tags.SparseEvent:
160
219
  if self.event_rbkd is not None:
161
220
  self.any_full |= self.event_decoder.decode_packet(
162
221
  self.fcio, self.event_rbkd, self.packet_id
163
222
  )
164
- # sizeof(fcio_event): (5 + 3*10 + 1)*4 + numtraces*(1 + nsamples+2)*2
165
- self.n_bytes_read += (
166
- 144 + self.fcio.numtraces * (self.fcio.nsamples + 3) * 2
223
+ if self.fcio.fsp and self.fsp_event_rbkd is not None:
224
+ self.any_full |= self.fsp_event_decoder.decode_packet(
225
+ self.fcio, self.fsp_event_rbkd, self.packet_id, False
226
+ )
227
+
228
+ elif self.fcio.tag == Tags.EventHeader:
229
+ if self.eventheader_rbkd is not None:
230
+ self.any_full |= self.eventheader_decoder.decode_packet(
231
+ self.fcio, self.eventheader_rbkd, self.packet_id
232
+ )
233
+ if self.fcio.fsp and self.fsp_event_rbkd is not None:
234
+ self.any_full |= self.fsp_event_decoder.decode_packet(
235
+ self.fcio, self.fsp_event_rbkd, self.packet_id, True
236
+ )
237
+
238
+ # FIXME: push to a buffer of skipped packets?
239
+ else: # unknown record
240
+ log.warning(
241
+ f"skipping unsupported record {Tags.str(self.fcio.tag)}. "
242
+ f"n_bytes_read = {self.n_bytes_read}"
167
243
  )
168
- return True
244
+
245
+ return True
@@ -92,7 +92,6 @@ class LLAMAHeaderDecoder(DataDecoder): # DataDecoder currently unused
92
92
  log.debug(
93
93
  f"{self.number_chOpen} channels open, each config {self.length_econf} bytes long"
94
94
  )
95
-
96
95
  n_bytes_read += self.__decode_channel_configs(f_in)
97
96
 
98
97
  # print(self.channel_configs[0]["maw3_offset"])
@@ -151,7 +150,7 @@ class LLAMAHeaderDecoder(DataDecoder): # DataDecoder currently unused
151
150
  # print("reading in channel config {}".format(i))
152
151
 
153
152
  channel = f_in.read(self.length_econf)
154
- n_bytes_read += self.length_econf
153
+ n_bytes_read += int(self.length_econf)
155
154
  ch_dpf = channel[16:32]
156
155
  evt_data_32 = np.frombuffer(channel, dtype=np.uint32)
157
156
  evt_data_dpf = np.frombuffer(ch_dpf, dtype=np.float64)
@@ -295,7 +295,7 @@ class ORSIS3316WaveformDecoder(OrcaDecoder):
295
295
  key_lists = []
296
296
  for key in self.decoded_values.keys():
297
297
  key_lists.append([key])
298
- return [key_lists]
298
+ return key_lists
299
299
 
300
300
  def get_decoded_values(self, key: int = None) -> dict[str, Any]:
301
301
  if key is None: