4 #ifndef artdaq_dune_Overlays_FelixFragment_hh 5 #define artdaq_dune_Overlays_FelixFragment_hh 8 #include "artdaq-core/Data/Fragment.hh" 25 class FelixFragmentBase;
26 class FelixFragmentUnordered;
27 class FelixFragmentReordered;
28 class FelixFragmentCompressed;
80 "FelixFragment::Metadata size changed");
83 virtual uint8_t
sof(
const unsigned& frame_ID = 0)
const = 0;
84 virtual uint8_t
version(
const unsigned& frame_ID = 0)
const = 0;
85 virtual uint8_t
fiber_no(
const unsigned& frame_ID = 0)
const = 0;
86 virtual uint8_t
slot_no(
const unsigned& frame_ID = 0)
const = 0;
87 virtual uint8_t
crate_no(
const unsigned& frame_ID = 0)
const = 0;
88 virtual uint8_t
mm(
const unsigned& frame_ID = 0)
const = 0;
89 virtual uint8_t
oos(
const unsigned& frame_ID = 0)
const = 0;
90 virtual uint16_t
wib_errors(
const unsigned& frame_ID = 0)
const = 0;
91 virtual uint64_t
timestamp(
const unsigned& frame_ID = 0)
const = 0;
92 virtual uint16_t
wib_counter(
const unsigned& frame_ID = 0)
const = 0;
95 virtual uint8_t
s1_error(
const unsigned& frame_ID,
96 const uint8_t& block_num)
const = 0;
97 virtual uint8_t
s2_error(
const unsigned& frame_ID,
98 const uint8_t& block_num)
const = 0;
99 virtual uint16_t
checksum_a(
const unsigned& frame_ID,
100 const uint8_t& block_num)
const = 0;
101 virtual uint16_t
checksum_b(
const unsigned& frame_ID,
102 const uint8_t& block_num)
const = 0;
104 const uint8_t& block_num)
const = 0;
106 const uint8_t& block_num)
const = 0;
107 virtual uint8_t
hdr(
const unsigned& frame_ID,
const uint8_t& block_num,
108 const uint8_t& hdr_num)
const = 0;
112 const uint8_t channel_ID)
const = 0;
117 virtual void print(
const unsigned i)
const = 0;
160 unsigned sizeBytes = fragment.dataSizeBytes();
185 return (1ul << daq_adc_bits);
206 uint8_t
sof(
const unsigned& frame_ID = 0)
const {
207 return frame_(frame_ID)->sof();
209 uint8_t
version(
const unsigned& frame_ID = 0)
const {
210 return frame_(frame_ID)->version();
212 uint8_t
fiber_no(
const unsigned& frame_ID = 0)
const {
213 return frame_(frame_ID)->fiber_no();
215 uint8_t
slot_no(
const unsigned& frame_ID = 0)
const {
216 return frame_(frame_ID)->slot_no();
218 uint8_t
crate_no(
const unsigned& frame_ID = 0)
const {
219 return frame_(frame_ID)->crate_no();
221 uint8_t
mm(
const unsigned& frame_ID = 0)
const {
222 return frame_(frame_ID)->mm();
224 uint8_t
oos(
const unsigned& frame_ID = 0)
const {
225 return frame_(frame_ID)->oos();
228 return frame_(frame_ID)->wib_errors();
230 uint64_t
timestamp(
const unsigned& frame_ID = 0)
const {
231 return frame_(frame_ID)->timestamp();
234 return frame_(frame_ID)->wib_counter();
238 uint8_t
s1_error(
const unsigned& frame_ID,
const uint8_t& block_num)
const {
239 return frame_(frame_ID)->s1_error(block_num);
241 uint8_t
s2_error(
const unsigned& frame_ID,
const uint8_t& block_num)
const {
242 return frame_(frame_ID)->s2_error(block_num);
245 const uint8_t& block_num)
const {
246 return frame_(frame_ID)->checksum_a(block_num);
249 const uint8_t& block_num)
const {
250 return frame_(frame_ID)->checksum_b(block_num);
253 const uint8_t& block_num)
const {
254 return frame_(frame_ID)->coldata_convert_count(block_num);
257 const uint8_t& block_num)
const {
258 return frame_(frame_ID)->error_register(block_num);
260 uint8_t
hdr(
const unsigned& frame_ID,
const uint8_t& block_num,
261 const uint8_t& hdr_num)
const {
262 return frame_(frame_ID)->hdr(block_num, hdr_num);
266 adc_t get_ADC(
const unsigned& frame_ID,
const uint8_t channel_ID)
const {
267 return frame_(frame_ID)->channel(channel_ID);
278 void print(
const unsigned i)
const { frame_(i)->print(); }
319 uint8_t
sof(
const unsigned& frame_ID = 0)
const {
320 return head_(frame_ID)->sof;
322 uint8_t
version(
const unsigned& frame_ID = 0)
const {
323 return head_(frame_ID)->version;
325 uint8_t
fiber_no(
const unsigned& frame_ID = 0)
const {
326 return head_(frame_ID)->fiber_no;
328 uint8_t
slot_no(
const unsigned& frame_ID = 0)
const {
329 return head_(frame_ID)->slot_no;
331 uint8_t
crate_no(
const unsigned& frame_ID = 0)
const {
332 return head_(frame_ID)->crate_no;
334 uint8_t
mm(
const unsigned& frame_ID = 0)
const {
return head_(frame_ID)->mm; }
335 uint8_t
oos(
const unsigned& frame_ID = 0)
const {
336 return head_(frame_ID)->oos;
339 return head_(frame_ID)->wib_errors;
341 uint64_t
timestamp(
const unsigned& frame_ID = 0)
const {
342 uint64_t
result = head_(frame_ID)->timestamp();
343 if (header_is_faulty(frame_ID) ==
false) {
345 result += frame_ID * 25;
350 return head_(frame_ID)->wib_counter();
354 uint8_t
s1_error(
const unsigned& frame_ID,
const uint8_t& block_num)
const {
355 return blockhead_(frame_ID, block_num)->s1_error;
357 uint8_t
s2_error(
const unsigned& frame_ID,
const uint8_t& block_num)
const {
358 return blockhead_(frame_ID, block_num)->s2_error;
361 const uint8_t& block_num)
const {
362 return blockhead_(frame_ID, block_num)->checksum_a();
365 const uint8_t& block_num)
const {
366 return blockhead_(frame_ID, block_num)->checksum_b();
369 const uint8_t& block_num)
const {
370 uint16_t
result = blockhead_(frame_ID, block_num)->coldata_convert_count;
371 if (header_is_faulty(frame_ID) ==
false) {
378 const uint8_t& block_num)
const {
379 return blockhead_(frame_ID, block_num)->error_register;
381 uint8_t
hdr(
const unsigned& frame_ID,
const uint8_t& block_num,
382 const uint8_t& hdr_num)
const {
383 return blockhead_(frame_ID, block_num)->hdr(hdr_num);
387 adc_t get_ADC(
const unsigned& frame_ID,
const uint8_t channel_ID)
const {
388 return channel_(frame_ID, channel_ID);
400 void print(
const unsigned i)
const {
401 std::cout <<
"Frame " << i
402 <<
" should be printed here.\n";
416 unsigned int bad_header_count = 1;
418 if (header_is_faulty(i)) {
419 bad_header_num[i] = bad_header_count++;
438 const unsigned int adc_start = 0;
439 const unsigned int bitlist_start =
443 const unsigned int header_set_size =
449 bitlist_start + frame_num / 8;
450 return ((*curr_byte) >> (frame_num % 8)) & 1;
457 if (header_is_faulty(frame_num)) {
461 bad_header_num[frame_num] * header_set_size);
470 const uint8_t block_num)
const {
471 if (header_is_faulty(frame_num)) {
476 bad_header_num[frame_num] * header_set_size) +
488 const uint8_t ch_num)
const {
502 long unsigned int uncompSizeBytes;
512 dst.resizeBytes(uncompSizeBytes);
514 int num_bytes = internal_inflate(src.dataBeginBytes(), src.dataSizeBytes(),
515 dst.dataBeginBytes(), dst.dataSizeBytes());
521 z_stream strm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
522 strm.total_in = strm.avail_in = srcLen;
523 strm.total_out = strm.avail_out = dstLen;
524 strm.next_in = (Bytef*)src;
525 strm.next_out = (Bytef*)dst;
527 strm.zalloc = Z_NULL;
529 strm.opaque = Z_NULL;
535 while (read < srcLen && write < dstLen) {
536 strm.next_in = (Bytef*)src + read;
537 strm.next_out = (Bytef*)dst + write;
539 unsigned to_read = srcLen -
read;
540 unsigned to_write = dstLen -
write;
547 strm.total_in = strm.avail_in = to_read;
548 strm.total_out = strm.avail_out = to_write;
550 inflateInit2(&strm, MAX_WBITS | 16);
551 err = inflate(&strm, Z_FINISH);
553 if (err == Z_DATA_ERROR) {
554 std::cout <<
"Warning: decompression data error. Returning compressed " 556 memcpy(dst, src, srcLen);
561 read += to_read - strm.avail_in;
562 write += to_write - strm.avail_out;
576 decompress_copy(fragment, uncompfrag_);
582 uncompfrag_.setMetadata(
meta_);
593 uint8_t
sof(
const unsigned& frame_ID = 0)
const {
594 return flxfrag->sof(frame_ID);
596 uint8_t
version(
const unsigned& frame_ID = 0)
const {
597 return flxfrag->version(frame_ID);
599 uint8_t
fiber_no(
const unsigned& frame_ID = 0)
const {
600 return flxfrag->fiber_no(frame_ID);
602 uint8_t
slot_no(
const unsigned& frame_ID = 0)
const {
603 return flxfrag->slot_no(frame_ID);
605 uint8_t
crate_no(
const unsigned& frame_ID = 0)
const {
606 return flxfrag->crate_no(frame_ID);
608 uint8_t
mm(
const unsigned& frame_ID = 0)
const {
609 return flxfrag->mm(frame_ID);
611 uint8_t
oos(
const unsigned& frame_ID = 0)
const {
612 return flxfrag->oos(frame_ID);
615 return flxfrag->wib_errors(frame_ID);
617 uint64_t
timestamp(
const unsigned& frame_ID = 0)
const {
618 return flxfrag->timestamp(frame_ID);
621 return flxfrag->wib_counter(frame_ID);
625 uint8_t
s1_error(
const unsigned& frame_ID,
const uint8_t& block_num)
const {
626 return flxfrag->s1_error(frame_ID, block_num);
628 uint8_t
s2_error(
const unsigned& frame_ID,
const uint8_t& block_num)
const {
629 return flxfrag->s2_error(frame_ID, block_num);
632 const uint8_t& block_num)
const {
633 return flxfrag->checksum_a(frame_ID, block_num);
636 const uint8_t& block_num)
const {
637 return flxfrag->checksum_b(frame_ID, block_num);
640 const uint8_t& block_num)
const {
641 return flxfrag->coldata_convert_count(frame_ID, block_num);
644 const uint8_t& block_num)
const {
645 return flxfrag->error_register(frame_ID, block_num);
647 uint8_t
hdr(
const unsigned& frame_ID,
const uint8_t& block_num,
648 const uint8_t& hdr_num)
const {
649 return flxfrag->hdr(frame_ID, block_num, hdr_num);
653 adc_t get_ADC(
const unsigned& frame_ID,
const uint8_t channel_ID)
const {
654 return flxfrag->get_ADC(frame_ID, channel_ID);
660 void print(
const unsigned i)
const {
return flxfrag->print(i); }
697 bool shift_good =
true;
702 shift_good &= fragment.timestamp() -
707 trig_offset = (fragment.timestamp() - flxfrag->timestamp()) / 25 -
meta_.
offset_frames;
710 <<
"Can't find the trigger window in FELIX fragment " 711 << fragment.fragmentID() <<
".\nFragment TS: " << fragment.timestamp()
712 <<
" first frame TS: " << flxfrag->timestamp() <<
'\n';
719 uint8_t
sof(
const unsigned& frame_ID = 0)
const {
720 return flxfrag->sof(frame_ID + trig_offset);
722 uint8_t
version(
const unsigned& frame_ID = 0)
const {
723 return flxfrag->version(frame_ID + trig_offset);
725 uint8_t
fiber_no(
const unsigned& frame_ID = 0)
const {
726 return flxfrag->fiber_no(frame_ID + trig_offset);
728 uint8_t
slot_no(
const unsigned& frame_ID = 0)
const {
729 return flxfrag->slot_no(frame_ID + trig_offset);
731 uint8_t
crate_no(
const unsigned& frame_ID = 0)
const {
732 return flxfrag->crate_no(frame_ID + trig_offset);
734 uint8_t
mm(
const unsigned& frame_ID = 0)
const {
735 return flxfrag->mm(frame_ID + trig_offset);
737 uint8_t
oos(
const unsigned& frame_ID = 0)
const {
738 return flxfrag->oos(frame_ID + trig_offset);
741 return flxfrag->wib_errors(frame_ID + trig_offset);
743 uint64_t
timestamp(
const unsigned& frame_ID = 0)
const {
744 return flxfrag->timestamp(frame_ID + trig_offset);
747 return flxfrag->wib_counter(frame_ID + trig_offset);
751 uint8_t
s1_error(
const unsigned& frame_ID,
const uint8_t& block_num)
const {
752 return flxfrag->s1_error(frame_ID + trig_offset, block_num);
754 uint8_t
s2_error(
const unsigned& frame_ID,
const uint8_t& block_num)
const {
755 return flxfrag->s2_error(frame_ID + trig_offset, block_num);
758 const uint8_t& block_num)
const {
759 return flxfrag->checksum_a(frame_ID + trig_offset, block_num);
762 const uint8_t& block_num)
const {
763 return flxfrag->checksum_b(frame_ID + trig_offset, block_num);
766 const uint8_t& block_num)
const {
767 return flxfrag->coldata_convert_count(frame_ID + trig_offset, block_num);
770 const uint8_t& block_num)
const {
771 return flxfrag->error_register(frame_ID + trig_offset, block_num);
773 uint8_t
hdr(
const unsigned& frame_ID,
const uint8_t& block_num,
774 const uint8_t& hdr_num)
const {
775 return flxfrag->hdr(frame_ID + trig_offset, block_num, hdr_num);
779 adc_t get_ADC(
const unsigned& frame_ID,
const uint8_t channel_ID)
const {
780 return flxfrag->get_ADC(frame_ID + trig_offset, channel_ID);
783 const uint8_t channel_ID)
const {
784 return get_ADC(frame_ID, channel_ID + block_ID * 64);
791 output[i] =
get_ADC(i, channel_ID);
796 const uint8_t channel_ID)
const {
797 return get_ADCs_by_channel(channel_ID + block_ID * 64);
802 std::map<uint8_t, adc_v>
output;
803 for (
int i = 0; i < 256; i++)
804 output.insert(std::pair<uint8_t, adc_v>(i, get_ADCs_by_channel(i)));
811 void print(
const unsigned i)
const {
return flxfrag->print(i); }
823 size_t trig_offset = 0;
adc_t get_ADC(const unsigned &frame_ID, const uint8_t channel_ID) const
virtual uint16_t wib_errors(const unsigned &frame_ID=0) const =0
static constexpr size_t num_ch_per_frame
uint8_t hdr(const unsigned &frame_ID, const uint8_t &block_num, const uint8_t &hdr_num) const
uint8_t s1_error(const unsigned &frame_ID, const uint8_t &block_num) const
uint16_t wib_counter(const unsigned &frame_ID=0) const
virtual uint8_t fiber_no(const unsigned &frame_ID=0) const =0
size_t total_frames() const
FelixFragmentCompressed(const artdaq::Fragment &fragment)
void print_frames() const
uint8_t hdr(const unsigned &frame_ID, const uint8_t &block_num, const uint8_t &hdr_num) const
uint8_t version(const unsigned &frame_ID=0) const
uint8_t oos(const unsigned &frame_ID=0) const
uint16_t checksum_b(const unsigned &frame_ID, const uint8_t &block_num) const
uint8_t s2_error(const unsigned &frame_ID, const uint8_t &block_num) const
uint64_t timestamp(const unsigned &frame_ID=0) const
uint8_t slot_no(const unsigned &frame_ID=0) const
size_t total_adc_values() const
uint8_t version(const unsigned &frame_ID=0) const
virtual uint8_t mm(const unsigned &frame_ID=0) const =0
uint8_t sof(const unsigned &frame_ID=0) const
FelixFragmentUnordered(artdaq::Fragment const &fragment)
void print_timestamps() const
uint8_t crate_no(const unsigned &frame_ID=0) const
uint64_t timestamp(const unsigned &frame_ID=0) const
uint8_t version(const unsigned &frame_ID=0) const
void print_frames() const
const void * artdaq_Fragment_
bool header_is_faulty(const unsigned int frame_num) const
size_t total_frames() const
virtual uint8_t hdr(const unsigned &frame_ID, const uint8_t &block_num, const uint8_t &hdr_num) const =0
uint8_t s2_error(const unsigned &frame_ID, const uint8_t &block_num) const
uint16_t checksum_b(const unsigned &frame_ID, const uint8_t &block_num) const
virtual uint8_t slot_no(const unsigned &frame_ID=0) const =0
size_t total_words() const
virtual void print_timestamps() const =0
uint8_t sof(const unsigned &frame_ID=0) const
uint8_t crate_no(const unsigned &frame_ID=0) const
uint16_t wib_errors(const unsigned &frame_ID=0) const
uint8_t hdr(const unsigned &frame_ID, const uint8_t &block_num, const uint8_t &hdr_num) const
size_t write(int, const char *, size_t)
Writes count bytes from buf to the filedescriptor fd.
uint16_t checksum_b(const unsigned &frame_ID, const uint8_t &block_num) const
QTextStream & hex(QTextStream &s)
uint16_t error_register(const unsigned &frame_ID, const uint8_t &block_num) const
adc_t get_ADC(const unsigned &frame_ID, const uint8_t block_ID, const uint8_t channel_ID) const
virtual void print(const unsigned i) const =0
const artdaq::Fragment uncompressed_fragment() const
uint16_t checksum_a(const unsigned &frame_ID, const uint8_t &block_num) const
uint8_t mm(const unsigned &frame_ID=0) const
FelixFragmentBase(const artdaq::Fragment &fragment)
std::vector< uint16_t > adc_v
uint16_t wib_errors(const unsigned &frame_ID=0) const
uint16_t coldata_convert_count(const unsigned &frame_ID, const uint8_t &block_num) const
uint16_t wib_counter(const unsigned &frame_ID=0) const
virtual adc_t get_ADC(const unsigned &frame_ID, const uint8_t channel_ID) const =0
std::vector< unsigned int > bad_header_num
dune::adc_t channel_(const unsigned int frame_num, const uint8_t ch_num) const
uint8_t mm(const unsigned &frame_ID=0) const
uint64_t timestamp(const unsigned &frame_ID=0) const
size_t total_frames() const
void print_frames() const
int decompress_copy(const artdaq::Fragment &src, artdaq::Fragment &dst)
adc_t get_ADC(const unsigned &frame_ID, const uint8_t channel_ID) const
uint8_t fiber_no(const unsigned &frame_ID=0) const
virtual uint8_t s1_error(const unsigned &frame_ID, const uint8_t &block_num) const =0
uint16_t checksum_a(const unsigned &frame_ID, const uint8_t &block_num) const
virtual uint16_t coldata_convert_count(const unsigned &frame_ID, const uint8_t &block_num) const =0
uint16_t wib_counter(const unsigned &frame_ID=0) const
virtual uint64_t timestamp(const unsigned &frame_ID=0) const =0
uint8_t oos(const unsigned &frame_ID=0) const
uint8_t sof(const unsigned &frame_ID=0) const
uint8_t version(const unsigned &frame_ID=0) const
virtual ~FelixFragmentBase()
dune::ColdataHeader const * blockhead_(const unsigned int frame_num, const uint8_t block_num) const
uint16_t wib_counter(const unsigned &frame_ID=0) const
~FelixFragmentCompressed()
uint16_t coldata_convert_count(const unsigned &frame_ID, const uint8_t &block_num) const
uint16_t checksum_a(const unsigned &frame_ID, const uint8_t &block_num) const
uint8_t fiber_no(const unsigned &frame_ID=0) const
int internal_inflate(const void *src, uint srcLen, void *dst, uint dstLen)
uint16_t error_register(const unsigned &frame_ID, const uint8_t &block_num) const
uint8_t oos(const unsigned &frame_ID=0) const
uint16_t wib_errors(const unsigned &frame_ID=0) const
uint8_t slot_no(const unsigned &frame_ID=0) const
void print_timestamps() const
uint8_t s1_error(const unsigned &frame_ID, const uint8_t &block_num) const
uint16_t checksum_b(const unsigned &frame_ID, const uint8_t &block_num) const
uint8_t slot_no(const unsigned &frame_ID=0) const
void print(const unsigned i) const
uint8_t s1_error(const unsigned &frame_ID, const uint8_t &block_num) const
adc_t get_ADC(const unsigned &frame_ID, const uint8_t channel_ID) const
uint16_t error_register(const unsigned &frame_ID, const uint8_t &block_num) const
size_t total_words() const
size_t total_words() const
uint16_t coldata_convert_count(const unsigned &frame_ID, const uint8_t &block_num) const
FelixFrame const * frame_(const unsigned &frame_num=0) const
void err(const char *fmt,...)
virtual size_t total_frames() const =0
virtual uint8_t oos(const unsigned &frame_ID=0) const =0
QTextStream & dec(QTextStream &s)
uint8_t fiber_no(const unsigned &frame_ID=0) const
virtual size_t total_words() const =0
uint8_t s1_error(const unsigned &frame_ID, const uint8_t &block_num) const
uint8_t s2_error(const unsigned &frame_ID, const uint8_t &block_num) const
void print_timestamps() const
uint8_t fiber_no(const unsigned &frame_ID=0) const
artdaq::Fragment uncompfrag_
virtual void print_frames() const =0
adc_v get_ADCs_by_channel(const uint8_t channel_ID) const
size_t total_adc_values() const
void print(const unsigned i) const
uint8_t crate_no(const unsigned &frame_ID=0) const
uint16_t error_register(const unsigned &frame_ID, const uint8_t &block_num) const
const FelixFragmentBase * flxfrag
uint16_t wib_errors(const unsigned &frame_ID=0) const
virtual uint16_t checksum_b(const unsigned &frame_ID, const uint8_t &block_num) const =0
FelixFragmentReordered(artdaq::Fragment const &fragment)
const FelixFragmentBase * flxfrag
virtual size_t adc_range(int daq_adc_bits=12)
void print(const unsigned i) const
uint8_t s2_error(const unsigned &frame_ID, const uint8_t &block_num) const
void print_timestamps() const
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
uint8_t mm(const unsigned &frame_ID=0) const
size_t total_adc_values() const
uint8_t crate_no(const unsigned &frame_ID=0) const
uint8_t slot_no(const unsigned &frame_ID=0) const
virtual uint16_t wib_counter(const unsigned &frame_ID=0) const =0
virtual size_t total_adc_values() const =0
size_t dataSizeBytes() const
virtual uint16_t checksum_a(const unsigned &frame_ID, const uint8_t &block_num) const =0
uint8_t hdr(const unsigned &frame_ID, const uint8_t &block_num, const uint8_t &hdr_num) const
int read(int, char *, size_t)
Read bytes from a file descriptor.
dune::WIBHeader const * head_(const unsigned int frame_num) const
uint16_t checksum_a(const unsigned &frame_ID, const uint8_t &block_num) const
uint16_t coldata_convert_count(const unsigned &frame_ID, const uint8_t &block_num) const
size_t total_words() const
adc_v get_ADCs_by_channel(const uint8_t block_ID, const uint8_t channel_ID) const
const uint8_t * dataBeginBytes() const
void print(const unsigned i) const
adc_t get_ADC(const unsigned &frame_ID, const uint8_t channel_ID) const
size_t total_frames() const
virtual uint8_t sof(const unsigned &frame_ID=0) const =0
std::map< uint8_t, adc_v > get_all_ADCs() const
virtual uint8_t crate_no(const unsigned &frame_ID=0) const =0
virtual uint8_t s2_error(const unsigned &frame_ID, const uint8_t &block_num) const =0
uint8_t oos(const unsigned &frame_ID=0) const
uint8_t sof(const unsigned &frame_ID=0) const
FelixFragment(const artdaq::Fragment &fragment)
QTextStream & endl(QTextStream &s)
virtual uint16_t error_register(const unsigned &frame_ID, const uint8_t &block_num) const =0
void print_frames() const
size_t total_adc_values() const
uint8_t mm(const unsigned &frame_ID=0) const
uint64_t timestamp(const unsigned &frame_ID=0) const