// Copyright (2019-2023) Paul Scherrer Institute #include #include "DetectorWrapper.h" #include "../common/JFJochException.h" #include "../common/Definitions.h" void DetectorWrapper::Configure(const DiffractionExperiment& experiment, const std::vector& net_config) { logger.Info("Configure"); try { if (det.size() > 0) { // Only if the detector is already defined // Stop the detector InternalStop(); // Clear synchronization prior to reconfiguring the detector det.setMaster(false, 0); det.setSynchronization(false); } auto module_hostname = experiment.GetDetectorModuleHostname(); if (!module_hostname.empty() > 0) { logger.Info("Resetting detector module host names"); det.setHostname(module_hostname); } 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}); } 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); det.setSynchronization(false); det.setTimingMode(slsDetectorDefs::timingMode::TRIGGER_EXPOSURE); det.setMaster(true, 0); det.setSynchronization(true); det.setAutoComparatorDisable(true); if (!det.getPowerChip().squash(false)) { det.setPowerChip(true); std::this_thread::sleep_for(std::chrono::seconds(5)); } det.setHighVoltage(HIGH_VOLTAGE); } catch (const std::exception &e) { logger.ErrorException(e); throw JFJochException(JFJochExceptionCategory::Detector, e.what()); } logger.Info(" ... done"); } 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"); try { InternalStop(); 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; } } 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.IsUsingGainHG0()) det.setSettings(slsDetectorDefs::HIGHGAIN0); else det.setSettings(slsDetectorDefs::GAIN0); det.setDelayAfterTrigger(experiment.GetDetectorDelay()); det.setNextFrameNumber(1); if (experiment.GetNumTriggers() == 1) { det.setNumberOfFrames(experiment.GetFrameNumPerTrigger() + DELAY_FRAMES_STOP_AND_QUIT); det.setNumberOfTriggers(1); } else { // More than 1 trigger - detector needs one trigger or few more trigger if (experiment.GetStorageCellNumber() > 1) det.setNumberOfFrames(1); else det.setNumberOfFrames(experiment.GetFrameNumPerTrigger()); if (experiment.GetFrameNumPerTrigger() < DELAY_FRAMES_STOP_AND_QUIT) det.setNumberOfTriggers(experiment.GetNumTriggers() + DELAY_FRAMES_STOP_AND_QUIT); else det.setNumberOfTriggers(experiment.GetNumTriggers() + 1); } det.setStorageCellStart(experiment.GetStorageCellStart()); det.setNumberOfAdditionalStorageCells(experiment.GetStorageCellNumber() - 1); det.setStorageCellDelay(experiment.GetStorageCellDelay() - std::chrono::nanoseconds(MIN_STORAGE_CELL_DELAY_IN_NS)); if ((experiment.GetStorageCellNumber() > 1) || (experiment.GetFrameTime().count() < MIN_FRAME_TIME_HALF_SPEED_IN_US)) det.setReadoutSpeed(slsDetectorDefs::speedLevel::FULL_SPEED); else det.setReadoutSpeed(slsDetectorDefs::speedLevel::HALF_SPEED); if (experiment.GetStorageCellNumber() > 1) { det.setPeriod((experiment.GetFrameTime() + std::chrono::microseconds(10)) * experiment.GetStorageCellNumber() ); } else det.setPeriod(experiment.GetFrameTime()); det.setExptime(std::chrono::microseconds(experiment.GetFrameCountTime())); det.startDetector(); } catch (std::exception &e) { logger.ErrorException(e); throw JFJochException(JFJochExceptionCategory::Detector, e.what()); } logger.Info(" ... done"); } void DetectorWrapper::InternalStop() { // Assume it is executed in try-catch! auto state = GetState(); if (state == DetectorState::ERROR) throw JFJochException(JFJochExceptionCategory::Detector, "Detector in error state"); else if (state == DetectorState::BUSY) { try { // Sometimes stop gives problem - ignore these logger.Warning("Problem with stopping the detector - ignored."); det.stopDetector(); } catch (...) {} std::this_thread::sleep_for(std::chrono::milliseconds(10)); state = GetState(); if (state != DetectorState::IDLE) throw JFJochException(JFJochExceptionCategory::Detector, "Detector busy and cannot be stopped"); } } void DetectorWrapper::Deactivate() { logger.Info("Deactivate"); try { InternalStop(); det.setHighVoltage(0); std::this_thread::sleep_for(std::chrono::seconds(5)); det.setPowerChip(false); } catch (std::exception &e) { logger.ErrorException(e); throw JFJochException(JFJochExceptionCategory::Detector, e.what()); } logger.Info(" ... done"); } void DetectorWrapper::Stop() { logger.Info("Stop"); try { InternalStop(); } catch (std::exception &e) { logger.ErrorException(e); throw JFJochException(JFJochExceptionCategory::Detector, e.what()); } logger.Info(" ... done"); } void DetectorWrapper::Trigger() { logger.Info("Trigger"); try { det.sendSoftwareTrigger(); } catch (std::exception &e) { logger.ErrorException(e); throw JFJochException(JFJochExceptionCategory::Detector, e.what()); } logger.Info(" ... done"); } DetectorState DetectorWrapper::GetState() const { try { bool is_idle = true; bool is_waiting = true; for (const auto & i : det.getDetectorStatus()) { if (i == slsDetectorDefs::runStatus::ERROR) return DetectorState::ERROR; if ((i != slsDetectorDefs::runStatus::IDLE) && (i != slsDetectorDefs::runStatus::STOPPED) && (i != slsDetectorDefs::runStatus::RUN_FINISHED)) is_idle = false; if (i != slsDetectorDefs::WAITING) is_waiting = false; } if (is_idle) return DetectorState::IDLE; else if (is_waiting) return DetectorState::WAITING; else return DetectorState::BUSY; } catch (std::exception &e) { throw JFJochException(JFJochExceptionCategory::Detector, e.what()); } } int64_t DetectorWrapper::GetNumberOfTriggersLeft() const { int64_t ret = 0; for (const auto & i : det.getNumberOfTriggersLeft()) { if (i > ret) ret = i; } return ret; } DetectorPowerState DetectorWrapper::GetPowerState() const { uint64_t count_on = 0; for (const auto &i : det.getPowerChip()) { if (i) count_on++; } if (count_on == 0) return DetectorPowerState::OFF; else if (count_on == det.size()) return DetectorPowerState::ON; else return DetectorPowerState::PARTIAL; } int64_t DetectorWrapper::GetFirmwareVersion() const { try { auto result = det.getFirmwareVersion(); return result.squash(0x0); } catch (std::exception &e) { throw JFJochException(JFJochExceptionCategory::Detector, e.what()); } } std::string DetectorWrapper::GetDetectorServerVersion() const { try { auto result = det.getDetectorServerVersion(); return result.squash("mixed"); } catch (std::exception &e) { throw JFJochException(JFJochExceptionCategory::Detector, e.what()); } } std::vector DetectorWrapper::GetFPGATemperatures() const { try { auto result = det.getTemperature(slsDetectorDefs::TEMPERATURE_FPGA); std::vector ret; for (int i = 0; i < result.size(); i++) ret.push_back(result[i]); return ret; } catch (std::exception &e) { throw JFJochException(JFJochExceptionCategory::Detector, e.what()); } } DetectorStatus DetectorWrapper::GetStatus() const { DetectorStatus status; status.detector_server_version = GetDetectorServerVersion(); status.detector_state = GetState(); status.power_state = GetPowerState(); status.remaining_triggers = GetNumberOfTriggersLeft(); status.temperature_fpga_degC = GetFPGATemperatures(); return status; }