diff --git a/broker/JFJochBrokerParser.cpp b/broker/JFJochBrokerParser.cpp index 89aa6c0d..d78920d4 100644 --- a/broker/JFJochBrokerParser.cpp +++ b/broker/JFJochBrokerParser.cpp @@ -34,6 +34,19 @@ inline int64_t GET_I64(const nlohmann::json &j, const std::string& tag, int64_t return def; } +inline int32_t GET_I32(const nlohmann::json &j, const std::string& tag) { + if (j.contains(tag)) { + if (!j[tag].is_number_integer()) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + " must be integer"); + try { + return j[tag].get(); + } catch (std::exception &e) { + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + ": " + e.what()); + } + } else + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, tag + " is compulsory"); +} + inline int32_t GET_I32(const nlohmann::json &j, const std::string& tag, int32_t def) { if (j.contains(tag)) { if (!j[tag].is_number_integer()) @@ -245,8 +258,6 @@ DetectorSetup ParseDetectorSetup(const nlohmann::json &j) { std::string description = GET_STR(j, "description"); auto module_hostname = GET_STR_ARR(j, "module_hostname"); - auto tx_delay = GET_I64_ARR(j, "tx_delay"); - DetectorType detector_type; const std::string detector_type_str = GET_STR(j, "type", "jungfrau"); if (detector_type_str == "jungfrau") @@ -260,13 +271,22 @@ DetectorSetup ParseDetectorSetup(const nlohmann::json &j) { auto gain_files = GET_STR_ARR(j, "gain_files"); if (!gain_files.empty()) setup.LoadGain(gain_files); + } else if (detector_type == DetectorType::EIGER) { + auto trim_files = GET_STR_ARR(j, "trim_files"); + if (!trim_files.empty()) + setup.SetTrimFiles(trim_files); } + if (j.contains("high_voltage")) + setup.HighVoltage(GET_I32(j,"high_voltage")); + setup.UDPInterfaceCount(GET_I64(j, "udp_interface_count", 2)) .SensorThickness_um(GET_FLOAT(j, "sensor_thickness_um", 320.0f)) .PixelSize_um(GET_FLOAT(j, "pixel_size_um", 75.0f)) - .SensorMaterial(GET_STR(j, "sensor_material", "Si")) - .TxDelay(tx_delay); + .SensorMaterial(GET_STR(j, "sensor_material", "Si")); + + if (j.contains("tx_delay")) + setup.TxDelay(GET_I64_ARR(j, "tx_delay")); return setup; } @@ -300,13 +320,18 @@ void ParseFacilityConfiguration(const nlohmann::json &input, const std::string& } experiment.NeuralNetModelPath(GET_STR(j, "neural_net_model", "")); - experiment.PedestalG0Frames(GET_I64(j, "pedestal_g0_frames")); - experiment.PedestalG1Frames(GET_I64(j, "pedestal_g1_frames")); - experiment.PedestalG2Frames(GET_I64(j, "pedestal_g2_frames")); + if (j.contains("pedestal_g0_frames")) + experiment.PedestalG0Frames(GET_I64(j, "pedestal_g0_frames")); + if (j.contains("pedestal_g1_frames")) + experiment.PedestalG1Frames(GET_I64(j, "pedestal_g1_frames")); + if (j.contains("pedestal_g2_frames")) + experiment.PedestalG2Frames(GET_I64(j, "pedestal_g2_frames")); if (j.contains("detector_trigger_delay_us")) experiment.DetectorDelay(GET_TIME(j, "detector_trigger_delay_us")); + experiment.FrameTime(GET_TIME(j, "frame_time_us"), GET_TIME(j, "count_time_us")); - experiment.PreviewPeriod(GET_TIME(j, "preview_period_us")); + if (j.contains("preview_period_us")) + experiment.PreviewPeriod(GET_TIME(j, "preview_period_us")); experiment.UseInternalPacketGenerator(GET_BOOL(j, "internal_frame_generator", false)); if (experiment.IsUsingInternalPacketGen()) experiment.ConversionOnFPGA(false); diff --git a/common/DetectorSetup.cpp b/common/DetectorSetup.cpp index 1888c9df..6a7ee69e 100644 --- a/common/DetectorSetup.cpp +++ b/common/DetectorSetup.cpp @@ -17,9 +17,22 @@ DetectorSetup::DetectorSetup(const DetectorGeometry &in_geometry, description(in_description), det_modules_hostname(in_det_modules_hostname), detector_type(in_detector_type) { - if (!det_modules_hostname.empty() && (geometry.GetModulesNum() != det_modules_hostname.size())) - throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, - "Mismatch between number of modules in detector geometry and hostname"); + switch (detector_type) { + case DetectorType::EIGER: + high_voltage = 150; + if (!det_modules_hostname.empty() && (2 * geometry.GetModulesNum() != det_modules_hostname.size())) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Mismatch between number of modules in detector geometry and hostname (For EIGER - one module = 2 hostnames)"); + break; + case DetectorType::JUNGFRAU: + high_voltage = 120; + if (!det_modules_hostname.empty() && (geometry.GetModulesNum() != det_modules_hostname.size())) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Mismatch between number of modules in detector geometry and hostname"); + break; + default: + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Detector not supported"); + } } const DetectorGeometry &DetectorSetup::GetGeometry() const { @@ -72,6 +85,8 @@ const std::vector &DetectorSetup::GetGainCalibration() } int64_t DetectorSetup::GetUDPInterfaceCount() const { + if (detector_type == DetectorType::EIGER) + return 2; return udp_interface_count; } @@ -113,3 +128,23 @@ const std::vector &DetectorSetup::GetGainFileNames() const { DetectorType DetectorSetup::GetDetectorType() const { return detector_type; } + +DetectorSetup &DetectorSetup::HighVoltage(int32_t input) { + high_voltage = input; + return *this; +} + +int32_t DetectorSetup::GetHighVoltage() const { + return high_voltage; +} + +void DetectorSetup::SetTrimFiles(const std::vector &filenames) { + if (filenames.size() != 2 * GetModulesNum()) + throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, + "Mismatch in number of trim bit calibration files"); + trim_file_names = filenames; +} + +const std::vector &DetectorSetup::GetTrimFileNames() const { + return trim_file_names; +} diff --git a/common/DetectorSetup.h b/common/DetectorSetup.h index b0dd4f9c..7d4005ff 100644 --- a/common/DetectorSetup.h +++ b/common/DetectorSetup.h @@ -13,6 +13,7 @@ class DetectorSetup { DetectorGeometry geometry; std::vector det_modules_hostname; std::vector gain_file_names; + std::vector trim_file_names; std::vector gain_calibration; int64_t udp_interface_count = 2; float pixel_size_um = 75.0f; @@ -20,6 +21,7 @@ class DetectorSetup { float sensor_thickness_um = 320.0f; std::vector tx_delay; DetectorType detector_type; + int32_t high_voltage = 120.0; public: // This is implicit constructor from DetectorGeometry with JUNGFRAU! // TODO: Remove implicit constructor @@ -31,12 +33,14 @@ public: const std::vector &det_modules_hostname); void LoadGain(const std::vector &filenames); + void SetTrimFiles(const std::vector &filenames); DetectorSetup& TxDelay(const std::vector &v); DetectorSetup& UDPInterfaceCount(int64_t input); DetectorSetup& SensorMaterial(const std::string &input); DetectorSetup& SensorThickness_um(float input); DetectorSetup& PixelSize_um(float input); + DetectorSetup& HighVoltage(int32_t input); [[nodiscard]] DetectorType GetDetectorType() const; [[nodiscard]] const DetectorGeometry& GetGeometry() const; @@ -50,6 +54,8 @@ public: [[nodiscard]] int64_t GetUDPInterfaceCount() const; [[nodiscard]] const std::vector &GetTxDelay() const; // can be empty for default [[nodiscard]] const std::vector &GetGainFileNames() const; + [[nodiscard]] const std::vector &GetTrimFileNames() const; + [[nodiscard]] int32_t GetHighVoltage() const; }; diff --git a/detector_control/DetectorWrapper.cpp b/detector_control/DetectorWrapper.cpp index b23e5c87..73daa573 100644 --- a/detector_control/DetectorWrapper.cpp +++ b/detector_control/DetectorWrapper.cpp @@ -9,6 +9,7 @@ void DetectorWrapper::Initialize(const DiffractionExperiment& experiment, const std::vector& net_config) { logger.Info("Initialize detector"); + det_type = experiment.GetDetectorSetup().GetDetectorType(); try { auto module_hostname = experiment.GetDetectorModuleHostname(); @@ -22,9 +23,11 @@ void DetectorWrapper::Initialize(const DiffractionExperiment& experiment, // Stop the detector InternalStop(); - // Clear synchronization prior to reconfiguring the detector - det.setMaster(false, 0); - det.setSynchronization(false); + if (det_type == DetectorType::JUNGFRAU) { + // Clear synchronization prior to reconfiguring the detector + det.setMaster(false, 0); + det.setSynchronization(false); + } if (!module_hostname.empty()) { bool reset = true; @@ -44,69 +47,101 @@ void DetectorWrapper::Initialize(const DiffractionExperiment& experiment, } } - if (det.size() != experiment.GetModulesNum()) { - logger.Error("Discrepancy in module number between DAQ and detector"); - throw JFJochException(JFJochExceptionCategory::Detector, - "Discrepancy in module number between DAQ and detector"); - } - - det.setNumberofUDPInterfaces(experiment.GetUDPInterfaceCount()); - auto mod_cfg = experiment.GetDetectorModuleConfig(net_config); - for (int i = 0; i < mod_cfg.size(); i++) { - logger.Info("Configure network for module {}", i); - - auto &cfg = mod_cfg[i]; - - det.setSourceUDPIP(sls::IpAddr(cfg.ipv4_src_addr_1), {i}); - det.setSourceUDPMAC(sls::MacAddr(BASE_DETECTOR_MAC + i * 2), {i}); - - det.setDestinationUDPPort (cfg.udp_dest_port_1, i); - det.setDestinationUDPIP( sls::IpAddr(cfg.ipv4_dest_addr_1), {i}); - det.setDestinationUDPMAC( sls::MacAddr(cfg.mac_addr_dest_1), {i}); - - if (experiment.GetUDPInterfaceCount() == 2) { - det.setSourceUDPIP2(sls::IpAddr(cfg.ipv4_src_addr_2), {i}); - det.setSourceUDPMAC2(sls::MacAddr(BASE_DETECTOR_MAC + i * 2 + 1), {i}); - det.setDestinationUDPPort2(cfg.udp_dest_port_2, i); - det.setDestinationUDPIP2( sls::IpAddr(cfg.ipv4_dest_addr_2), {i}); - det.setDestinationUDPMAC2(sls::MacAddr(cfg.mac_addr_dest_2), {i}); + if (det_type == DetectorType::JUNGFRAU) { + if (det.size() != experiment.GetModulesNum()) { + logger.Error("Discrepancy in module number between DAQ and detector"); + throw JFJochException(JFJochExceptionCategory::Detector, + "Discrepancy in module number between DAQ and detector"); } - uint32_t tmp = (cfg.module_id_in_data_stream * 2) % UINT16_MAX; - uint32_t column_id_register = ((tmp + 1) << 16) | tmp; - det.writeRegister(0x7C, column_id_register, {i}); + det.setNumberofUDPInterfaces(experiment.GetUDPInterfaceCount()); + for (int i = 0; i < mod_cfg.size(); i++) { + logger.Info("Configure network for module {}", i); + + auto &cfg = mod_cfg[i]; + + det.setSourceUDPIP(sls::IpAddr(cfg.ipv4_src_addr_1), {i}); + det.setSourceUDPMAC(sls::MacAddr(BASE_DETECTOR_MAC + i * 2), {i}); + + det.setDestinationUDPPort(cfg.udp_dest_port_1, i); + det.setDestinationUDPIP(sls::IpAddr(cfg.ipv4_dest_addr_1), {i}); + det.setDestinationUDPMAC(sls::MacAddr(cfg.mac_addr_dest_1), {i}); + + if (experiment.GetUDPInterfaceCount() == 2) { + det.setSourceUDPIP2(sls::IpAddr(cfg.ipv4_src_addr_2), {i}); + det.setSourceUDPMAC2(sls::MacAddr(BASE_DETECTOR_MAC + i * 2 + 1), {i}); + det.setDestinationUDPPort2(cfg.udp_dest_port_2, i); + det.setDestinationUDPIP2(sls::IpAddr(cfg.ipv4_dest_addr_2), {i}); + det.setDestinationUDPMAC2(sls::MacAddr(cfg.mac_addr_dest_2), {i}); + } + uint32_t tmp = (cfg.module_id_in_data_stream * 2) % UINT16_MAX; + uint32_t column_id_register = ((tmp + 1) << 16) | tmp; + + det.writeRegister(0x7C, column_id_register, {i}); + } + + det.setTemperatureControl(true); + det.setThresholdTemperature(THRESHOLD_TEMPERATURE_DEGC); + } else if (det_type == DetectorType::EIGER) { + + if (det.size() != 2 * experiment.GetModulesNum()) { + logger.Error("Discrepancy in module number between DAQ and detector"); + throw JFJochException(JFJochExceptionCategory::Detector, + "Discrepancy in module number between DAQ and detector"); + } + + det.setTenGiga(true); + auto trim_files = experiment.GetDetectorSetup().GetTrimFileNames(); + + for (int i = 0; i < mod_cfg.size(); i++) { + logger.Info("Configure network for module {}", i); + + auto &cfg = mod_cfg[i]; + + det.setDestinationUDPPort(cfg.udp_dest_port_1, 2 * i); + det.setDestinationUDPPort2(cfg.udp_dest_port_1, 2 * i + 1); + det.setSourceUDPIP(sls::IpAddr(cfg.ipv4_src_addr_1), {2 * i, 2 * i + 1}); + det.setDestinationUDPIP(sls::IpAddr(cfg.ipv4_dest_addr_1), {2 * i, 2 * i + 1}); + det.setDestinationUDPMAC(sls::MacAddr(cfg.mac_addr_dest_1), {2 * i, 2 * i + 1}); + + if (!trim_files.empty()) { + det.loadTrimbits(trim_files[2 * i], {2 * i}); + det.loadTrimbits(trim_files[2 * i + 1], {2 * i + 1}); + } + + } } - det.setTemperatureControl(true); - det.setThresholdTemperature(THRESHOLD_TEMPERATURE_DEGC); - det.setSynchronization(false); + if (det_type == DetectorType::JUNGFRAU) { + det.setTimingMode(slsDetectorDefs::timingMode::TRIGGER_EXPOSURE); - det.setTimingMode(slsDetectorDefs::timingMode::TRIGGER_EXPOSURE); + auto tx_delay = experiment.GetDetectorSetup().GetTxDelay(); + if (tx_delay.size() == experiment.GetModulesNum()) { + for (int i = 0 ; i < tx_delay.size(); i++) + det.setTransmissionDelayFrame(tx_delay[i], {i}); + } - det.setMaster(true, 0); - det.setSynchronization(true); + det.setMaster(true, 0); + det.setSynchronization(true); - auto tx_delay = experiment.GetDetectorSetup().GetTxDelay(); - if (tx_delay.size() == experiment.GetModulesNum()) { - for (int i = 0 ; i < tx_delay.size(); i++) - det.setTransmissionDelayFrame(tx_delay[i], {i}); + if (experiment.GetUDPInterfaceCount() == 2) + det.setReadoutSpeed(slsDetectorDefs::speedLevel::FULL_SPEED); + else + det.setReadoutSpeed(slsDetectorDefs::speedLevel::HALF_SPEED); + + det.setAutoComparatorDisable(true); + if (!det.getPowerChip().squash(false)) { + det.setPowerChip(true); + std::this_thread::sleep_for(std::chrono::seconds(5)); + } + } else if (det_type == DetectorType::EIGER) { + det.setTimingMode(slsDetectorDefs::timingMode::AUTO_TIMING); } - if (experiment.GetUDPInterfaceCount() == 2) - det.setReadoutSpeed(slsDetectorDefs::speedLevel::FULL_SPEED); - else - det.setReadoutSpeed(slsDetectorDefs::speedLevel::HALF_SPEED); - - det.setAutoComparatorDisable(true); - if (!det.getPowerChip().squash(false)) { - det.setPowerChip(true); - std::this_thread::sleep_for(std::chrono::seconds(5)); - } - - det.setHighVoltage(HIGH_VOLTAGE); + det.setHighVoltage(experiment.GetDetectorSetup().GetHighVoltage()); } catch (const std::exception &e) { logger.ErrorException(e); throw JFJochException(JFJochExceptionCategory::Detector, e.what()); @@ -117,9 +152,16 @@ void DetectorWrapper::Initialize(const DiffractionExperiment& experiment, void DetectorWrapper::Start(const DiffractionExperiment& experiment) { logger.Info("Start"); - if (det.size() != experiment.GetModulesNum()) - throw JFJochException(JFJochExceptionCategory::Detector, - "Discrepancy in module number between DAQ and detector"); + if (det_type == DetectorType::JUNGFRAU) { + if (det.size() != experiment.GetModulesNum()) + throw JFJochException(JFJochExceptionCategory::Detector, + "Discrepancy in module number between DAQ and detector"); + } else if (det_type == DetectorType::EIGER) { + if (det.size() != 2 * experiment.GetModulesNum()) + throw JFJochException(JFJochExceptionCategory::Detector, + "Discrepancy in module number between DAQ and detector"); + // det.setThresholdEnergy(std::lround(experiment.GetPhotonEnergy_keV() * 1000.0/ 2.0)); + } try { InternalStop(); @@ -163,11 +205,11 @@ void DetectorWrapper::Deactivate() { InternalStop(); det.setHighVoltage(0); std::this_thread::sleep_for(std::chrono::seconds(5)); - det.setPowerChip(false); - - det.setMaster(false, 0); - det.setSynchronization(false); - + if (det_type == DetectorType::JUNGFRAU) { + det.setPowerChip(false); + det.setMaster(false, 0); + det.setSynchronization(false); + } det.freeSharedMemory(); } catch (std::exception &e) { logger.ErrorException(e); @@ -280,8 +322,10 @@ std::vector DetectorWrapper::GetHighVoltage() const { try { auto result = det.getHighVoltage(); std::vector ret; - for (int i = 0; i < result.size(); i++) - ret.push_back(result[i]); + for (int i = 0; i < result.size(); i++) { + if (result[i] >= 0) + ret.push_back(result[i]); + } return ret; } catch (std::exception &e) { throw JFJochException(JFJochExceptionCategory::Detector, e.what()); @@ -293,46 +337,54 @@ DetectorStatus DetectorWrapper::GetStatus() const { DetectorStatus status; status.detector_server_version = GetDetectorServerVersion(); status.detector_state = GetState(); - status.power_state = GetPowerState(); - status.remaining_triggers = GetNumberOfTriggersLeft(); + if (det_type == DetectorType::JUNGFRAU) { + status.power_state = GetPowerState(); + status.remaining_triggers = GetNumberOfTriggersLeft(); + } else { + status.power_state = DetectorPowerState::ON; + status.remaining_triggers = -1; + } + status.temperature_fpga_degC = GetFPGATemperatures(); status.high_voltage_V = GetHighVoltage(); return status; } void DetectorWrapper::Configure(const DiffractionExperiment &experiment) { - if (experiment.IsFixedGainG1()) { - if ((experiment.GetDetectorMode() == DetectorMode::PedestalG0) || - (experiment.GetDetectorMode() == DetectorMode::PedestalG2)) - throw JFJochException(JFJochExceptionCategory::Detector, - "Pedestal G0/G2 doesn't make sense for fixed G1 mode"); - det.setGainMode(slsDetectorDefs::FIX_G1); - } else { - switch (experiment.GetDetectorMode()) { - case DetectorMode::PedestalG1: - det.setGainMode(slsDetectorDefs::gainMode::FORCE_SWITCH_G1); - break; - case DetectorMode::PedestalG2: - det.setGainMode(slsDetectorDefs::gainMode::FORCE_SWITCH_G2); - break; - default: - det.setGainMode(slsDetectorDefs::gainMode::DYNAMIC); - break; + if (det_type == DetectorType::JUNGFRAU) { + if (experiment.IsFixedGainG1()) { + if ((experiment.GetDetectorMode() == DetectorMode::PedestalG0) || + (experiment.GetDetectorMode() == DetectorMode::PedestalG2)) + throw JFJochException(JFJochExceptionCategory::Detector, + "Pedestal G0/G2 doesn't make sense for fixed G1 mode"); + det.setGainMode(slsDetectorDefs::FIX_G1); + } else { + switch (experiment.GetDetectorMode()) { + case DetectorMode::PedestalG1: + det.setGainMode(slsDetectorDefs::gainMode::FORCE_SWITCH_G1); + break; + case DetectorMode::PedestalG2: + det.setGainMode(slsDetectorDefs::gainMode::FORCE_SWITCH_G2); + break; + default: + det.setGainMode(slsDetectorDefs::gainMode::DYNAMIC); + break; + } } + + det.setStorageCellStart(experiment.GetStorageCellStart()); + det.setNumberOfAdditionalStorageCells(experiment.GetStorageCellNumber() - 1); + det.setStorageCellDelay( + experiment.GetStorageCellDelay() - std::chrono::nanoseconds(MIN_STORAGE_CELL_DELAY_IN_NS)); + + if (experiment.IsUsingGainHG0()) + det.setSettings(slsDetectorDefs::HIGHGAIN0); + else + det.setSettings(slsDetectorDefs::GAIN0); + + det.setDelayAfterTrigger(experiment.GetDetectorDelay()); } - det.setStorageCellStart(experiment.GetStorageCellStart()); - det.setNumberOfAdditionalStorageCells(experiment.GetStorageCellNumber() - 1); - det.setStorageCellDelay(experiment.GetStorageCellDelay() - std::chrono::nanoseconds(MIN_STORAGE_CELL_DELAY_IN_NS)); - det.setPeriod(experiment.GetDetectorPeriod()); - det.setExptime(std::chrono::microseconds(experiment.GetFrameCountTime())); - - if (experiment.IsUsingGainHG0()) - det.setSettings(slsDetectorDefs::HIGHGAIN0); - else - det.setSettings(slsDetectorDefs::GAIN0); - - det.setDelayAfterTrigger(experiment.GetDetectorDelay()); } diff --git a/detector_control/DetectorWrapper.h b/detector_control/DetectorWrapper.h index 2f7a5a63..861a8253 100644 --- a/detector_control/DetectorWrapper.h +++ b/detector_control/DetectorWrapper.h @@ -8,7 +8,6 @@ #include "../common/Logger.h" #define BASE_DETECTOR_MAC 0xAABBCCDDEE10 // little-endian! -#define HIGH_VOLTAGE 120 #define THRESHOLD_TEMPERATURE_DEGC 55 enum class DetectorState {IDLE, ERROR, BUSY, WAITING}; @@ -25,6 +24,7 @@ struct DetectorStatus { class DetectorWrapper { Logger logger{"DetectorWrapper"}; + DetectorType det_type; sls::Detector det; void InternalStop(); [[nodiscard]] int64_t GetNumberOfTriggersLeft() const; diff --git a/export_images/PreviewImage.cpp b/export_images/PreviewImage.cpp index bb555b29..1541ccff 100644 --- a/export_images/PreviewImage.cpp +++ b/export_images/PreviewImage.cpp @@ -84,20 +84,25 @@ std::vector GenerateRGB(const T* value, size_t npixel, uint32_t s } std::string PreviewImage::GenerateJPEG(const PreviewJPEGSettings &settings) const { - if (!pixel_is_signed) - throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Unsigned images not allowed"); - std::vector v; { // JPEG compression is outside the critical loop protected by m std::unique_lock ul(m); - - if (pixel_depth_bytes == 2) - v = GenerateRGB((int16_t *) uncompressed_image.data(), xpixel * ypixel, settings.saturation_value, - INT16_MIN); - else - v = GenerateRGB((int32_t *) uncompressed_image.data(), xpixel * ypixel, settings.saturation_value, - INT32_MIN); + if (!pixel_is_signed) { + if (pixel_depth_bytes == 2) + v = GenerateRGB((uint16_t *) uncompressed_image.data(), xpixel * ypixel, + settings.saturation_value, UINT16_MAX); + else + v = GenerateRGB((uint32_t *) uncompressed_image.data(), xpixel * ypixel, + settings.saturation_value, UINT32_MAX); + } else { + if (pixel_depth_bytes == 2) + v = GenerateRGB((int16_t *) uncompressed_image.data(), xpixel * ypixel, + settings.saturation_value, INT16_MIN); + else + v = GenerateRGB((int32_t *) uncompressed_image.data(), xpixel * ypixel, + settings.saturation_value, INT32_MIN); + } if (settings.show_spots) AddSpots(v); } @@ -140,11 +145,17 @@ std::string PreviewImage::GenerateTIFFDioptas() const { std::unique_lock ul(m); std::vector vec; - if (pixel_depth_bytes == 2) - vec = GenerateDioptasPreview(uncompressed_image.data(), xpixel, ypixel, INT16_MIN); - else - vec = GenerateDioptasPreview(uncompressed_image.data(), xpixel, ypixel, INT32_MIN); - + if (pixel_is_signed) { + if (pixel_depth_bytes == 2) + vec = GenerateDioptasPreview(uncompressed_image.data(), xpixel, ypixel, INT16_MIN); + else + vec = GenerateDioptasPreview(uncompressed_image.data(), xpixel, ypixel, INT32_MIN); + } else { + if (pixel_depth_bytes == 2) + vec = GenerateDioptasPreview(uncompressed_image.data(), xpixel, ypixel, UINT16_MAX); + else + vec = GenerateDioptasPreview(uncompressed_image.data(), xpixel, ypixel, UINT32_MAX); + } return WriteTIFFToString(vec.data(), xpixel, ypixel, 2, false); } @@ -195,8 +206,10 @@ void PreviewImage::AddBeamCenter(std::vector &rgb_image) const { int crosshair_width = 3; for (int w = -crosshair_width; w <= crosshair_width; w++) { for (int i = -crosshair_size; i <= crosshair_size; i++) { - feature(rgb_image, (beam_y_int + w) * xpixel + beam_x_int + i); - feature(rgb_image, (beam_y_int + i) * xpixel + beam_x_int + w); + if ((beam_y_int + w < ypixel) && (beam_x_int + i < xpixel)) + feature(rgb_image, (beam_y_int + w) * xpixel + beam_x_int + i); + if ((beam_y_int + i < ypixel) && (beam_x_int + w < xpixel)) + feature(rgb_image, (beam_y_int + i) * xpixel + beam_x_int + w); } } } diff --git a/export_images/WriteJPEG.cpp b/export_images/WriteJPEG.cpp index a9263644..b57b0c34 100644 --- a/export_images/WriteJPEG.cpp +++ b/export_images/WriteJPEG.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include diff --git a/fpga/hls/jf_conversion.cpp b/fpga/hls/jf_conversion.cpp index 609b4e29..a7e859dc 100644 --- a/fpga/hls/jf_conversion.cpp +++ b/fpga/hls/jf_conversion.cpp @@ -160,10 +160,13 @@ void jf_conversion(STREAM_512 &data_in, STREAM_768 &data_out, ap_uint<64> mode = ACT_REG_MODE(packet_in.data); ap_uint<1> conversion = (mode & MODE_CONV) ? 1 : 0; ap_uint<1> fixed_g1 = (mode & MODE_FIXG1) ? 1 : 0; + ap_uint<1> mode_unsigned = ((mode & MODE_UNSIGNED) ? 1 : 0); + ap_uint<6> modules = ACT_REG_NMODULES(packet_in.data) + 1; in_energy_kev.u = ACT_REG_ENERGY_KEV_FLOAT(packet_in.data); ap_uint<5> storage_cells = ACT_REG_NSTORAGE_CELLS(packet_in.data); + ap_uint<32> offset_hbm_0 = 0 * hbm_size_bytes / 32; ap_uint<32> offset_hbm_1 = 1 * hbm_size_bytes / 32; ap_uint<32> offset_hbm_2 = 2 * hbm_size_bytes / 32; @@ -248,11 +251,28 @@ void jf_conversion(STREAM_512 &data_in, STREAM_768 &data_out, for (int i = 0; i < RAW_MODULE_SIZE * sizeof(uint16_t) / 64; i++) { #pragma HLS PIPELINE II=1 data_in >> packet_in; - ap_uint<16> val_in[32]; ap_int<24> val_out[32]; - unpack32(packet_in.data, val_in); - for (int i = 0; i < 32; i++) - val_out[i] = val_in[i]; + if (mode_unsigned) { + ap_uint<16> val_in[32]; + unpack32(packet_in.data, val_in); + for (int i = 0; i < 32; i++) { + if (val_in[i] == UINT16_MAX) + val_out[i] = INT24_MAX; + else + val_out[i] = val_in[i]; + } + } else { + ap_int<16> val_in[32]; + unpack32(packet_in.data, val_in); + for (int i = 0; i < 32; i++) { + if (val_in[i] == INT16_MAX) + val_out[i] = INT24_MAX; + else if (val_in[i] == INT16_MIN) + val_out[i] = INT24_MIN; + else + val_out[i] = val_in[i]; + } + } packet_out.data = pack32(val_out); packet_out.last = packet_in.last; packet_out.user = packet_in.user; diff --git a/fpga/hls/sls_detector.cpp b/fpga/hls/sls_detector.cpp index 2e5861a4..cdb376e6 100644 --- a/fpga/hls/sls_detector.cpp +++ b/fpga/hls/sls_detector.cpp @@ -59,8 +59,13 @@ void sls_detector(AXI_STREAM &udp_payload_in, #pragma HLS RESET variable=internal_pulseid #pragma HLS RESET variable=state - if (state == INSPECT_HEADER && udp_metadata_in.empty()) + if (state == INSPECT_HEADER && udp_metadata_in.empty()) { + counter = internal_counter; + counter_eth_error = internal_counter_eth_error; + counter_len_error = internal_counter_len_error; + pulse_id = internal_pulseid; return; + } if (udp_payload_in.read_nb(packet_in)) { diff --git a/fpga/hls/stream_24bit_conv.cpp b/fpga/hls/stream_24bit_conv.cpp index 883469fd..ed1a4841 100644 --- a/fpga/hls/stream_24bit_conv.cpp +++ b/fpga/hls/stream_24bit_conv.cpp @@ -96,8 +96,6 @@ void stream_24bit_conv(STREAM_768 &data_in, ap_uint<1> write_32bit = ((data_collection_mode & MODE_32BIT) ? 1 : 0); ap_uint<1> write_unsigned = ((data_collection_mode & MODE_UNSIGNED) ? 1 : 0); - - data_in >> packet_in; if (write_32bit) { diff --git a/receiver/JFJochReceiver.cpp b/receiver/JFJochReceiver.cpp index e56b28b4..d78ef7e2 100644 --- a/receiver/JFJochReceiver.cpp +++ b/receiver/JFJochReceiver.cpp @@ -19,7 +19,7 @@ JFJochReceiver::JFJochReceiver(const DiffractionExperiment& in_experiment, const SpotFindingSettings &in_spot_finding_settings, SendBuffer &buf) : experiment(in_experiment), - calibration(in_calibration), + calibration(nullptr), send_buf_ctrl(experiment, buf), acquisition_device(in_aq_device), logger(in_logger), @@ -38,6 +38,9 @@ JFJochReceiver::JFJochReceiver(const DiffractionExperiment& in_experiment, preview_image(experiment), preview_image_indexed(experiment) { + if (experiment.GetDetectorSetup().GetDetectorType() == DetectorType::JUNGFRAU) + calibration = in_calibration; + push_images_to_writer = (experiment.GetImageNum() > 0) && (!experiment.GetFilePrefix().empty()); if (acquisition_device.size() < ndatastreams) diff --git a/tests/FPGAIntegrationTest.cpp b/tests/FPGAIntegrationTest.cpp index bab9ba7e..f148b9aa 100644 --- a/tests/FPGAIntegrationTest.cpp +++ b/tests/FPGAIntegrationTest.cpp @@ -683,6 +683,121 @@ TEST_CASE("HLS_C_Simulation_check_convert_full_range_U16", "[FPGA][Full]") { } } +TEST_CASE("HLS_C_Simulation_no_conversion_U16", "[FPGA][Full]") { + Logger logger("HLS_C_Simulation_no_conversion_U16"); + std::vector data(RAW_MODULE_SIZE); + + for (int i = 0; i < RAW_MODULE_SIZE; i++) + data[i] = i % UINT16_MAX; + + data[5456] = UINT16_MAX; + data[211] = UINT16_MAX; + + const uint16_t nmodules = 1; + DiffractionExperiment x((DetectorGeometry(nmodules))); + + x.Mode(DetectorMode::Conversion).ConversionOnFPGA(false); + HLSSimulatedDevice test(0, 64); + + x.PedestalG0Frames(0).NumTriggers(1).ImagesPerTrigger(1).FPGAOutputMode(FPGAPixelOutput::Uint16); + + test.CreateJFPackets(x, 1, 1, 0, data.data()); + test.CreateFinalPacket(x); + + REQUIRE_NOTHROW(test.StartAction(x)); + REQUIRE_NOTHROW(test.WaitForActionComplete()); + + REQUIRE_NOTHROW(test.OutputStream().read()); + REQUIRE(test.OutputStream().size() == 0); + CHECK(test.GetBytesReceived() == 128 * JUNGFRAU_PACKET_SIZE_BYTES); + + auto output = (uint16_t *) test.GetDeviceOutput(0, 0)->pixels; + size_t err = 0; + for (int i = 0; i < RAW_MODULE_SIZE; i++) { + CHECK(data[i] == output[i]); + } + REQUIRE(err == 0); +} + +TEST_CASE("HLS_C_Simulation_no_conversion_U32", "[FPGA][Full]") { + Logger logger("HLS_C_Simulation_no_conversion_U32"); + std::vector data(RAW_MODULE_SIZE); + + for (int i = 0; i < RAW_MODULE_SIZE; i++) + data[i] = i % UINT16_MAX; + + data[5456] = UINT16_MAX; + data[211] = UINT16_MAX; + + const uint16_t nmodules = 1; + DiffractionExperiment x((DetectorGeometry(nmodules))); + + x.Mode(DetectorMode::Conversion).ConversionOnFPGA(false); + HLSSimulatedDevice test(0, 64); + + x.PedestalG0Frames(0).NumTriggers(1).ImagesPerTrigger(1).FPGAOutputMode(FPGAPixelOutput::Uint32); + + test.CreateJFPackets(x, 1, 1, 0, data.data()); + test.CreateFinalPacket(x); + + REQUIRE_NOTHROW(test.StartAction(x)); + REQUIRE_NOTHROW(test.WaitForActionComplete()); + + REQUIRE_NOTHROW(test.OutputStream().read()); + REQUIRE(test.OutputStream().size() == 0); + CHECK(test.GetBytesReceived() == 128 * JUNGFRAU_PACKET_SIZE_BYTES); + + auto output = (uint32_t *) test.GetDeviceOutput(0, 0)->pixels; + size_t err = 0; + for (int i = 0; i < RAW_MODULE_SIZE; i++) { + if (data[i] == UINT16_MAX) { + CHECK(output[i] == UINT32_MAX); + } else if (data[i] != output[i]) err++; + } + REQUIRE(err == 0); +} + +TEST_CASE("HLS_C_Simulation_no_conversion_I32", "[FPGA][Full]") { + Logger logger("HLS_C_Simulation_no_conversion_I32"); + std::vector data(RAW_MODULE_SIZE); + + for (int i = 0; i < RAW_MODULE_SIZE; i++) + data[i] = i % UINT16_MAX; + + data[5456] = UINT16_MAX; + data[211] = UINT16_MAX; + + const uint16_t nmodules = 1; + DiffractionExperiment x((DetectorGeometry(nmodules))); + + x.Mode(DetectorMode::Conversion).ConversionOnFPGA(false); + HLSSimulatedDevice test(0, 64); + + x.PedestalG0Frames(0).NumTriggers(1).ImagesPerTrigger(1).FPGAOutputMode(FPGAPixelOutput::Int32); + + test.CreateJFPackets(x, 1, 1, 0, data.data()); + test.CreateFinalPacket(x); + + REQUIRE_NOTHROW(test.StartAction(x)); + REQUIRE_NOTHROW(test.WaitForActionComplete()); + + REQUIRE_NOTHROW(test.OutputStream().read()); + REQUIRE(test.OutputStream().size() == 0); + CHECK(test.GetBytesReceived() == 128 * JUNGFRAU_PACKET_SIZE_BYTES); + + auto data16_signed = (int16_t *) data.data(); + auto output = (int32_t *) test.GetDeviceOutput(0, 0)->pixels; + size_t err = 0; + for (int i = 0; i < RAW_MODULE_SIZE; i++) { + if (data16_signed[i] == INT16_MAX) { + CHECK(output[i] == INT32_MAX); + } else if (data16_signed[i] == INT16_MIN) { + CHECK(output[i] == INT32_MIN); + } else if (data16_signed[i] != output[i]) err++; + } + REQUIRE(err == 0); +} + TEST_CASE("HLS_C_Simulation_internal_packet_generator_convert_full_range", "[FPGA][Full]") { double energy = 6.0; const uint16_t nmodules = 4; @@ -1687,13 +1802,13 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_32bit", "[FPGA][Full]") { std::vector test_frame(nmodules*RAW_MODULE_SIZE); std::mt19937 g1(1387); - std::uniform_int_distribution dist(0, UINT16_MAX); + std::uniform_int_distribution dist(0, UINT16_MAX - 1); for (auto &i: test_frame) i = dist(g1); x.Mode(DetectorMode::Raw); - x.UseInternalPacketGenerator(true).ImagesPerTrigger(nframes).PedestalG0Frames(0).FPGAOutputMode(FPGAPixelOutput::Int32); + x.UseInternalPacketGenerator(true).ImagesPerTrigger(nframes).PedestalG0Frames(0).FPGAOutputMode(FPGAPixelOutput::Uint32); HLSSimulatedDevice test(0, 64); for (int m = 0; m < x.GetModulesNum(); m++) @@ -1720,7 +1835,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_32bit", "[FPGA][Full]") { CHECK(test.GetDeviceOutput(image, m)->module_statistics.pulse_id == INT_PKT_GEN_BUNCHID + image); CHECK(test.GetDeviceOutput(image, m)->module_statistics.exptime == INT_PKT_GEN_EXPTTIME); - auto imageBuf = (int32_t *) test.GetDeviceOutput(image, m)->pixels; + auto imageBuf = (uint32_t *) test.GetDeviceOutput(image, m)->pixels; for (int i = 0; i < RAW_MODULE_SIZE; i++) { REQUIRE(imageBuf[i] == test_frame_unsigned[m * RAW_MODULE_SIZE + i]); } @@ -1737,14 +1852,14 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_summation", "[FPGA][Full]" std::vector test_frame(nmodules*RAW_MODULE_SIZE); std::mt19937 g1(1387); - std::uniform_int_distribution dist(0, 65535); + std::uniform_int_distribution dist(0, UINT16_MAX); for (auto &i: test_frame) i = dist(g1); x.Mode(DetectorMode::Conversion); x.UseInternalPacketGenerator(true).ImagesPerTrigger(nframes).PedestalG0Frames(0).Summation(nsummation) - .ConversionOnFPGA(false); + .ConversionOnFPGA(false).FPGAOutputMode(FPGAPixelOutput::Int32); HLSSimulatedDevice test(0, 64); for (int m = 0; m < x.GetModulesNum(); m++) @@ -1757,7 +1872,7 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_summation", "[FPGA][Full]" REQUIRE(test.GetBytesReceived() == 128 * nmodules * nframes * nsummation * JUNGFRAU_PACKET_SIZE_BYTES); - auto test_frame_signed = (uint16_t *) test_frame.data(); + auto test_frame_signed = (int16_t *) test_frame.data(); for (int image = 0; image < nframes; image++) { for (int m = 0; m < nmodules; m++) { REQUIRE(test.GetDeviceOutput(image, m)->module_statistics.timestamp == INT_PKT_GEN_EXPTTIME * image * nsummation); @@ -1766,6 +1881,11 @@ TEST_CASE("HLS_C_Simulation_internal_packet_generator_summation", "[FPGA][Full]" auto imageBuf = (int32_t *) test.GetDeviceOutput(image, m)->pixels; for (int i = 0; i < RAW_MODULE_SIZE; i++) { + if (test_frame_signed[m * RAW_MODULE_SIZE + i] == INT16_MAX) + CHECK(imageBuf[i] == INT32_MAX); + else if (test_frame_signed[m * RAW_MODULE_SIZE + i] == INT16_MIN) + CHECK(imageBuf[i] == INT32_MIN); + else REQUIRE(imageBuf[i] == test_frame_signed[m * RAW_MODULE_SIZE + i] * nsummation); } } diff --git a/tests/FrameTransformationTest.cpp b/tests/FrameTransformationTest.cpp index 15abe00c..4cb943a2 100644 --- a/tests/FrameTransformationTest.cpp +++ b/tests/FrameTransformationTest.cpp @@ -370,6 +370,7 @@ TEST_CASE("FrameTransformation_Converted_bshuf_zstd_unsigned_16bit" ,"") { input_0[311*1024+256] = UINT16_MAX - 2; input_0[311*1024+255] = UINT16_MAX - 1; + input_0[255*1024] = UINT16_MAX - 1; std::vector input_1(nmodules*RAW_MODULE_SIZE); for (int i = 0; i < nmodules*RAW_MODULE_SIZE; i++) @@ -397,7 +398,9 @@ TEST_CASE("FrameTransformation_Converted_bshuf_zstd_unsigned_16bit" ,"") { REQUIRE(input_0[311*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 0]); REQUIRE(input_0[311*1024+255] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 255]); + REQUIRE(input_0[311*1024+255] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 256]); REQUIRE(input_0[311*1024+256] / 2 == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 200 * 1030 * 2 + 258]); + REQUIRE(input_0[255*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 257 * 1030 * 2 + 0]); REQUIRE(input_0[(511+512)*1024] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 1030]); REQUIRE(input_0[(511+512)*1024 + 800] == output[CONVERTED_MODULE_SIZE * (2 * nmodules - 2) + 1030 + 800 + 6]); diff --git a/tests/JFJochBrokerParserTest.cpp b/tests/JFJochBrokerParserTest.cpp index 66668c1a..83acb0b5 100644 --- a/tests/JFJochBrokerParserTest.cpp +++ b/tests/JFJochBrokerParserTest.cpp @@ -163,7 +163,8 @@ TEST_CASE("JFJochBrokerParser_DetectorType_EIGER") { }, "description": "PSI JUNGFRAU 2M", "udp_interface_count": 1, - "module_hostname": ["mx1", "mx2", "mx3", "mx4"], + "module_hostname": ["mx1", "mx2", "mx3", "mx4", "mx5", "mx6", "mx7", "mx8"], + "trim_files": ["a","b","c","d","e","f","g","h"], "type": "eiger" } )"_json;