diff --git a/acquisition_device/AcquisitionDevice.cpp b/acquisition_device/AcquisitionDevice.cpp index a422fb581..7e2d070a3 100644 --- a/acquisition_device/AcquisitionDevice.cpp +++ b/acquisition_device/AcquisitionDevice.cpp @@ -14,11 +14,34 @@ AcquisitionDevice::AcquisitionDevice(uint16_t in_data_stream) { data_stream = in_data_stream; } +uint64_t AcquisitionDevice::GeneratorModuleFrames(uint32_t hbm_size_bytes) { + return 2 * static_cast(hbm_size_bytes) / (RAW_MODULE_SIZE * sizeof(uint16_t)); +} + +// frame_generator.cpp refuses a run that fills its memory, and load_calibration.cpp lets one module frame past it +// through, so the host keeps the last one free. +void AcquisitionDevice::CheckInternalGeneratorFrame(size_t module_frame) const { + if (module_frame + 1 >= internal_generator_module_frames) + throw JFJochException(JFJochExceptionCategory::InputParameterAboveMax, + "Internal frame generator: the card memory holds " + + std::to_string(internal_generator_module_frames - 1) + + " module frames (modules x images), this needs " + + std::to_string(module_frame + 1)); +} + void AcquisitionDevice::PrepareAction(const DiffractionExperiment &experiment) { if (experiment.GetModulesNum(data_stream) > max_modules) throw(JFJochException(JFJochExceptionCategory::InputParameterAboveMax, "Number of modules exceeds max possible for FPGA")); + if (experiment.IsUsingInternalPacketGen()) { + int64_t module_frames = experiment.GetModulesNum(data_stream) * experiment.GetInternalPacketGeneratorImages(); + // A 32-bit EIGER frame takes two + if ((experiment.GetDetectorType() == DetectorType::EIGER) && (experiment.GetBitDepthReadout() == 32)) + module_frames *= 2; + CheckInternalGeneratorFrame(module_frames - 1); + } + counters.Reset(experiment, data_stream); } diff --git a/acquisition_device/AcquisitionDevice.h b/acquisition_device/AcquisitionDevice.h index 7b9d59e1b..41f2d30ee 100644 --- a/acquisition_device/AcquisitionDevice.h +++ b/acquisition_device/AcquisitionDevice.h @@ -57,6 +57,10 @@ protected: uint16_t data_stream; uint32_t max_modules = 1; + // Module frames the card memory holds for the internal frame generator + uint64_t internal_generator_module_frames = 0; + // As frame_generator.cpp: the frames are in two HBM interfaces of hbm_size_bytes each + static uint64_t GeneratorModuleFrames(uint32_t hbm_size_bytes); uint64_t mac_addr; uint32_t ipv4_addr; explicit AcquisitionDevice(uint16_t data_stream); @@ -117,5 +121,7 @@ public: virtual uint32_t GetExpectedDescriptorsPerModule() const = 0; void RunInternalGenerator(const DiffractionExperiment& experiment); + // The module frame of the internal frame generator's images, throws if the card memory cannot hold it + void CheckInternalGeneratorFrame(size_t module_frame) const; }; diff --git a/acquisition_device/FPGAAcquisitionDevice.cpp b/acquisition_device/FPGAAcquisitionDevice.cpp index 87bda00bf..f7b24a08b 100644 --- a/acquisition_device/FPGAAcquisitionDevice.cpp +++ b/acquisition_device/FPGAAcquisitionDevice.cpp @@ -123,6 +123,7 @@ void FPGAAcquisitionDevice::InitializeIntegrationMap(const uint16_t *map, const } void FPGAAcquisitionDevice::SetInternalGeneratorFrame(const uint16_t *input, size_t module_number) { + CheckInternalGeneratorFrame(module_number); memcpy(buffer_device[0]->pixels, input, RAW_MODULE_SIZE * sizeof(uint16_t)); buffer_device[0]->module_statistics.module_number = module_number; buffer_device[0]->module_statistics.load_calibration_destination = LOAD_CALIBRATION_DEST_FRAME_GEN; diff --git a/acquisition_device/HLSSimulatedDevice.cpp b/acquisition_device/HLSSimulatedDevice.cpp index 54e8c5b33..e36a794dd 100644 --- a/acquisition_device/HLSSimulatedDevice.cpp +++ b/acquisition_device/HLSSimulatedDevice.cpp @@ -17,6 +17,7 @@ HLSSimulatedDevice::HLSSimulatedDevice(uint16_t data_stream, size_t in_frame_buf } device = std::make_unique(buffer_device); + internal_generator_module_frames = GeneratorModuleFrames(device->GetDataCollectionStatus().hbm_size_bytes); } void HLSSimulatedDevice::CreateFinalPacket(const DiffractionExperiment& experiment) { @@ -60,6 +61,9 @@ void HLSSimulatedDevice::HW_RunInternalGenerator(const FrameGeneratorConfig &con void HLSSimulatedDevice::FPGA_EndAction() { device->FPGA_EndAction(); + if (const int result = device->GetFrameGeneratorResult(); result != 0) + throw JFJochException(JFJochExceptionCategory::AcquisitionDeviceError, + "Internal frame generator refused its configuration, error code " + std::to_string(result)); } diff --git a/acquisition_device/MockAcquisitionDevice.cpp b/acquisition_device/MockAcquisitionDevice.cpp index 31a0c5ac1..6309f0467 100644 --- a/acquisition_device/MockAcquisitionDevice.cpp +++ b/acquisition_device/MockAcquisitionDevice.cpp @@ -26,6 +26,8 @@ MockAcquisitionDevice::MockAcquisitionDevice(uint16_t data_stream, size_t in_fra ipv4_addr = 0x0132010A; max_modules = MAX_MODULES_FPGA; + // As FrameGenerator below + internal_generator_module_frames = 64; buffers.reserve(in_frame_buffer_size_modules); for (size_t i = 0; i < in_frame_buffer_size_modules; i++) { diff --git a/acquisition_device/PCIExpressDevice.cpp b/acquisition_device/PCIExpressDevice.cpp index 3fa146fd0..767a872fe 100644 --- a/acquisition_device/PCIExpressDevice.cpp +++ b/acquisition_device/PCIExpressDevice.cpp @@ -20,6 +20,7 @@ PCIExpressDevice::PCIExpressDevice(uint16_t data_stream, const std::string &devi max_modules = status.max_modules; if (max_modules == 0) throw JFJochException(JFJochExceptionCategory::PCIeError, "Max modules cannot be zero"); + internal_generator_module_frames = GeneratorModuleFrames(status.hbm_size_bytes); uint32_t num_buf = GetNumKernelBuffers(); diff --git a/fpga/hls_simulation/HLSDevice.cpp b/fpga/hls_simulation/HLSDevice.cpp index 7752a083f..828c80bcb 100644 --- a/fpga/hls_simulation/HLSDevice.cpp +++ b/fpga/hls_simulation/HLSDevice.cpp @@ -216,17 +216,25 @@ void HLSDevice::FPGA_StartAction() { } void HLSDevice::FrameGeneratorFuture(FrameGeneratorConfig config) { - frame_generator(impl_->din_eth, - impl_->hbm.data(), - impl_->hbm.data(), - impl_->hbm_if_size, - mac_addr, - ipv4_addr, - impl_->cancel_data_collection, - config); + frame_generator_result = frame_generator(impl_->din_eth, + impl_->hbm.data(), + impl_->hbm.data(), + impl_->hbm_if_size, + mac_addr, + ipv4_addr, + impl_->cancel_data_collection, + config); + // A generator that refused its configuration sends no frame: the data collection ends instead of waiting for them + if (frame_generator_result != 0) + impl_->cancel_data_collection = 1; +} + +int HLSDevice::GetFrameGeneratorResult() const { + return frame_generator_result; } void HLSDevice::HW_RunInternalGenerator(const FrameGeneratorConfig &config) { + frame_generator_result = 0; frame_generator_future = std::async(std::launch::async, &HLSDevice::FrameGeneratorFuture, this, config); } diff --git a/fpga/hls_simulation/HLSDevice.h b/fpga/hls_simulation/HLSDevice.h index 1e73b28b9..d5294c8ec 100644 --- a/fpga/hls_simulation/HLSDevice.h +++ b/fpga/hls_simulation/HLSDevice.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include @@ -19,6 +20,7 @@ class HLSDevice { std::thread action_thread; std::future frame_generator_future; + std::atomic frame_generator_result{0}; std::vector dma_address_table; uint64_t eth_packets = 0; uint64_t icmp_packets = 0; @@ -52,6 +54,8 @@ public: void CreateXfelBunchIDPacket(double bunchid, uint32_t event_code); DataCollectionStatus GetDataCollectionStatus() const ; + // What frame_generator returned in the last run, 0 if it was not run or went fine + int GetFrameGeneratorResult() const; void Cancel() ; void HW_ReadActionRegister(DataCollectionConfig *job); diff --git a/tests/MockAcquisitionDeviceTest.cpp b/tests/MockAcquisitionDeviceTest.cpp index 0c4148ebe..746a9a62a 100644 --- a/tests/MockAcquisitionDeviceTest.cpp +++ b/tests/MockAcquisitionDeviceTest.cpp @@ -447,3 +447,23 @@ TEST_CASE("MockAcquisitionDevice_SameAsHLS_Receiver", "[MockAcquisitionDevice][H CHECK(memcmp(mock_plots[i].data(), hls_plots[i].data(), hls_plots[i].size() * sizeof(float)) == 0); } } + +TEST_CASE("MockAcquisitionDevice_InternalGeneratorMemory", "[MockAcquisitionDevice]") { + // 64 module frames in the card memory; the generator takes 63 at most + DiffractionExperiment x(DetJF(2)); + x.UseInternalPacketGenerator(true).ImagesPerTrigger(1).NumTriggers(1); + MockAcquisitionDevice device(0, 64); + HLSSimulatedDevice hls_device(0, 64); + + x.InternalPacketGeneratorImages(31); + REQUIRE_NOTHROW(device.PrepareAction(x)); + REQUIRE_NOTHROW(hls_device.PrepareAction(x)); + + x.InternalPacketGeneratorImages(32); + REQUIRE_THROWS(device.PrepareAction(x)); + REQUIRE_THROWS(hls_device.PrepareAction(x)); + + std::vector frame(RAW_MODULE_SIZE); + REQUIRE_NOTHROW(hls_device.SetInternalGeneratorFrame(frame.data(), 62)); + REQUIRE_THROWS(hls_device.SetInternalGeneratorFrame(frame.data(), 63)); +}