diff --git a/common/DiffractionExperiment.cpp b/common/DiffractionExperiment.cpp index 1eb9788c..c863689e 100644 --- a/common/DiffractionExperiment.cpp +++ b/common/DiffractionExperiment.cpp @@ -108,7 +108,7 @@ DiffractionExperiment &DiffractionExperiment::Mode(DetectorMode input) { } DiffractionExperiment &DiffractionExperiment::DataStreams(int64_t input) { - check_max("Number of data streams", input, 7); + check_max("Number of data streams", input, 16); check_min("Number of data streams", input, 1); internal.set_ndatastreams(input); return *this; diff --git a/receiver/MockAcquisitionDevice.cpp b/receiver/MockAcquisitionDevice.cpp index 7f64914b..513cb843 100644 --- a/receiver/MockAcquisitionDevice.cpp +++ b/receiver/MockAcquisitionDevice.cpp @@ -4,11 +4,25 @@ #include "MockAcquisitionDevice.h" #include "../common/JFJochException.h" #include +#include "../jungfrau/JFConversionFloatingPoint.h" void MockAcquisitionDevice::Start(const DiffractionExperiment& experiment) { idle = false; cancel = false; - measure = std::async(std::launch::async, &MockAcquisitionDevice::MeasureThread, this); + + if (experiment.IsUsingInternalPacketGen()) { + if (experiment.GetDetectorMode() == DetectorMode::Conversion) { + for (auto &i: buffer_device) + memcpy(i, internal_pkt_gen_frame_conv.data(), RAW_MODULE_SIZE * sizeof(uint16_t)); + } else { + for (auto &i: buffer_device) + memcpy(i, internal_pkt_gen_frame.data(), RAW_MODULE_SIZE * sizeof(uint16_t)); + } + measure = std::async(std::launch::async, &MockAcquisitionDevice::InternalPacketGeneratorThread, this, + experiment.GetModulesNum(data_stream), experiment.GetFrameNum()); + } else { + measure = std::async(std::launch::async, &MockAcquisitionDevice::MeasureThread, this); + } } void MockAcquisitionDevice::Cancel() { @@ -20,10 +34,15 @@ void MockAcquisitionDevice::Cancel() { } MockAcquisitionDevice::MockAcquisitionDevice(uint16_t data_stream, size_t in_frame_buffer_size_modules) -: AcquisitionDevice(data_stream) { +: AcquisitionDevice(data_stream), internal_pkt_gen_frame(RAW_MODULE_SIZE), internal_pkt_gen_frame_conv(RAW_MODULE_SIZE) { max_modules = 16; MapBuffersStandard(in_frame_buffer_size_modules, 1, -1); max_handle = in_frame_buffer_size_modules; + + for (int i = 0; i < RAW_MODULE_SIZE; i++) { + internal_pkt_gen_frame[i] = i % 65536; + internal_pkt_gen_frame_conv[i] = i % 65536; + } } void MockAcquisitionDevice::SendCompletion(uint32_t handle, uint16_t module_number, uint64_t frame_number) { @@ -74,6 +93,40 @@ void MockAcquisitionDevice::MeasureThread() { idle = true; } +void MockAcquisitionDevice::InternalPacketGeneratorThread(uint32_t nmodules, uint32_t nframes) { + work_completion_queue.Put(Completion{.type = Completion::Type::Start}); + uint32_t curr_module = 0; + uint32_t curr_frame = 0; + + while ((!cancel) && (curr_frame < nframes)) { + WorkRequest wr{}; + if (work_request_queue.Get(wr)) { + Completion c{}; + + c.handle = wr.handle; + c.module_number = curr_module; + c.frame_number = curr_frame; + c.type = Completion::Type::Image; + c.packet_mask[0] = UINT64_MAX; + c.packet_mask[1] = UINT64_MAX; + c.packet_count = 128; + work_completion_queue.Put(c); + + curr_module++; + if (curr_module == nmodules) { + curr_module = 0; + curr_frame++; + } + } else + std::this_thread::sleep_for(std::chrono::microseconds(100)); + } + + work_completion_queue.Put(Completion{ + .type = Completion::Type::End + }); + idle = true; +} + void MockAcquisitionDevice::Terminate() { mock_completions.Put(Completion{ .type = Completion::Type::End @@ -91,4 +144,27 @@ std::string MockAcquisitionDevice::GetIPv4Address() const { void MockAcquisitionDevice::Finalize() { if (measure.valid()) measure.get(); -} \ No newline at end of file +} + +void MockAcquisitionDevice::SetCustomInternalGeneratorFrame(const std::vector &v) { + if (v.size() != RAW_MODULE_SIZE) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Error in size of custom internal generator frame"); + + internal_pkt_gen_frame = v; + internal_pkt_gen_frame_conv = v; +} + +void MockAcquisitionDevice::InitializeCalibration(const DiffractionExperiment &experiment, const JFCalibration &calib) { + JFConversionFloatingPoint conv; + conv.Setup(calib.GainCalibration(experiment.GetFirstModuleOfDataStream(data_stream)), + calib.Pedestal(experiment.GetFirstModuleOfDataStream(data_stream),0), + calib.Pedestal(experiment.GetFirstModuleOfDataStream(data_stream),1), + calib.Pedestal(experiment.GetFirstModuleOfDataStream(data_stream),2), + experiment.GetPhotonEnergy_keV()); + conv.ConvertModule((int16_t *) internal_pkt_gen_frame_conv.data(), internal_pkt_gen_frame.data()); +} + +std::vector MockAcquisitionDevice::GetInternalGeneratorFrame() const { + return internal_pkt_gen_frame; +} diff --git a/receiver/MockAcquisitionDevice.h b/receiver/MockAcquisitionDevice.h index 677d8d7f..c53d4d2b 100644 --- a/receiver/MockAcquisitionDevice.h +++ b/receiver/MockAcquisitionDevice.h @@ -15,12 +15,14 @@ class MockAcquisitionDevice : public AcquisitionDevice { bool idle = true; std::future measure; volatile bool cancel = false; - + std::vector internal_pkt_gen_frame; + std::vector internal_pkt_gen_frame_conv; ThreadSafeFIFO mock_completions; void SendCompletion(uint32_t handle, uint16_t module_number, uint64_t frame_number); void Start(const DiffractionExperiment& experiment) override; void MeasureThread(); + void InternalPacketGeneratorThread(uint32_t nmodules, uint32_t nframes); public: MockAcquisitionDevice(uint16_t data_stream, size_t in_frame_buffer_size_modules); void AddModule(uint64_t frame, uint16_t module_number, const uint16_t *data); @@ -29,6 +31,13 @@ public: std::string GetIPv4Address() const override; void Cancel() override; void Finalize() override; + + // Warning - internal packet generator in MockAcquisitionDevice has one limitation: + // it assumes the same calibration for all modules of the device + // For routine receiver tests one should always set one module per device + void SetCustomInternalGeneratorFrame(const std::vector &v); + std::vector GetInternalGeneratorFrame() const override; + void InitializeCalibration(const DiffractionExperiment &experiment, const JFCalibration &calib) override; }; #endif //JUNGFRAUJOCH_MOCKACQUISITIONDEVICE_H diff --git a/tests/MockAcquisitionDeviceTest.cpp b/tests/MockAcquisitionDeviceTest.cpp index 30a72155..9f0dff6a 100644 --- a/tests/MockAcquisitionDeviceTest.cpp +++ b/tests/MockAcquisitionDeviceTest.cpp @@ -3,6 +3,7 @@ #include #include "../receiver/MockAcquisitionDevice.h" +#include "../receiver/JFJochReceiverTest.h" TEST_CASE("MockAcquisitionDevice") { std::vector module_data(RAW_MODULE_SIZE, 765); @@ -37,3 +38,70 @@ TEST_CASE("MockAcquisitionDevice") { RAW_MODULE_SIZE * sizeof(uint16_t)) == 0); } +TEST_CASE("JFJochReceiverTest_Raw_MockAcquisitionDevice", "[JFJochReceiver]") { + Logger logger("JFJochReceiverTest_Raw_MockAcquisitionDevice"); + logger.Verbose(true); + + std::mt19937 g1(1387); + std::uniform_int_distribution dist(0, 65535); + + DiffractionExperiment x(DetectorGeometry(4)); + const uint16_t nthreads = 4; + + std::vector test_frame(RAW_MODULE_SIZE); + + x.Mode(DetectorMode::Raw); + x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true) + .ImagesPerTrigger(100).DataFileCount(16).PhotonEnergy_keV(12.4).Compression(JFJochProtoBuf::NO_COMPRESSION); + + std::vector> aq_devices; + for (int i = 0; i < x.GetDataStreamsNum(); i++) { + for (auto &j: test_frame) + j = dist(g1); + + auto *test = new MockAcquisitionDevice(i, 64); + test->EnableLogging(&logger); + test->SetCustomInternalGeneratorFrame(test_frame); + aq_devices.emplace_back(test); + } + + JFJochProtoBuf::ReceiverOutput output; + bool ret; + REQUIRE_NOTHROW(ret = JFJochReceiverTest(output, logger, aq_devices, x, nthreads, false)); + REQUIRE(ret); + REQUIRE(output.efficiency() == 1.0); + REQUIRE(output.images_sent() == x.GetImageNum()); + REQUIRE(output.compressed_ratio() == 1.0); + REQUIRE(output.compressed_size() == x.GetImageNum() * x.GetPixelDepth() * x.GetPixelsNum()); + REQUIRE(output.max_image_number_sent() == x.GetImageNum() - 1); + REQUIRE(!output.cancelled()); +} + + +TEST_CASE("JFJochReceiverTest_Conversion_MockAcquisitionDevice", "[JFJochReceiver]") { + Logger logger("JFJochReceiverTest_Conversion"); + + DiffractionExperiment x(DetectorGeometry(8)); + const uint16_t nthreads = 4; + + x.Mode(DetectorMode::Conversion); + x.PedestalG0Frames(0).NumTriggers(1).UseInternalPacketGenerator(true).DataStreams(x.GetModulesNum()) + .ImagesPerTrigger(32).DataFileCount(16).PhotonEnergy_keV(12.4).Compression(JFJochProtoBuf::BSHUF_ZSTD); + + std::vector> aq_devices; + for (int i = 0; i < x.GetDataStreamsNum(); i++) { + AcquisitionDevice *test; + test = new MockAcquisitionDevice(i, 64); + test->EnableLogging(&logger); + aq_devices.emplace_back(test); + } + + JFJochProtoBuf::ReceiverOutput output; + bool ret; + REQUIRE_NOTHROW(ret = JFJochReceiverTest(output, logger, aq_devices, x, nthreads, false)); + REQUIRE(ret); + REQUIRE(output.efficiency() == 1.0); + REQUIRE(output.images_sent() == x.GetImageNum()); + + REQUIRE(!output.cancelled()); +}