11#include "data_types.hpp"
12#include "int_arith.hpp"
13#include "int_types.hpp"
14#include "introspect.hpp"
16#include "npint_ops.hpp"
17#include "processor.hpp"
18#include "read_integers.hpp"
19#include "time_tagged_events.hpp"
87 [[nodiscard]]
constexpr auto marker_flag() const noexcept ->
bool {
101 [[nodiscard]]
constexpr auto gap_flag() const noexcept ->
bool {
123 [[nodiscard]]
constexpr auto
134 [[nodiscard]]
constexpr auto
156 bool macrotime_overflow =
false)
158 return make_from_fields(
false, macrotime_overflow,
false,
false,
177 return make_from_fields(
true,
false,
false,
false,
adc_value, 0_u8np,
196 bool macrotime_overflow =
false)
198 return make_from_fields(
true, macrotime_overflow,
false,
true, 0_u16np,
223 throw std::invalid_argument(
224 "bit for marker 0 must be set in intensity counter event");
225 return make_from_fields(
true, macrotime_overflow,
false,
true,
count,
241 constexpr auto flags = 0b1100'0000_u8np;
246 std::byte((flags | (
u8np(
count >> 24) & 0x0f_u8np)).value()),
260 static constexpr auto gap_bit = std::byte(0b0010'0000);
261 bytes[3] = (
bytes[3] & ~gap_bit) | (gap ? gap_bit : std::byte(0));
272 return strm <<
"bh_spc(MT=" << e.macrotime()
273 <<
", ROUT=" << unsigned(e.routing_signals().value())
274 <<
", ADC=" << e.adc_value()
275 <<
", INVALID=" << e.invalid_flag()
276 <<
", MTOV=" << e.macrotime_overflow_flag()
277 <<
", GAP=" << e.gap_flag() <<
", MARK=" << e.marker_flag()
278 <<
", CNT=" << e.multiple_macrotime_overflow_count()
283 static constexpr auto make_from_fields(
bool invalid,
bool mtov,
bool gap,
286 auto const flags = (
u8np(
u8(invalid)) << 7) | (
u8np(
u8(mtov)) << 6) |
289 std::byte(
u8np(mt).value()),
290 std::byte(((rout << 4) | (
u8np(mt >> 8) & 0x0f_u8np)).value()),
291 std::byte(
u8np(adc).value()),
292 std::byte((flags | (
u8np(adc >> 8) & 0x0f_u8np)).value()),
342 return lo8 | (mid8 << 8) | (hi8 << 16);
348 [[nodiscard]]
static constexpr auto marker_flag() noexcept ->
bool {
362 [[nodiscard]]
constexpr auto gap_flag() const noexcept ->
bool {
384 [[nodiscard]]
static constexpr auto
393 [[nodiscard]]
static constexpr auto
415 bool macrotime_overflow =
false)
417 return make_from_fields(
macrotime,
route,
false, macrotime_overflow,
435 bool macrotime_overflow =
false)
437 return make_from_fields(
macrotime, 0_u8np,
false, macrotime_overflow,
451 static constexpr auto gap_bit = std::byte(0b0100'0000);
452 bytes[1] = (
bytes[1] & ~gap_bit) | (gap ? gap_bit : std::byte(0));
464 bool const unused_bit =
465 (
read_u8_at<1>(std::span(e.bytes)) & (1_u8np << 7)) != 0_u8np;
466 return strm <<
"bh_spc600_4096ch(MT=" << e.macrotime()
467 <<
", R=" << unsigned(e.routing_signals().value())
468 <<
", ADC=" << e.adc_value()
469 <<
", INVALID=" << e.invalid_flag()
470 <<
", MTOV=" << e.macrotime_overflow_flag()
471 <<
", GAP=" << e.gap_flag() <<
", bit15=" << unused_bit
476 static constexpr auto make_from_fields(
u32np mt,
u8np r,
bool gap,
477 bool mtov,
bool invalid,
u16np adc)
479 auto const flags = (
u8np(
u8(gap)) << 6) | (
u8np(
u8(mtov)) << 5) |
482 std::byte(
u8np(adc).value()),
483 std::byte((flags | (
u8np(adc >> 8) & 0x0f_u8np)).value()),
484 std::byte(
u8np(mt >> 16).value()),
485 std::byte(r.value()),
486 std::byte(
u8np(mt >> 0).value()),
487 std::byte(
u8np(mt >> 8).value()),
537 return lo8 | (mid8 << 8) | (hi1 << 16);
543 [[nodiscard]]
static constexpr auto marker_flag() noexcept ->
bool {
557 [[nodiscard]]
constexpr auto gap_flag() const noexcept ->
bool {
579 [[nodiscard]]
constexpr auto
588 [[nodiscard]]
constexpr auto
610 bool macrotime_overflow =
false)
612 return make_from_fields(
false, macrotime_overflow,
false,
route,
631 return make_from_fields(
true,
false,
false, 0_u8np,
macrotime,
647 constexpr auto flags = 0b1100'0000_u8np;
652 std::byte((flags | (
u8np(
count >> 24) & 0x0f_u8np)).value()),
666 static constexpr auto gap_bit = std::byte(0b0010'0000);
667 bytes[3] = (
bytes[3] & ~gap_bit) | (gap ? gap_bit : std::byte(0));
679 bool const unused_bit =
680 (
read_u8_at<3>(std::span(e.bytes)) & (1_u8np << 4)) != 0_u8np;
681 return strm <<
"bh_spc600_256ch(MT=" << e.macrotime()
682 <<
", R=" << unsigned(e.routing_signals().value())
683 <<
", ADC=" << e.adc_value()
684 <<
", INVALID=" << e.invalid_flag()
685 <<
", MTOV=" << e.macrotime_overflow_flag()
686 <<
", GAP=" << e.gap_flag() <<
", bit28=" << unused_bit
687 <<
", CNT=" << e.multiple_macrotime_overflow_count()
692 static constexpr auto make_from_fields(
bool invalid,
bool mtov,
bool gap,
695 auto const flags = (
u8np(
u8(invalid)) << 7) | (
u8np(
u8(mtov)) << 6) |
698 std::byte(adc.value()),
699 std::byte(
u8np(mt).value()),
700 std::byte(
u8np(mt >> 8).value()),
701 std::byte((flags | ((r << 1) & 0b1110_u8np) |
702 (
u8np(mt >> 16) & 0x01_u8np))
712template <
typename DataTypes,
typename BHSPCEvent,
bool HasIntensityCounter,
716 same_as_any_of<BHSPCEvent, bh_spc_event, bh_spc600_256ch_event,
717 bh_spc600_4096ch_event>);
719 static_assert(processor<Downstream, time_reached_event<DataTypes>,
720 time_correlated_detection_event<DataTypes>,
721 data_lost_event<DataTypes>, warning_event>);
722 static_assert(handler_for<Downstream, bulk_counts_event<DataTypes>> ||
723 not HasIntensityCounter);
724 static_assert(handler_for<Downstream, marker_event<DataTypes>> ||
725 not BHSPCEvent::has_markers);
728 static_assert(
sizeof(
typename DataTypes::abstime_type) >= 4);
730 static_assert(std::in_range<typename DataTypes::channel_type>(255) ||
731 (not std::is_same_v<BHSPCEvent, bh_spc600_4096ch_event> &&
732 std::in_range<typename DataTypes::channel_type>(15)));
734 static_assert(std::in_range<typename DataTypes::difftime_type>(4095) ||
735 (std::is_same_v<BHSPCEvent, bh_spc600_256ch_event> &&
736 std::in_range<typename DataTypes::difftime_type>(255)));
738 static_assert(std::in_range<typename DataTypes::count_type>(4095) ||
739 not HasIntensityCounter);
741 using abstime_type =
typename DataTypes::abstime_type;
743 abstime_type abstime_base = 0;
745 Downstream downstream;
747 LIBTCSPC_NOINLINE
void issue_warning(
char const *message) {
748 downstream.handle(warning_event{message});
751 void handle_bh(BHSPCEvent
const &event) {
752 if (event.is_multiple_macrotime_overflow()) {
754 abstime_type(BHSPCEvent::macrotime_overflow_period) *
755 event.multiple_macrotime_overflow_count().value();
756 if (event.gap_flag())
757 downstream.handle(data_lost_event<DataTypes>{abstime_base});
758 return downstream.handle(
759 time_reached_event<DataTypes>{abstime_base});
762 if (event.macrotime_overflow_flag())
763 abstime_base += BHSPCEvent::macrotime_overflow_period;
764 abstime_type
const abstime = abstime_base +
event.macrotime().value();
766 if (event.gap_flag())
767 downstream.handle(data_lost_event<DataTypes>{abstime});
769 if (not event.marker_flag()) {
770 if (not event.invalid_flag()) {
771 downstream.handle(time_correlated_detection_event<DataTypes>{
772 abstime,
event.routing_signals().value(),
773 event.adc_value().value()});
775 downstream.handle(time_reached_event<DataTypes>{abstime});
778 if (event.invalid_flag()) {
779 auto const bits =
u32np(event.marker_bits());
780 if constexpr (HasIntensityCounter) {
781 if ((bits & 0x01_u32np) != 0_u32np)
782 downstream.handle(bulk_counts_event<DataTypes>{
783 abstime, -1,
event.adc_value().value()});
785 if constexpr (BHSPCEvent::has_markers) {
786 for_each_set_bit(bits, [&](
int b) {
787 downstream.handle(marker_event<DataTypes>{
789 static_cast<typename DataTypes::channel_type
>(b)});
796 "unexpected BH SPC event flags: marker bit set but invalid bit cleared");
802 explicit decode_bh_spc(Downstream downstream)
803 : downstream(std::move(downstream)) {}
805 [[nodiscard]]
auto introspect_node() const -> processor_info {
806 return processor_info(
this,
"decode_bh_spc");
809 [[nodiscard]]
auto introspect_graph() const -> processor_graph {
810 return downstream.introspect_graph().push_entry_point(
this);
813 template <
typename Event>
814 requires std::convertible_to<std::remove_cvref_t<Event>, BHSPCEvent>
815 void handle(Event &&event) {
819 template <
typename Event>
821 not std::convertible_to<std::remove_cvref_t<Event>, BHSPCEvent> and
822 handler_for<Downstream, std::remove_cvref_t<Event>>)
823 void handle(Event &&event) {
824 downstream.handle(std::forward<Event>(event));
827 void flush() { downstream.flush(); }
863template <
typename DataTypes = default_data_types,
typename Downstream>
865 return internal::decode_bh_spc<DataTypes, bh_spc_event, false, Downstream>(
866 std::move(downstream));
896template <
typename DataTypes = default_data_types,
typename Downstream>
898 return internal::decode_bh_spc<DataTypes, bh_spc_event, true, Downstream>(
899 std::move(downstream));
925template <
typename DataTypes = default_data_types,
typename Downstream>
928 Downstream>(std::move(downstream));
954template <
typename DataTypes = default_data_types,
typename Downstream>
957 Downstream>(std::move(downstream));
npint< u32 > u32np
Non-promoted unsigned 32-bit integer.
Definition npint.hpp:306
constexpr auto read_u8_at(std::span< T, N > bytes) noexcept -> u8np
Read an 8-bit unsigned integer from bytes at offset.
Definition read_integers.hpp:77
constexpr auto read_u32le_at(std::span< T, N > bytes) noexcept -> u32np
Read a little-endian 32-bit unsigned integer from bytes at offset.
Definition read_integers.hpp:102
npint< u8 > u8np
Non-promoted unsigned 8-bit integer.
Definition npint.hpp:292
npint< u16 > u16np
Non-promoted unsigned 16-bit integer.
Definition npint.hpp:299
constexpr auto read_u16le_at(std::span< T, N > bytes) noexcept -> u16np
Read a little-endian 16-bit unsigned integer from bytes at offset.
Definition read_integers.hpp:90
auto decode_bh_spc600_256ch(Downstream downstream)
Create a processor that decodes 32-bit FIFO records from Becker & Hickl SPC-600/630 in 256-channel mo...
Definition bh_spc.hpp:955
auto decode_bh_spc(Downstream downstream)
Create a processor that decodes FIFO records from most Becker & Hickl SPC models.
Definition bh_spc.hpp:864
auto decode_bh_spc600_4096ch(Downstream downstream)
Create a processor that decodes 48-bit FIFO records from Becker & Hickl SPC-600/630 in 4096-channel m...
Definition bh_spc.hpp:926
auto decode_bh_spc_with_intensity_counter(Downstream downstream)
Create a processor that decodes FIFO records from Becker & Hickl SPC-160 and SPC-180N with fast inten...
Definition bh_spc.hpp:897
auto route(Router router, Downstreams... downstreams)
Create a processor that routes events to different downstreams.
Definition route.hpp:250
auto count(access_tracker< count_access > &&tracker, Downstream downstream)
Create a processor that counts events of a given type.
Definition count.hpp:313
std::uint8_t u8
Short name for uint8_t.
Definition int_types.hpp:24
std::uint32_t u32
Short name for uint32_t.
Definition int_types.hpp:30
libtcspc namespace.
Definition acquire.hpp:29
Binary record interpretation for raw events from SPC-600/630 in 256-channel mode.
Definition bh_spc.hpp:498
static constexpr u32 macrotime_overflow_period
The macrotime overflow period of this event type.
Definition bh_spc.hpp:507
static constexpr auto marker_flag() noexcept -> bool
Read the 'marker' flag.
Definition bh_spc.hpp:543
constexpr auto macrotime_overflow_flag() const noexcept -> bool
Read the 'macrotime overflow' flag.
Definition bh_spc.hpp:564
static constexpr auto make_multiple_macrotime_overflow(u32np count) -> bh_spc600_256ch_event
Make an event representing a multiple macrotime overflow.
Definition bh_spc.hpp:645
static constexpr auto make_photon(u32np macrotime, u8np adc_value, u8np route, bool macrotime_overflow=false) -> bh_spc600_256ch_event
Make an event representing a valid photon event.
Definition bh_spc.hpp:608
std::array< std::byte, 4 > bytes
Bytes of the 32-bit raw device event.
Definition bh_spc.hpp:502
constexpr auto invalid_flag() const noexcept -> bool
Read the 'invalid' flag.
Definition bh_spc.hpp:572
constexpr auto macrotime() const noexcept -> u32np
Read the macrotime counter value (no rollover correction).
Definition bh_spc.hpp:533
constexpr auto gap_flag() const noexcept -> bool
Read the 'gap' (data lost) flag.
Definition bh_spc.hpp:557
auto gap_flag(bool gap) noexcept -> bh_spc600_256ch_event &
Set or clear the gap flag of this event.
Definition bh_spc.hpp:665
constexpr auto is_multiple_macrotime_overflow() const noexcept -> bool
Determine if this event represents multiple macrotime overflows.
Definition bh_spc.hpp:580
constexpr auto multiple_macrotime_overflow_count() const noexcept -> u32np
Read the macrotime overflow count if this event represents multiple macrotime overflows.
Definition bh_spc.hpp:589
friend auto operator<<(std::ostream &strm, bh_spc600_256ch_event const &e) -> std::ostream &
Stream insertion operator.
Definition bh_spc.hpp:677
constexpr auto adc_value() const noexcept -> u16np
Read the ADC value (i.e., difference time) if this event represents a photon.
Definition bh_spc.hpp:518
static constexpr bool has_markers
Whether this event type can represent marker events.
Definition bh_spc.hpp:512
constexpr auto routing_signals() const noexcept -> u8np
Read the routing signals (usually the detector channel) if this event represents a photon.
Definition bh_spc.hpp:526
friend auto operator==(bh_spc600_256ch_event const &lhs, bh_spc600_256ch_event const &rhs) noexcept -> bool=default
Equality comparison operator.
static constexpr auto make_invalid_photon(u32np macrotime, u8np adc_value) -> bh_spc600_256ch_event
Make an event representing an invalid photon event.
Definition bh_spc.hpp:628
static constexpr auto marker_bits() noexcept -> u8np
Read the marker bits (mask) if this event represents markers.
Definition bh_spc.hpp:550
Binary record interpretation for raw events from SPC-600/630 in 4096-channel mode.
Definition bh_spc.hpp:303
static constexpr auto make_photon(u32np macrotime, u16np adc_value, u8np route, bool macrotime_overflow=false) -> bh_spc600_4096ch_event
Make an event representing a valid photon event.
Definition bh_spc.hpp:413
constexpr auto macrotime() const noexcept -> u32np
Read the macrotime counter value (no rollover correction).
Definition bh_spc.hpp:338
static constexpr u32 macrotime_overflow_period
The macrotime overflow period of this event type.
Definition bh_spc.hpp:312
constexpr auto gap_flag() const noexcept -> bool
Read the 'gap' (data lost) flag.
Definition bh_spc.hpp:362
friend auto operator==(bh_spc600_4096ch_event const &lhs, bh_spc600_4096ch_event const &rhs) noexcept -> bool=default
Equality comparison operator.
static constexpr auto multiple_macrotime_overflow_count() noexcept -> u32np
Read the macrotime overflow count if this event represents multiple macrotime overflows.
Definition bh_spc.hpp:394
friend auto operator<<(std::ostream &strm, bh_spc600_4096ch_event const &e) -> std::ostream &
Stream insertion operator.
Definition bh_spc.hpp:462
auto gap_flag(bool gap) noexcept -> bh_spc600_4096ch_event &
Set or clear the gap flag of this event.
Definition bh_spc.hpp:450
static constexpr auto is_multiple_macrotime_overflow() noexcept -> bool
Determine if this event represents multiple macrotime overflows.
Definition bh_spc.hpp:385
static constexpr auto marker_bits() noexcept -> u8np
Read the marker bits (mask) if this event represents markers.
Definition bh_spc.hpp:355
static constexpr bool has_markers
Whether this event type can represent marker events.
Definition bh_spc.hpp:317
static constexpr auto make_invalid_photon(u32np macrotime, u16np adc_value, bool macrotime_overflow=false) -> bh_spc600_4096ch_event
Make an event representing an invalid photon event.
Definition bh_spc.hpp:434
std::array< std::byte, 6 > bytes
Bytes of the 48-bit raw device event.
Definition bh_spc.hpp:307
constexpr auto routing_signals() const noexcept -> u8np
Read the routing signals (usually the detector channel) if this event represents a photon.
Definition bh_spc.hpp:331
static constexpr auto marker_flag() noexcept -> bool
Read the 'marker' flag.
Definition bh_spc.hpp:348
constexpr auto macrotime_overflow_flag() const noexcept -> bool
Read the 'macrotime overflow' flag.
Definition bh_spc.hpp:369
constexpr auto adc_value() const noexcept -> u16np
Read the ADC value (i.e., difference time) if this event represents a photon.
Definition bh_spc.hpp:323
constexpr auto invalid_flag() const noexcept -> bool
Read the 'invalid' flag.
Definition bh_spc.hpp:377
Binary record interpretation for raw BH SPC event.
Definition bh_spc.hpp:42
static constexpr auto make_marker(u16np macrotime, u8np marker_bits, bool macrotime_overflow=false) -> bh_spc_event
Make an event representing a marker.
Definition bh_spc.hpp:195
std::array< std::byte, 4 > bytes
Bytes of the 32-bit raw device event.
Definition bh_spc.hpp:46
auto gap_flag(bool gap) noexcept -> bh_spc_event &
Set or clear the gap flag of this event.
Definition bh_spc.hpp:259
constexpr auto invalid_flag() const noexcept -> bool
Read the 'invalid' flag.
Definition bh_spc.hpp:116
constexpr auto macrotime_overflow_flag() const noexcept -> bool
Read the 'macrotime overflow' flag.
Definition bh_spc.hpp:108
static constexpr auto make_photon(u16np macrotime, u16np adc_value, u8np route, bool macrotime_overflow=false) -> bh_spc_event
Make an event representing a valid photon event.
Definition bh_spc.hpp:154
static constexpr auto make_invalid_photon(u16np macrotime, u16np adc_value) -> bh_spc_event
Make an event representing an invalid photon event.
Definition bh_spc.hpp:174
constexpr auto adc_value() const noexcept -> u16np
Read the ADC value (i.e., difference time) if this event represents a photon.
Definition bh_spc.hpp:62
friend auto operator==(bh_spc_event const &lhs, bh_spc_event const &rhs) noexcept -> bool=default
Equality comparison operator.
friend auto operator<<(std::ostream &strm, bh_spc_event const &e) -> std::ostream &
Stream insertion operator.
Definition bh_spc.hpp:270
constexpr auto marker_flag() const noexcept -> bool
Read the 'marker' flag.
Definition bh_spc.hpp:87
constexpr auto routing_signals() const noexcept -> u8np
Read the routing signals (usually the detector channel) if this event represents a photon.
Definition bh_spc.hpp:70
constexpr auto multiple_macrotime_overflow_count() const noexcept -> u32np
Read the macrotime overflow count if this event represents multiple macrotime overflows.
Definition bh_spc.hpp:135
constexpr auto macrotime() const noexcept -> u16np
Read the macrotime counter value (no rollover correction).
Definition bh_spc.hpp:80
constexpr auto marker_bits() const noexcept -> u8np
Read the marker bits (mask) if this event represents markers.
Definition bh_spc.hpp:94
static constexpr u32 macrotime_overflow_period
The macrotime overflow period of this event type.
Definition bh_spc.hpp:51
static constexpr auto make_multiple_macrotime_overflow(u32np count) -> bh_spc_event
Make an event representing a multiple macrotime overflow.
Definition bh_spc.hpp:239
constexpr auto is_multiple_macrotime_overflow() const noexcept -> bool
Determine if this event represents multiple macrotime overflows.
Definition bh_spc.hpp:124
static constexpr auto make_marker0_with_intensity_count(u16np macrotime, u8np marker_bits, u16np count, bool macrotime_overflow=false) -> bh_spc_event
Make an event representing a marker, with marker 0 intensity count as generated by SPC-160 and SPC-18...
Definition bh_spc.hpp:219
constexpr auto gap_flag() const noexcept -> bool
Read the 'gap' (data lost) flag.
Definition bh_spc.hpp:101
static constexpr bool has_markers
Whether this event type can represent marker events.
Definition bh_spc.hpp:56