11#include "int_arith.hpp"
12#include "int_types.hpp"
13#include "introspect.hpp"
15#include "npint_ops.hpp"
16#include "numeric_traits.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 NumericTraits,
typename BHSPCEvent,
713 bool HasIntensityCounter,
typename Downstream>
714 requires processor<Downstream, time_reached_event<NumericTraits>,
715 time_correlated_detection_event<NumericTraits>,
716 data_lost_event<NumericTraits>, warning_event> &&
717 (handler_for<Downstream, bulk_counts_event<NumericTraits>> ||
718 not HasIntensityCounter) &&
719 (handler_for<Downstream, marker_event<NumericTraits>> ||
720 not BHSPCEvent::has_markers)
723 same_as_any_of<BHSPCEvent, bh_spc_event, bh_spc600_256ch_event,
724 bh_spc600_4096ch_event>);
727 static_assert(
sizeof(
typename NumericTraits::abstime_type) >= 4);
729 static_assert(std::in_range<typename NumericTraits::channel_type>(255) ||
730 (not std::is_same_v<BHSPCEvent, bh_spc600_4096ch_event> &&
731 std::in_range<typename NumericTraits::channel_type>(15)));
733 static_assert(std::in_range<typename NumericTraits::difftime_type>(4095) ||
734 (std::is_same_v<BHSPCEvent, bh_spc600_256ch_event> &&
735 std::in_range<typename NumericTraits::difftime_type>(255)));
737 static_assert(std::in_range<typename NumericTraits::count_type>(4095) ||
738 not HasIntensityCounter);
740 using abstime_type = NumericTraits::abstime_type;
742 abstime_type abstime_base = 0;
744 Downstream downstream;
746 LIBTCSPC_NOINLINE
void issue_warning(
char const *message) {
747 downstream.handle(warning_event{message});
750 void handle_bh(BHSPCEvent
const &event) {
751 if (event.is_multiple_macrotime_overflow()) {
753 abstime_type(BHSPCEvent::macrotime_overflow_period) *
754 event.multiple_macrotime_overflow_count().value();
755 if (event.gap_flag())
757 data_lost_event<NumericTraits>{abstime_base});
758 return downstream.handle(
759 time_reached_event<NumericTraits>{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<NumericTraits>{abstime});
769 if (not event.marker_flag()) {
770 if (not event.invalid_flag()) {
772 time_correlated_detection_event<NumericTraits>{
773 abstime,
event.routing_signals().value(),
774 event.adc_value().value()});
776 downstream.handle(time_reached_event<NumericTraits>{abstime});
779 if (event.invalid_flag()) {
780 auto const bits =
u32np(event.marker_bits());
781 if constexpr (HasIntensityCounter) {
782 if ((bits & 0x01_u32np) != 0_u32np)
783 downstream.handle(bulk_counts_event<NumericTraits>{
784 abstime, -1,
event.adc_value().value()});
786 if constexpr (BHSPCEvent::has_markers) {
787 for_each_set_bit(bits, [&](
int b) {
788 downstream.handle(marker_event<NumericTraits>{
790 static_cast<NumericTraits::channel_type
>(b)});
797 "unexpected BH SPC event flags: marker bit set but invalid bit cleared");
803 explicit decode_bh_spc(Downstream downstream)
804 : downstream(std::move(downstream)) {}
806 [[nodiscard]]
auto introspect_node() const -> processor_info {
807 return processor_info(
this,
"decode_bh_spc");
810 [[nodiscard]]
auto introspect_graph() const -> processor_graph {
811 return downstream.introspect_graph().push_entry_point(
this);
814 template <
typename Event>
815 requires std::convertible_to<std::remove_cvref_t<Event>, BHSPCEvent>
816 void handle(Event &&event) {
820 template <
typename Event>
822 not std::convertible_to<std::remove_cvref_t<Event>, BHSPCEvent> and
823 handler_for<Downstream, std::remove_cvref_t<Event>>)
824 void handle(Event &&event) {
825 downstream.handle(std::forward<Event>(event));
828 void flush() { downstream.flush(); }
865template <
typename NumericTraits = default_numeric_traits,
typename Downstream>
867 return internal::decode_bh_spc<NumericTraits,
bh_spc_event,
false,
868 Downstream>(std::move(downstream));
899template <
typename NumericTraits = default_numeric_traits,
typename Downstream>
901 return internal::decode_bh_spc<NumericTraits,
bh_spc_event,
true,
902 Downstream>(std::move(downstream));
928template <
typename NumericTraits = default_numeric_traits,
typename Downstream>
931 false, Downstream>(std::move(downstream));
957template <
typename NumericTraits = default_numeric_traits,
typename Downstream>
960 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:958
auto decode_bh_spc(Downstream downstream)
Create a processor that decodes FIFO records from most Becker & Hickl SPC models.
Definition bh_spc.hpp:866
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:929
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:900
auto route(Router router, Downstreams... downstreams)
Create a processor that routes events to different downstreams.
Definition route.hpp:273
auto count(access_tracker< count_accessor > &&tracker, Downstream downstream)
Create a processor that counts events of a given type.
Definition count.hpp:312
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:30
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