legend-daq2lh5 1.4.3__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.
- daq2lh5/_version.py +2 -2
- daq2lh5/buffer_processor/buffer_processor.py +8 -5
- daq2lh5/buffer_processor/lh5_buffer_processor.py +8 -5
- daq2lh5/build_raw.py +4 -3
- daq2lh5/data_decoder.py +1 -3
- daq2lh5/data_streamer.py +73 -28
- daq2lh5/fc/fc_config_decoder.py +99 -28
- daq2lh5/fc/fc_event_decoder.py +128 -138
- daq2lh5/fc/fc_eventheader_decoder.py +311 -0
- daq2lh5/fc/fc_fsp_decoder.py +885 -0
- daq2lh5/fc/fc_status_decoder.py +231 -63
- daq2lh5/fc/fc_streamer.py +153 -76
- daq2lh5/llama/llama_event_decoder.py +10 -0
- daq2lh5/llama/llama_header_decoder.py +43 -3
- daq2lh5/llama/llama_streamer.py +4 -1
- daq2lh5/orca/orca_digitizers.py +1 -1
- daq2lh5/orca/orca_fcio.py +405 -0
- daq2lh5/orca/orca_flashcam.py +7 -4
- daq2lh5/orca/orca_header.py +7 -2
- daq2lh5/orca/orca_packet.py +10 -0
- daq2lh5/orca/orca_run_decoder.py +6 -6
- daq2lh5/orca/orca_streamer.py +28 -10
- daq2lh5/orca/skim_orca_file.py +54 -0
- daq2lh5/raw_buffer.py +15 -2
- {legend_daq2lh5-1.4.3.dist-info → legend_daq2lh5-1.6.1.dist-info}/METADATA +14 -15
- legend_daq2lh5-1.6.1.dist-info/RECORD +46 -0
- {legend_daq2lh5-1.4.3.dist-info → legend_daq2lh5-1.6.1.dist-info}/WHEEL +1 -1
- legend_daq2lh5-1.6.1.dist-info/entry_points.txt +3 -0
- legend_daq2lh5-1.4.3.dist-info/RECORD +0 -42
- legend_daq2lh5-1.4.3.dist-info/entry_points.txt +0 -2
- {legend_daq2lh5-1.4.3.dist-info → legend_daq2lh5-1.6.1.dist-info/licenses}/LICENSE +0 -0
- {legend_daq2lh5-1.4.3.dist-info → legend_daq2lh5-1.6.1.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,10 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
import datetime
|
3
4
|
import io
|
4
5
|
import logging
|
6
|
+
import os
|
7
|
+
import re
|
5
8
|
from typing import Any, Dict
|
6
9
|
|
7
10
|
import lgdo
|
@@ -15,6 +18,25 @@ log = logging.getLogger(__name__)
|
|
15
18
|
LLAMA_Channel_Configs_t = Dict[int, Dict[str, Any]]
|
16
19
|
|
17
20
|
|
21
|
+
def parse_filename_for_timestamp(f_in_name: str) -> float:
|
22
|
+
"""take a filename; return the unixtime parsed from the filename; 0 if impossible."""
|
23
|
+
filename = os.path.basename(f_in_name)
|
24
|
+
if match := re.fullmatch(r".*(\d{8})[-T](\d{6})(Z?).*", filename):
|
25
|
+
tsymd = match.group(1)
|
26
|
+
tshms = match.group(2)
|
27
|
+
utc: bool = True if match.group(3) == "Z" else False
|
28
|
+
when_file: datetime.datetime = datetime.datetime.strptime(
|
29
|
+
tsymd + tshms, "%Y%m%d%H%M%S"
|
30
|
+
) # naive datetime object
|
31
|
+
if utc:
|
32
|
+
when_file = when_file.replace(
|
33
|
+
tzinfo=datetime.timezone.utc
|
34
|
+
) # make it aware; UTC. Naive is treated as local
|
35
|
+
return when_file.timestamp()
|
36
|
+
else:
|
37
|
+
return 0
|
38
|
+
|
39
|
+
|
18
40
|
class LLAMAHeaderDecoder(DataDecoder): # DataDecoder currently unused
|
19
41
|
"""Decode llamaDAQ header data.
|
20
42
|
|
@@ -31,7 +53,7 @@ class LLAMAHeaderDecoder(DataDecoder): # DataDecoder currently unused
|
|
31
53
|
self.config = lgdo.Struct()
|
32
54
|
self.channel_configs = None
|
33
55
|
|
34
|
-
def decode_header(self, f_in: io.BufferedReader) -> lgdo.Struct:
|
56
|
+
def decode_header(self, f_in: io.BufferedReader, f_in_name: str) -> lgdo.Struct:
|
35
57
|
n_bytes_read = 0
|
36
58
|
|
37
59
|
f_in.seek(0) # should be there anyhow, but re-set if not
|
@@ -55,13 +77,21 @@ class LLAMAHeaderDecoder(DataDecoder): # DataDecoder currently unused
|
|
55
77
|
self.length_econf = evt_data_16[5]
|
56
78
|
self.number_chOpen = evt_data_32[3]
|
57
79
|
|
80
|
+
self.global_configs = {}
|
81
|
+
|
82
|
+
# currently pulled from filename with 1s precision.
|
83
|
+
# change if we have it in the llamaDAQ file's header
|
84
|
+
self.global_configs["initial_timestamp"] = parse_filename_for_timestamp(
|
85
|
+
f_in_name
|
86
|
+
)
|
87
|
+
self.global_configs["initial_timestamp_accuracy"] = 1.0 # in seconds
|
88
|
+
|
58
89
|
log.debug(
|
59
90
|
f"File version: {self.version_major}.{self.version_minor}.{self.version_patch}"
|
60
91
|
)
|
61
92
|
log.debug(
|
62
93
|
f"{self.number_chOpen} channels open, each config {self.length_econf} bytes long"
|
63
94
|
)
|
64
|
-
|
65
95
|
n_bytes_read += self.__decode_channel_configs(f_in)
|
66
96
|
|
67
97
|
# print(self.channel_configs[0]["maw3_offset"])
|
@@ -72,6 +102,13 @@ class LLAMAHeaderDecoder(DataDecoder): # DataDecoder currently unused
|
|
72
102
|
self.config.add_field("version_patch", lgdo.Scalar(self.version_patch))
|
73
103
|
self.config.add_field("length_econf", lgdo.Scalar(self.length_econf))
|
74
104
|
self.config.add_field("number_chOpen", lgdo.Scalar(self.number_chOpen))
|
105
|
+
self.config.add_field(
|
106
|
+
"initial_timestamp", lgdo.Scalar(self.global_configs["initial_timestamp"])
|
107
|
+
)
|
108
|
+
self.config.add_field(
|
109
|
+
"initial_timestamp_accuracy",
|
110
|
+
lgdo.Scalar(self.global_configs["initial_timestamp_accuracy"]),
|
111
|
+
)
|
75
112
|
|
76
113
|
for fch_id, fch_content in self.channel_configs.items():
|
77
114
|
fch_lgdo = lgdo.Struct()
|
@@ -88,6 +125,9 @@ class LLAMAHeaderDecoder(DataDecoder): # DataDecoder currently unused
|
|
88
125
|
def get_channel_configs(self) -> LLAMA_Channel_Configs_t:
|
89
126
|
return self.channel_configs
|
90
127
|
|
128
|
+
def get_global_configs(self) -> dict[str, Any]:
|
129
|
+
return self.global_configs
|
130
|
+
|
91
131
|
def __decode_channel_configs(self, f_in: io.BufferedReader) -> int:
|
92
132
|
"""Reads the metadata.
|
93
133
|
|
@@ -110,7 +150,7 @@ class LLAMAHeaderDecoder(DataDecoder): # DataDecoder currently unused
|
|
110
150
|
# print("reading in channel config {}".format(i))
|
111
151
|
|
112
152
|
channel = f_in.read(self.length_econf)
|
113
|
-
n_bytes_read += self.length_econf
|
153
|
+
n_bytes_read += int(self.length_econf)
|
114
154
|
ch_dpf = channel[16:32]
|
115
155
|
evt_data_32 = np.frombuffer(channel, dtype=np.uint32)
|
116
156
|
evt_data_dpf = np.frombuffer(ch_dpf, dtype=np.float64)
|
daq2lh5/llama/llama_streamer.py
CHANGED
@@ -53,12 +53,15 @@ class LLAMAStreamer(DataStreamer):
|
|
53
53
|
self.packet_id = 0
|
54
54
|
|
55
55
|
# read header info here
|
56
|
-
header, n_bytes_hdr = self.header_decoder.decode_header(
|
56
|
+
header, n_bytes_hdr = self.header_decoder.decode_header(
|
57
|
+
self.in_stream, llama_filename
|
58
|
+
)
|
57
59
|
self.n_bytes_read += n_bytes_hdr
|
58
60
|
|
59
61
|
self.event_decoder.set_channel_configs(
|
60
62
|
self.header_decoder.get_channel_configs()
|
61
63
|
)
|
64
|
+
self.event_decoder.set_global_configs(self.header_decoder.get_global_configs())
|
62
65
|
|
63
66
|
# as far as I can tell, this happens if a user does not specify output.
|
64
67
|
# Then I can still get a rb_lib, but that misses keys entirely, which I need since channels can have different setups.
|
daq2lh5/orca/orca_digitizers.py
CHANGED
@@ -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
|
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:
|
@@ -0,0 +1,405 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import copy
|
4
|
+
import logging
|
5
|
+
from typing import Any
|
6
|
+
|
7
|
+
from fcio import FCIO, Tags
|
8
|
+
|
9
|
+
from daq2lh5.fc.fc_config_decoder import FCConfigDecoder
|
10
|
+
from daq2lh5.fc.fc_event_decoder import FCEventDecoder
|
11
|
+
from daq2lh5.fc.fc_eventheader_decoder import FCEventHeaderDecoder, get_fcid, get_key
|
12
|
+
from daq2lh5.fc.fc_fsp_decoder import (
|
13
|
+
FSPConfigDecoder,
|
14
|
+
FSPEventDecoder,
|
15
|
+
FSPStatusDecoder,
|
16
|
+
)
|
17
|
+
from daq2lh5.fc.fc_status_decoder import FCStatusDecoder
|
18
|
+
from daq2lh5.fc.fc_status_decoder import get_key as get_status_key
|
19
|
+
|
20
|
+
from ..raw_buffer import RawBufferList
|
21
|
+
from .orca_base import OrcaDecoder
|
22
|
+
from .orca_header import OrcaHeader
|
23
|
+
from .orca_packet import OrcaPacket
|
24
|
+
|
25
|
+
log = logging.getLogger(__name__)
|
26
|
+
|
27
|
+
|
28
|
+
# FCIO streams are stateful and need to be accessible for all decoders.
|
29
|
+
fcio_stream_library = dict()
|
30
|
+
|
31
|
+
|
32
|
+
def get_fcio_stream(streamid):
|
33
|
+
if streamid in fcio_stream_library:
|
34
|
+
return fcio_stream_library[streamid]
|
35
|
+
else:
|
36
|
+
fcio_stream_library[streamid] = FCIO()
|
37
|
+
return fcio_stream_library[streamid]
|
38
|
+
|
39
|
+
|
40
|
+
def extract_header_information(header: OrcaHeader):
|
41
|
+
|
42
|
+
fc_hdr_info = {
|
43
|
+
"key_list": {},
|
44
|
+
"n_adc": {},
|
45
|
+
"adc_card_layout": {},
|
46
|
+
"wf_len": {},
|
47
|
+
"fsp_enabled": {},
|
48
|
+
"n_card": {},
|
49
|
+
}
|
50
|
+
|
51
|
+
fc_card_info_dict = header.get_object_info(
|
52
|
+
[
|
53
|
+
"ORFlashCamGlobalTriggerModel",
|
54
|
+
"ORFlashCamTriggerModel",
|
55
|
+
"ORFlashCamADCModel",
|
56
|
+
"ORFlashCamADCStdModel",
|
57
|
+
]
|
58
|
+
)
|
59
|
+
|
60
|
+
fc_listener_info_list = header.get_readout_info("ORFlashCamListenerModel")
|
61
|
+
for fc_listener_info in fc_listener_info_list:
|
62
|
+
fcid = fc_listener_info["uniqueID"] # it should be called listener_id
|
63
|
+
if fcid == 0:
|
64
|
+
raise ValueError("got fcid=0 unexpectedly!")
|
65
|
+
aux_hw_info = header.get_auxhw_info("ORFlashCamListenerModel", fcid)
|
66
|
+
if "fspEnabled" in aux_hw_info:
|
67
|
+
fc_hdr_info["fsp_enabled"][fcid] = aux_hw_info["fspEnabled"]
|
68
|
+
else:
|
69
|
+
fc_hdr_info["fsp_enabled"][fcid] = False
|
70
|
+
|
71
|
+
fc_hdr_info["wf_len"][fcid] = header.get_auxhw_info(
|
72
|
+
"ORFlashCamListenerModel", fcid
|
73
|
+
)["eventSamples"]
|
74
|
+
fc_hdr_info["n_adc"][fcid] = 0
|
75
|
+
fc_hdr_info["n_card"][fcid] = 0
|
76
|
+
fc_hdr_info["key_list"][fcid] = []
|
77
|
+
fc_hdr_info["adc_card_layout"][fcid] = {}
|
78
|
+
for child in fc_listener_info["children"]:
|
79
|
+
|
80
|
+
crate = child["crate"]
|
81
|
+
card = child["station"]
|
82
|
+
card_address = fc_card_info_dict[crate][card]["CardAddress"]
|
83
|
+
fc_hdr_info["adc_card_layout"][fcid][card_address] = (
|
84
|
+
crate,
|
85
|
+
card,
|
86
|
+
card_address,
|
87
|
+
)
|
88
|
+
fc_hdr_info["n_card"][fcid] += 1
|
89
|
+
|
90
|
+
if crate not in fc_card_info_dict:
|
91
|
+
raise RuntimeError(f"no crate {crate} in fc_card_info_dict")
|
92
|
+
if card not in fc_card_info_dict[crate]:
|
93
|
+
raise RuntimeError(f"no card {card} in fc_card_info_dict[{crate}]")
|
94
|
+
|
95
|
+
for fc_input in range(len(fc_card_info_dict[crate][card]["Enabled"])):
|
96
|
+
if not fc_card_info_dict[crate][card]["Enabled"][fc_input]:
|
97
|
+
continue
|
98
|
+
|
99
|
+
fc_hdr_info["n_adc"][fcid] += 1
|
100
|
+
key = get_key(fcid, card_address, fc_input)
|
101
|
+
|
102
|
+
if key in fc_hdr_info["key_list"][fcid]:
|
103
|
+
log.warning(f"key {key} already in key_list...")
|
104
|
+
else:
|
105
|
+
fc_hdr_info["key_list"][fcid].append(key)
|
106
|
+
|
107
|
+
return fc_hdr_info
|
108
|
+
|
109
|
+
|
110
|
+
class ORFCIOConfigDecoder(OrcaDecoder):
|
111
|
+
def __init__(self, header: OrcaHeader = None, **kwargs) -> None:
|
112
|
+
|
113
|
+
self.decoder = FCConfigDecoder()
|
114
|
+
self.fsp_decoder = None
|
115
|
+
self.decoded_values = {}
|
116
|
+
self.key_list = {"fc_config": [], "fsp_config": []}
|
117
|
+
self.max_rows_in_packet = 0
|
118
|
+
|
119
|
+
super().__init__(header=header, **kwargs)
|
120
|
+
|
121
|
+
# The ConfigDecoder is always required for decoding fcio data.
|
122
|
+
# When OrcaStreamer.open_stream is called, we close any open fcio stream
|
123
|
+
for fcio_stream in fcio_stream_library.values():
|
124
|
+
fcio_stream.close()
|
125
|
+
|
126
|
+
def set_header(self, header: OrcaHeader) -> None:
|
127
|
+
self.header = header
|
128
|
+
self.fc_hdr_info = extract_header_information(header)
|
129
|
+
self.decoded_values = copy.deepcopy(self.decoder.get_decoded_values())
|
130
|
+
|
131
|
+
for fcid in self.fc_hdr_info["fsp_enabled"]:
|
132
|
+
key = get_key(fcid, 0, 0)
|
133
|
+
self.key_list["fc_config"].append(key)
|
134
|
+
if self.fc_hdr_info["fsp_enabled"][fcid]:
|
135
|
+
self.fsp_decoder = FSPConfigDecoder()
|
136
|
+
self.key_list["fsp_config"].append(f"fsp_config_{key}")
|
137
|
+
self.max_rows_in_packet = 1
|
138
|
+
|
139
|
+
def get_key_lists(self) -> list[list[int, str]]:
|
140
|
+
return list(self.key_list.values())
|
141
|
+
|
142
|
+
def get_decoded_values(self, key: int | str = None) -> dict[str, Any]:
|
143
|
+
if isinstance(key, str) and key.startswith("fsp_config"):
|
144
|
+
return copy.deepcopy(self.fsp_decoder.get_decoded_values())
|
145
|
+
return self.decoded_values
|
146
|
+
raise KeyError(f"no decoded values for key {key}")
|
147
|
+
|
148
|
+
def decode_packet(
|
149
|
+
self, packet: OrcaPacket, packet_id: int, rbl: RawBufferList
|
150
|
+
) -> bool:
|
151
|
+
|
152
|
+
fcio_stream = get_fcio_stream(packet[2])
|
153
|
+
if fcio_stream.is_open():
|
154
|
+
raise NotImplementedError(
|
155
|
+
f"FCIO stream with stream id {packet[2]} already opened. Update of FCIOConfig is not supported."
|
156
|
+
)
|
157
|
+
else:
|
158
|
+
fcio_stream.open(memoryview(packet[3:]))
|
159
|
+
|
160
|
+
if fcio_stream.config.streamid != packet[2]:
|
161
|
+
log.warning(
|
162
|
+
f"The expected stream id {packet[2]} does not match the contained stream id {fcio_stream.config.streamid}"
|
163
|
+
)
|
164
|
+
|
165
|
+
config_rbkd = rbl.get_keyed_dict()
|
166
|
+
|
167
|
+
# TODO: the decoders could fetch lgdo's using it's key_list
|
168
|
+
fc_key = get_key(fcio_stream.config.streamid, 0, 0)
|
169
|
+
any_full = self.decoder.decode_packet(
|
170
|
+
fcio_stream, config_rbkd[fc_key], packet_id
|
171
|
+
)
|
172
|
+
if self.fsp_decoder is not None:
|
173
|
+
fsp_key = f"fsp_config_{get_key(fcio_stream.config.streamid, 0, 0)}"
|
174
|
+
any_full |= self.fsp_decoder.decode_packet(
|
175
|
+
fcio_stream, config_rbkd[fsp_key], packet_id
|
176
|
+
)
|
177
|
+
|
178
|
+
return bool(any_full)
|
179
|
+
|
180
|
+
|
181
|
+
class ORFCIOStatusDecoder(OrcaDecoder):
|
182
|
+
def __init__(self, header: OrcaHeader = None, **kwargs) -> None:
|
183
|
+
|
184
|
+
self.decoder = FCStatusDecoder()
|
185
|
+
self.fsp_decoder = None
|
186
|
+
self.decoded_values = {}
|
187
|
+
self.key_list = {"fc_status": [], "fsp_status": []}
|
188
|
+
self.max_rows_in_packet = 0
|
189
|
+
super().__init__(header=header, **kwargs)
|
190
|
+
|
191
|
+
def set_header(self, header: OrcaHeader) -> None:
|
192
|
+
"""Setter for headers. Overload to set card parameters, etc."""
|
193
|
+
self.header = header
|
194
|
+
self.fc_hdr_info = extract_header_information(header)
|
195
|
+
self.decoded_values = copy.deepcopy(self.decoder.get_decoded_values())
|
196
|
+
|
197
|
+
for fcid in self.fc_hdr_info["n_card"]:
|
198
|
+
# If the data was taken without a master distribution module,
|
199
|
+
# i.e. only one ADC Module the decoder will just not write to the buffer.
|
200
|
+
|
201
|
+
# MDB key
|
202
|
+
self.key_list["fc_status"] = [get_status_key(fcid, 0)]
|
203
|
+
# ADC module keys
|
204
|
+
self.key_list["fc_status"] += [
|
205
|
+
get_status_key(fcid, 0x2000 + i)
|
206
|
+
for i in range(self.fc_hdr_info["n_card"][fcid])
|
207
|
+
]
|
208
|
+
|
209
|
+
if self.fc_hdr_info["fsp_enabled"][fcid]:
|
210
|
+
key = get_key(fcid, 0, 0)
|
211
|
+
self.key_list["fsp_status"].append(f"fsp_status_{key}")
|
212
|
+
self.fsp_decoder = FSPStatusDecoder()
|
213
|
+
self.max_rows_in_packet = max(self.fc_hdr_info["n_card"].values()) + 1
|
214
|
+
|
215
|
+
def get_key_lists(self) -> list[list[int | str]]:
|
216
|
+
return list(self.key_list.values())
|
217
|
+
|
218
|
+
def get_decoded_values(self, key: int | str = None) -> dict[str, Any]:
|
219
|
+
if key is None:
|
220
|
+
dec_vals_list = list(self.decoded_values)
|
221
|
+
if len(dec_vals_list) > 0:
|
222
|
+
return {dec_vals_list[0]: self.decoded_values[dec_vals_list[0]]}
|
223
|
+
raise RuntimeError("decoded_values not built")
|
224
|
+
|
225
|
+
if (
|
226
|
+
isinstance(key, str)
|
227
|
+
and key.startswith("fsp_status")
|
228
|
+
and self.fsp_decoder is not None
|
229
|
+
):
|
230
|
+
return copy.deepcopy(self.fsp_decoder.get_decoded_values())
|
231
|
+
elif isinstance(key, int):
|
232
|
+
return copy.deepcopy(self.decoder.get_decoded_values())
|
233
|
+
else:
|
234
|
+
raise KeyError(f"no decoded values for key {key}")
|
235
|
+
|
236
|
+
def get_max_rows_in_packet(self) -> int:
|
237
|
+
return self.max_rows_in_packet
|
238
|
+
|
239
|
+
def decode_packet(
|
240
|
+
self, packet: OrcaPacket, packet_id: int, rbl: RawBufferList
|
241
|
+
) -> bool:
|
242
|
+
status_rbkd = rbl.get_keyed_dict()
|
243
|
+
|
244
|
+
fcio_stream = get_fcio_stream(packet[2])
|
245
|
+
fcio_stream.set_mem_field(memoryview(packet[3:]))
|
246
|
+
|
247
|
+
any_full = False
|
248
|
+
while fcio_stream.get_record():
|
249
|
+
if fcio_stream.tag == Tags.Status:
|
250
|
+
any_full |= self.decoder.decode_packet(
|
251
|
+
fcio_stream, status_rbkd, packet_id
|
252
|
+
)
|
253
|
+
if self.fsp_decoder is not None:
|
254
|
+
any_full |= self.fsp_decoder.decode_packet(
|
255
|
+
fcio_stream, status_rbkd, packet_id
|
256
|
+
)
|
257
|
+
|
258
|
+
return bool(any_full)
|
259
|
+
|
260
|
+
|
261
|
+
class ORFCIOEventHeaderDecoder(OrcaDecoder):
|
262
|
+
def __init__(self, header: OrcaHeader = None, **kwargs) -> None:
|
263
|
+
|
264
|
+
self.decoder = FCEventHeaderDecoder()
|
265
|
+
self.fsp_decoder = None
|
266
|
+
self.decoded_values = {}
|
267
|
+
self.key_list = {"fc_eventheader": [], "fsp_eventheader": []}
|
268
|
+
|
269
|
+
super().__init__(header=header, **kwargs)
|
270
|
+
|
271
|
+
def set_header(self, header: OrcaHeader) -> None:
|
272
|
+
"""Setter for headers. Overload to set card parameters, etc."""
|
273
|
+
self.header = header
|
274
|
+
|
275
|
+
self.fc_hdr_info = extract_header_information(header)
|
276
|
+
|
277
|
+
key_list = self.fc_hdr_info["key_list"]
|
278
|
+
for fcid in key_list:
|
279
|
+
key = get_key(fcid, 0, 0)
|
280
|
+
self.key_list["fc_eventheader"].append(key)
|
281
|
+
self.decoded_values[fcid] = copy.deepcopy(self.decoder.get_decoded_values())
|
282
|
+
if self.fc_hdr_info["fsp_enabled"][fcid]:
|
283
|
+
self.fsp_decoder = FSPEventDecoder()
|
284
|
+
self.key_list["fsp_eventheader"].append(f"fsp_eventheader_{key}")
|
285
|
+
|
286
|
+
self.max_rows_in_packet = 1
|
287
|
+
|
288
|
+
def get_key_lists(self) -> list[list[int | str]]:
|
289
|
+
return list(self.key_list.values())
|
290
|
+
|
291
|
+
def get_decoded_values(self, key: int | str = None) -> dict[str, Any]:
|
292
|
+
if (
|
293
|
+
isinstance(key, str)
|
294
|
+
and key.startswith("fsp_eventheader_")
|
295
|
+
and self.fsp_decoder is not None
|
296
|
+
):
|
297
|
+
return copy.deepcopy(self.fsp_decoder.get_decoded_values())
|
298
|
+
elif isinstance(key, int):
|
299
|
+
fcid = get_fcid(key)
|
300
|
+
if fcid in self.decoded_values:
|
301
|
+
return self.decoded_values[fcid]
|
302
|
+
elif key is None and self.fsp_decoder is None:
|
303
|
+
dec_vals_list = list(self.decoded_values.values())
|
304
|
+
if len(dec_vals_list) > 0:
|
305
|
+
return dec_vals_list[0]
|
306
|
+
raise RuntimeError("decoded_values not built")
|
307
|
+
|
308
|
+
raise KeyError(f"no decoded values for key {key}")
|
309
|
+
|
310
|
+
def decode_packet(
|
311
|
+
self, packet: OrcaPacket, packet_id: int, rbl: RawBufferList
|
312
|
+
) -> bool:
|
313
|
+
evthdr_rbkd = rbl.get_keyed_dict()
|
314
|
+
fcio_stream = get_fcio_stream(packet[2])
|
315
|
+
fcio_stream.set_mem_field(memoryview(packet[3:]))
|
316
|
+
|
317
|
+
any_full = False
|
318
|
+
while fcio_stream.get_record():
|
319
|
+
if fcio_stream.tag == Tags.EventHeader:
|
320
|
+
any_full |= self.decoder.decode_packet(
|
321
|
+
fcio_stream, evthdr_rbkd, packet_id
|
322
|
+
)
|
323
|
+
if self.fsp_decoder is not None:
|
324
|
+
any_full |= self.fsp_decoder.decode_packet(
|
325
|
+
fcio_stream, evthdr_rbkd, packet_id, True
|
326
|
+
)
|
327
|
+
|
328
|
+
return bool(any_full)
|
329
|
+
|
330
|
+
|
331
|
+
class ORFCIOEventDecoder(OrcaDecoder):
|
332
|
+
"""Decoder for FlashCam FCIO stream data written by ORCA."""
|
333
|
+
|
334
|
+
def __init__(self, header: OrcaHeader = None, **kwargs) -> None:
|
335
|
+
self.decoder = FCEventDecoder()
|
336
|
+
self.fsp_decoder = None
|
337
|
+
|
338
|
+
self.key_list = {"event": [], "fsp_event": []}
|
339
|
+
self.decoded_values = {}
|
340
|
+
self.max_rows_in_packet = 0
|
341
|
+
|
342
|
+
super().__init__(header=header, **kwargs)
|
343
|
+
|
344
|
+
def set_header(self, header: OrcaHeader) -> None:
|
345
|
+
"""Setter for headers. Overload to set card parameters, etc."""
|
346
|
+
self.header = header
|
347
|
+
self.fc_hdr_info = extract_header_information(header)
|
348
|
+
key_list = self.fc_hdr_info["key_list"]
|
349
|
+
for fcid in key_list:
|
350
|
+
self.key_list["event"] += key_list[fcid]
|
351
|
+
self.decoded_values[fcid] = copy.deepcopy(self.decoder.get_decoded_values())
|
352
|
+
self.decoded_values[fcid]["waveform"]["wf_len"] = self.fc_hdr_info[
|
353
|
+
"wf_len"
|
354
|
+
][fcid]
|
355
|
+
if self.fc_hdr_info["fsp_enabled"][fcid]:
|
356
|
+
key = get_key(fcid, 0, 0)
|
357
|
+
self.key_list["fsp_event"].append(f"fsp_event_{key}")
|
358
|
+
self.fsp_decoder = FSPEventDecoder()
|
359
|
+
self.max_rows_in_packet = max(self.fc_hdr_info["n_adc"].values())
|
360
|
+
|
361
|
+
def get_key_lists(self) -> list[list[int]]:
|
362
|
+
return list(self.key_list.values())
|
363
|
+
|
364
|
+
def get_max_rows_in_packet(self) -> int:
|
365
|
+
return self.max_rows_in_packet
|
366
|
+
|
367
|
+
def get_decoded_values(self, key: int = None) -> dict[str, Any]:
|
368
|
+
if key is None:
|
369
|
+
dec_vals_list = list(self.decoded_values.values())
|
370
|
+
if len(dec_vals_list) > 0:
|
371
|
+
return dec_vals_list[0]
|
372
|
+
raise RuntimeError("decoded_values not built")
|
373
|
+
|
374
|
+
if (
|
375
|
+
isinstance(key, str)
|
376
|
+
and key.startswith("fsp_event_")
|
377
|
+
and self.fsp_decoder is not None
|
378
|
+
):
|
379
|
+
return copy.deepcopy(self.fsp_decoder.get_decoded_values())
|
380
|
+
elif isinstance(key, int):
|
381
|
+
fcid = get_fcid(key)
|
382
|
+
if fcid in self.decoded_values:
|
383
|
+
return self.decoded_values[fcid]
|
384
|
+
|
385
|
+
raise KeyError(f"no decoded values for key {key}")
|
386
|
+
|
387
|
+
def decode_packet(
|
388
|
+
self, packet: OrcaPacket, packet_id: int, rbl: RawBufferList
|
389
|
+
) -> bool:
|
390
|
+
"""Decode the ORCA FlashCam ADC packet."""
|
391
|
+
evt_rbkd = rbl.get_keyed_dict()
|
392
|
+
|
393
|
+
fcio_stream = get_fcio_stream(packet[2])
|
394
|
+
fcio_stream.set_mem_field(memoryview(packet[3:]))
|
395
|
+
|
396
|
+
any_full = False
|
397
|
+
while fcio_stream.get_record():
|
398
|
+
if fcio_stream.tag == Tags.Event or fcio_stream.tag == Tags.SparseEvent:
|
399
|
+
any_full |= self.decoder.decode_packet(fcio_stream, evt_rbkd, packet_id)
|
400
|
+
if self.fsp_decoder is not None:
|
401
|
+
any_full |= self.fsp_decoder.decode_packet(
|
402
|
+
fcio_stream, evt_rbkd, packet_id, False
|
403
|
+
)
|
404
|
+
|
405
|
+
return bool(any_full)
|
daq2lh5/orca/orca_flashcam.py
CHANGED
@@ -5,7 +5,7 @@ from typing import Any
|
|
5
5
|
|
6
6
|
import numpy as np
|
7
7
|
|
8
|
-
from ..fc.fc_event_decoder import
|
8
|
+
from ..fc.fc_event_decoder import fc_event_decoded_values
|
9
9
|
from ..raw_buffer import RawBufferLibrary
|
10
10
|
from .orca_base import OrcaDecoder
|
11
11
|
from .orca_header import OrcaHeader
|
@@ -43,7 +43,7 @@ class ORFlashCamListenerConfigDecoder(OrcaDecoder):
|
|
43
43
|
"packet_len": {"dtype": "uint32"},
|
44
44
|
"readout_id": {"dtype": "uint16"},
|
45
45
|
"fcid": {"dtype": "uint16"},
|
46
|
-
"
|
46
|
+
"streamid": {"dtype": "int32"},
|
47
47
|
"nadcs": {"dtype": "int32"},
|
48
48
|
"ntriggers": {"dtype": "int32"},
|
49
49
|
"nsamples": {"dtype": "int32"},
|
@@ -458,8 +458,8 @@ class ORFlashCamWaveformDecoder(OrcaDecoder):
|
|
458
458
|
|
459
459
|
def __init__(self, header: OrcaHeader = None, **kwargs) -> None:
|
460
460
|
# start with the values defined in fcdaq
|
461
|
-
self.decoded_values_template = copy.deepcopy(
|
462
|
-
"""A custom copy of :obj:`.fc.fc_event_decoder.
|
461
|
+
self.decoded_values_template = copy.deepcopy(fc_event_decoded_values)
|
462
|
+
"""A custom copy of :obj:`.fc.fc_event_decoder.fc_event_decoded_values`."""
|
463
463
|
# add header values from Orca
|
464
464
|
self.decoded_values_template.update(
|
465
465
|
{
|
@@ -737,6 +737,9 @@ class ORFlashCamWaveformDecoder(OrcaDecoder):
|
|
737
737
|
tbl["waveform"]["values"].nda[ii][:wf_samples] = wf
|
738
738
|
|
739
739
|
evt_rbkd[key].loc += 1
|
740
|
+
log.info(
|
741
|
+
f"-> {tbl['eventnumber'].nda[ii]} {channel} .. {evt_rbkd[key].loc}/{len(evt_rbkd[key])} {id(evt_rbkd[key])} {id(evt_rbkd[key].lgdo)}"
|
742
|
+
)
|
740
743
|
return evt_rbkd[key].is_full()
|
741
744
|
|
742
745
|
|
daq2lh5/orca/orca_header.py
CHANGED
@@ -46,16 +46,21 @@ class OrcaHeader(dict):
|
|
46
46
|
return d["Run Control"]["RunNumber"]
|
47
47
|
raise ValueError("No run number found in header!")
|
48
48
|
|
49
|
-
def get_object_info(
|
49
|
+
def get_object_info(
|
50
|
+
self, orca_class_name: str | list[str]
|
51
|
+
) -> dict[int, dict[int, dict]]:
|
50
52
|
"""Returns a ``dict[crate][card]`` with all info from the header for
|
51
53
|
each card with name `orca_class_name`.
|
52
54
|
"""
|
53
55
|
object_info_dict = {}
|
54
56
|
|
57
|
+
if isinstance(orca_class_name, str):
|
58
|
+
orca_class_name = [orca_class_name]
|
59
|
+
|
55
60
|
crates = self["ObjectInfo"]["Crates"]
|
56
61
|
for crate in crates:
|
57
62
|
for card in crate["Cards"]:
|
58
|
-
if card["Class Name"]
|
63
|
+
if card["Class Name"] in orca_class_name:
|
59
64
|
if crate["CrateNumber"] not in object_info_dict:
|
60
65
|
object_info_dict[crate["CrateNumber"]] = {}
|
61
66
|
object_info_dict[crate["CrateNumber"]][card["Card"]] = card
|
daq2lh5/orca/orca_packet.py
CHANGED
@@ -20,9 +20,19 @@ def is_short(packet: OrcaPacket) -> bool:
|
|
20
20
|
return bool(packet[0] >> 31)
|
21
21
|
|
22
22
|
|
23
|
+
def is_extended(packet: OrcaPacket) -> bool:
|
24
|
+
# if the packet is 0 size in default format
|
25
|
+
# the length if the packet is stored in the next uint32
|
26
|
+
return bool((packet[0] & 0x3FFFF) == 0)
|
27
|
+
|
28
|
+
|
23
29
|
def get_n_words(packet: OrcaPacket) -> int:
|
24
30
|
if is_short(packet):
|
25
31
|
return 1
|
32
|
+
if is_extended(packet):
|
33
|
+
# we could check here if packet is actually long enough
|
34
|
+
# to return packet[1]
|
35
|
+
return packet[1]
|
26
36
|
return packet[0] & 0x3FFFF
|
27
37
|
|
28
38
|
|
daq2lh5/orca/orca_run_decoder.py
CHANGED
@@ -18,12 +18,12 @@ class ORRunDecoderForRun(OrcaDecoder):
|
|
18
18
|
# bit in data packet
|
19
19
|
self.decoded_values = {
|
20
20
|
"subrun_number": {"dtype": "uint16"},
|
21
|
-
"runstartorstop": {"dtype": "
|
22
|
-
"quickstartrun": {"dtype": "
|
23
|
-
"remotecontrolrun": {"dtype": "
|
24
|
-
"heartbeatrecord": {"dtype": "
|
25
|
-
"endsubrunrecord": {"dtype": "
|
26
|
-
"startsubrunrecord": {"dtype": "
|
21
|
+
"runstartorstop": {"dtype": "bool"},
|
22
|
+
"quickstartrun": {"dtype": "bool"},
|
23
|
+
"remotecontrolrun": {"dtype": "bool"},
|
24
|
+
"heartbeatrecord": {"dtype": "bool"},
|
25
|
+
"endsubrunrecord": {"dtype": "bool"},
|
26
|
+
"startsubrunrecord": {"dtype": "bool"},
|
27
27
|
"run_number": {"dtype": "int32"},
|
28
28
|
"time": {"dtype": "int32"},
|
29
29
|
}
|