// 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(); 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.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"); } DetectorWrapper::DetectorState DetectorWrapper::GetState() const { try { bool is_idle = true; for (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 (is_idle) return DetectorState::IDLE; else return DetectorState::BUSY; } catch (std::exception &e) { throw JFJochException(JFJochExceptionCategory::Detector, e.what()); } } int64_t DetectorWrapper::GetFirmwareVersion() { try { auto result = det.getFirmwareVersion(); return result.squash(0x0); } catch (std::exception &e) { throw JFJochException(JFJochExceptionCategory::Detector, e.what()); } } std::string DetectorWrapper::GetDetectorServerVersion() { try { auto result = det.getDetectorServerVersion(); return result.squash(""); } catch (std::exception &e) { throw JFJochException(JFJochExceptionCategory::Detector, e.what()); } }