Welcome to SLS Detectors’ documentation!

Contents:

Introduction

The slsDetectors package allows you to control a Gotthard, or another Detector supported by PSI’s slsDetectorPackage.

The documentation from PSI can be found here.

Expert Contact

Deployment Guidelines

slsDetectors will automatically install its dependency slsDetectorsPackage.

For debugging purposes it can be useful to have tshark installed on the control server, and xctrl user added to the wireshark group.

The control server should have a 10 GbE network interface for sending images to the DAQ, and possibly one for the GUI server.

Special settings for Jungfrau

In order to have the receiving thread executed with real time priority, the line

username rtprio 99

shall be added to the file /etc/security/limits.conf on the control server (may differ depending on the Linux distribution).

The RX socket buffer size shall be set to 1000 MB

sysctl -w net.core.rmem_max=1048576000

The maximum socket input packet queue shall be set to 250000

sysctl -w net.core.netdev_max_backlog=250000

The MTU on the network interface used for Jungfrau shall be set to 9000, also known as “jumbo frames”.

Receiver Device Setup

The following parameter is needed if multiple receivers are run on the same control host:

  • rxTcpPort: the port on which the receiver will wait for reconfiguration from the control device. It corresponds to the –rx_tcpport or -t option in the slsReceiver from PSI. It must be unique on the control host.

Control Device Setup

The following are mandatory parameters for the control device. As one single device can control several detectors, all the parameters are vectors. Also, in parenthesis the corresponding parameter name in PSI’s tools is provided:

  • detectorHostName (hostname): the hostnames or IP addresses of the detector modules to be controlled;
  • udpSrcIp (udp_srcip): the IP addresses of the detector (source) UDP interfaces; must be in the same subnet as the destination UDP/IP; used to be named detectorIp (detectorip);
  • rxHostname (rx_hostname): the hostnames or IP addresses of the hosts where the receiver devices are running;
  • rxTcpPort (rx_tcpport): the port on which the receiver for the detector has been started; see the rxTcpPort paramter of the Karabo receiver.
  • udpDstIp (udp_dstip): the IP addresses of the network interfaces on the receiver’s host, which is receiving data from the detector; used to be named rxUdpIp (rx_udpip);
  • udpDstPort (udp_dstport): the port numbers of the receiver (destination) UDP interfaces; default is 50001; it must be unique if multiple receivers are run on the same host; used to be named rxUdpPort (rx_udpport).

How to control an SLS detector

The SlsControl class allows you to control a Gotthard, or another Detector supported by PSI’s slsDetectorPackage. You can set parameters, start and stop an acquisition.

The data receiver must be also running. It can be for example the slsReceiver provided with the slsDetectorPackage, or a SlsReceiver Karabo device.

Mandatory parameters

The mandatory parameters are described in Control Device Setup.

Optional parameters

The SlsControl device has several optional parameters; please be aware that:

  • simple (i.e. scalar) reconfigurable parameters tagged as sls are sent to all the modules;
  • vector reconfigurable parameters tagged as sls must have zero, one, or as many elements as the number of modules. If the vector has only one element, this value will be sent to all modules;

How to create a control device based on slsControl

If your detector is not covered by an already existing SlsControl derived class, it can easily added to the slsControl package. You have to create the source and header files (see MyControl.hh file and MyControl.cc file Sections) and add them to the Netbeans project. You also have to compile the project in Netbeans (Debug, Release and Simulation mode) in order to have the Makefiles updated.

Do not forget to “git add” the new files.

Expected parameters

There are already several common detector parameters defined in the base class (SlsControl). Check the SlsControl::expectedParameter() function to see what they are.

In case you need to set more parameters, they must have the “sls” tag. The alias have to contain the parameter name, as can be found in the description of the command line interface.

Any Karabo type is allowed, also VECTOR types.

MyControl.hh file

This is the minimal MyControl.hh:

#ifndef KARABO_MYCONTROL_HH
#define KARABO_MYCONTROL_HH


#include <karabo/karabo.hpp>

#include "SlsControl.hh"
#include "version.hh"  // provides PACKAGE_VERSION

/**
 * The main Karabo namespace
 */
namespace karabo {

    class MyControl : public karabo::SlsControl {
    public:

        KARABO_CLASSINFO(MyControl, "MyControl", PACKAGE_VERSION)

        MyControl(const karabo::util::Hash& config);

        virtual ~MyControl();

        static void expectedParameters(karabo::util::Schema& expected);

    private:

        // Optional. Send the commands needed to power-up and initialize
        // the detector
        void powerOn();

        // Optional. Place here the code needed to regularly poll detector
        // parameters, e.g. temperatures, and set them in the input Hash.
        void pollDetectorSpecific(karabo::util::Hash& h);

        // Optional. Place here the code needed to execute detector specific
        // actions, when a reconfiguration is received.
        void configureDetectorSpecific(const karabo::util::Hash& configHash);

        // Optional. Place here the code needed to create the calibration
        // and settings files, if needed by the detector.
        void createCalibrationAndSettings(const std::string& settings);
    };

} /* namespace karabo */

#endif /* KARABO_MYCONTROL_HH */

You probably don’t need anything more than that.

MyControl.cc file

An example of MyControl.cc is the following. In the best case you will just have to add detector specific expected parameters as described in the Expected parameters Section.

#include "MyControl.hh"

USING_KARABO_NAMESPACES

namespace karabo {

    KARABO_REGISTER_FOR_CONFIGURATION(BaseDevice, Device<>, SlsControl,
        MyControl)

    MyControl::MyControl(const Hash& config) : SlsControl(config) {
    }

    MyControl::~MyControl() {
    }

    void MyControl::expectedParameters(Schema& expected) {
        // Add here more detector specific expected parameters, for
        // example:

        VECTOR_INT32_ELEMENT(expected).key("tempAdc")
            .displayedName("ADC Temperature")
            .unit(Unit::DEGREE_CELSIUS)
            .readOnly()
            .commit();
    }

    void MyControl::powerOn() {
        // Send the commands needed to power-up and initialize the
        // detector, for example:
        sendConfiguration("powerchip", "1");
    }

    void MyControl::pollDetectorSpecific(karabo::util::Hash& h) {
        // Poll detector specifica properties, for example temperatures:
        const std::vector<int> tempAdc = m_SLS->getTemperature(slsDetectorDefs::dacIndex::TEMPERATURE_ADC, m_positions);
        h.set("tempAdc", tempAdc);
    }

    void MyControl::configureDetectorSpecific(const karabo::util::Hash& configHash) {
        // Execute detector specific actions, when a reconfiguration is
        // received.
    }


    void MyControl::createCalibrationAndSettings(const std::string& settings) {
        // Place here the code needed to create the calibration and
        // settings files, if needed by the detector. For example:

        const std::string calibrationDir = m_tmpDir + "/" + settings;

        if (!fs::exists(calibrationDir)) {
            // Create calibration and settings directory
            fs::create_directory(calibrationDir);

        KARABO_LOG_FRAMEWORK_DEBUG << "Created calibration dir" << calibrationDir;
        }

        const std::string fname = calibrationDir + "/calibration.sn";
        if (!fs::exists(fname)) {
            // Create calibration file
            std::ofstream fstr;
            fstr.open(fname.c_str());

            if (fstr.is_open()) {
               fstr << "227 5.6\n"
               fstr.close();

            } else {
                throw KARABO_RECONFIGURE_EXCEPTION("Could not open file " + fname + "for writing");
            }
        }
    }

} /* namespace karabo */

Simulation Mode

To compile slsControl in simulation mode, just run

make CONF=Simulation

This way the package will be linked against the simulation, instead of libSlsDetector.

For more details on how the simulation is implemented, see The slsDetectorSimulation Section.

How to receive data from an SLS detector

The SlsReceiver class allows you to receive data from a Gotthard, or another Detector supported by PSI’s slsDetectorPackage.

The detector configuration, and the acquisition command, must be executed somewhere else, for example by the command line interface provided by PSI, or by a SlsControl Karabo device.

How to create a receiver device based on slsReceiver

If your detector is not covered by an already existing SlsReceiver derived class, it can easily added to the slsReceiver package. You have to create the source and header files (see MyReceiver.hh file and MyReceiver.cc file Sections) and add them to the Netbeans project. You also have to compile the project in Netbeans (Debug, Release and Simulation mode) in order to have the Makefiles updated.

Do not forget to “git add” the new files.

Expected parameters

The receiver TCP port number (rx_tcpport) is already one of the expected parameters of the base class (SlsReceiver):

UINT16_ELEMENT(expected).key("rxTcpPort")
        .tags("sls")
        .alias("--rx_tcpport")
        .displayedName("rxTcpPort")
        .description("Receiver TCP Port")
        .assignmentOptional().defaultValue(1954)
        .init()
        .commit();

If you need to pass more options to the slsReceiverUsers object when it is instantiated in Karabo, you can do it by adding more expected parameters to your MyReceiver class. As done for the above one (rx_tcpport), you will need to tag them as “sls”, and to give in their alias the parameter name.

MyReceiver.hh file

This is the minimal MyReceiver.hh:

#ifndef KARABO_MYRECEIVER_HH
#define KARABO_MYRECEIVER_HH

#include <karabo/karabo.hpp>

#include "SlsReceiver.hh"
#include "version.hh"  // provides PACKAGE_VERSION

/**
 * The main Karabo namespace
 */
namespace karabo {

    class MyReceiver : public karabo::SlsReceiver {

    public:

        KARABO_CLASSINFO(MyReceiver, "MyReceiver", "PACKAGE_VERSION")
        static void expectedParameters(karabo::util::Schema& expected);

        MyReceiver(const karabo::util::Hash& config);

        virtual ~MyReceiver();

    private: // Raw data unpacking

        size_t getDetectorSize();
        std::vector<unsigned long long> getDisplayShape();
        std::vector<unsigned long long> getDaqShape(unsigned short framesperTrain);
        void unpackRawData(const char* data, size_t idx, unsigned short* adc, unsigned char* gain);

    };

} /* namespace karabo */

#endif /* KARABO_MYRECEIVER_HH */

You probably don’t need anything more than that.

Some functions are pure virtual in SlsReceiver and must be defined in the derived class:

  • getDetectorSize
  • getDisplayShape
  • getDaqShape
  • unpackRawData

MyReceiver.cc file

The pure virtual functions which must be defined in the derived class are:

size_t getDetectorSize()

returns the size of the detector (i.e. the number of channels, or pixels).

std::vector<unsigned long long> getDisplayShape()

returns the shape of one frame (can be 1- or 2-d).

std::vector<unsigned long long> getDaqShape(unsigned short framesPerTrain)

returns the shape of the data as needed by the DAQ (frames are grouped per train before being sent to the DAQ, therefore it is 2- or 3-d; moreover the DAQ wants the first dimension to be the fastest changing, the last dimension the slowest).

void unpackRawData(const char* data, size_t idx, unsigned short* adc, unsigned short* gain)

fill-up the <adc> and <gain> buffers with the ADC and gain values contained in <data> for the packet <idx>.

An example of MyReceiver.cc is the following. In the best case you will just have to change the constants (here for the Gotthard) to match the raw data format of the detector:

#include "MyReceiver.hh"

USING_KARABO_NAMESPACES

// e.g. Gotthard channels
#define MY_CHANNELS 1280

// e.g. Gotthard raw data: unpacking adc/gain bytes
#define MY_ADC_MASK       0x3FFF
#define MY_GAIN_MASK      0xC000
#define MY_GAIN_OFFSET        14

namespace karabo {

    KARABO_REGISTER_FOR_CONFIGURATION(BaseDevice, Device<>, SlsReceiver,
        MyReceiver)

    void MyReceiver::expectedParameters(Schema& expected) {
        Schema displayData;

        // This is the schema for data display in the GUI,
        // in this example for 1-d data
        NODE_ELEMENT(displayData).key("data")
                .displayedName("Data")
                .commit();

        VECTOR_UINT16_ELEMENT(displayData).key("data.adc")
                .displayedName("ADC")
                .description("The ADC counts.")
                .readOnly()
                .commit();

        VECTOR_UINT(_ELEMENT(displayData).key("data.gain")
                .displayedName("Gain")
                .description("The ADC gain.")
                .readOnly()
                .commit();

        OUTPUT_CHANNEL(expected).key("display")
                .displayedName("Display")
                .dataSchema(displayData)
                .commit();
    }

    MyReceiver::MyReceiver(const karabo::util::Hash& config) :
            SlsReceiver(config) {
    }

    MyReceiver::~MyReceiver() {
    }

    unsigned short MyReceiver::getDetectorSize() {
        return MY_CHANNELS;
    }

    std::vector<unsigned long long> MyReceiver::getDisplayShape() {
        return {this->getDetectorSize()};
    }

    std::vector<unsigned long long> MyReceiver::getDaqShape(unsigned short framesPerTrain) {
        // DAQ first dimension is fastest changing one
        return {this->getDetectorSize(), framesPerTrain};
    }

    void MyReceiver::unpackRawData(const char* data, size_t idx, unsigned short* adc, unsigned char* gain) {
        // e.g. For Gotthard:
        const size_t frameSize = this->getDetectorSize();
        size_t offset = sizeof(unsigned short) * idx * frameSize;
        const char* ptr = data + offset; // Base address of the <idx> frame

        for (size_t i = 0; i < frameSize; ++i) {
            adc[i] = (reinterpret_cast<const unsigned short*> (ptr))[i] & MY_ADC_MASK;
            gain[i] = ((reinterpret_cast<const unsigned short*> (ptr))[i] & MY_GAIN_MASK) >> MY_GAIN_OFFSET;
        }
    }

} /* namespace karabo */

Simulation Mode

To compile the slsReceiver in simulation mode, just run

make CONF=Simulation

This way the package will be linked against the simulation, instead of libSlsReceiver.

For more details on how the simulation is implemented, see The slsDetectorSimulation Section.

Troubleshooting

The control device is in UNKNOWN state

This means that the Karabo device cannot connect to the detector. You should check that

  • the detector is connected to the network,
  • and it is powered.

A possible way to verify that the detector is online is to login to the control server and use the ping command [1].

Detector power can often be controlled via a Beckhoff digital output device, with the same domain name as the detector, but different type and member. For example to the detector SA1_XTD9_HIREX/DET/GOTTHARD correspond the Beckhoff devices SA1_XTD9_HIREX/DCTRL/GOTTHARD_MASTER_POWER and SA1_XTD9_HIREX/DCTRL/GOTTHARD_SLAVE_POWER, which can be used to power on and off the Gotthard’s master and slave.

If the detector is online but still in UNKNOWN state, it can be that the server software on the detector is not running. In this you can can try to reboot the detectors micro-controller as explained in the next Section.

Rebooting the detector

If the detector is online but not working properly, it can be restarted by connecting to it. For example, if 192.168.194.82 is the IP of module to be restarted:

telnet 192.168.194.82

and then execute:

reboot

This command will restart the micro-controller, without the need of a complete power cycle of the detector.

The control device is in ERROR state

The control device will go to ERROR state if the receiver device(s) is (are) not running. This can happen because the instantiation sequence was not correct, or because the receiver device(s) went down.

The correct starting sequence is

  • start receiver device(s) first;
  • then start the control device.

To recover for the ERROR, please make sure that the receiver device(s) are online, then reset the control device.

The control device is in INIT state

This usually means that the detector is online but cannot be configured. Try to reboot is as described in this Section.

The receiver device is in ERROR state

This usually means that the RX TCP port used by this Karabo device, is already in use.

The control device is ACQUIRING but receiver’s Frame Rate In is 0

If you are in external trigger mode (Timing Mode = trigger), it is possible that the detector receives no trigger signal. You can test it by setting the trigger mode to internal (auto).

Frame Rate Out is not 0, but no images are visible in the GUI

First check that the flag onlineDisplayEnable on the receiver device is enabled.

If the flag is set to True, then it could be that the GUI server is malfunctioning. In case there is a second GUI server available for the topic, try to switch to that one.

Frame Rate Out is not 0, but the DAQ does not save any data

Check that in the DAQ Output node the hostname is set to the IP address of the 10 GbE interface dedicated to the DAQ.

The receiver device prints out TCP socket errors

If the receiver device logs messages like

they can be safely ignored.

This is because the control device, in order to check that the receiver is online, opens a TCP connection to it. The receiver complains as no data is exchanged before the connection is closed.

This is a periodic check repeated every 20 s.

If nothing else helps…

In order to cleanly restart the system, follow these steps:

  • shutdown the Karabo devices and the servers;
  • power off the detector;
  • optionally execute sls_detector_get free on the control server (this step should not be needed, as this “free” action is done by the Karabo control device);
  • power up the detector;
  • instantiate the receiver device(s);
  • instantiate the control device.
[1]https://linux.die.net/man/8/ping

The slsDetectorSimulation

In this package a subset of the slsDetector package have been reimplemented, in a simulation mode.

The Receiver Class

It reimplements part of the functionalities of the same class from the slsDetectorPackage. In order to use it, you need to include slssimulation/Receiver.h and link libSlsSimulation.so.

The Receiver class runs a TCP/IP server on the port specified on start-up by the argument –rx_tcpport or -t.

The commands known to the Receiver TCP/IP server are:

  • start: to start generating simulated data (till the stop command is received);
  • stop: to stop generating data;
  • exptime [ns]: to set the exposure time parameter;
  • delay [ns]: to set the delay after trigger parameter;
  • period [ns]: to set the period parameter;
  • detectortype: to set the detector type; an integer value must be used; the options are defined in slssimulation/sls_simulation_defs.h;
  • fpath: to set the output path;
  • fname: to set the root name of the output file;
  • findex: to set the start index of the output file;
  • fwrite: to enable or disable the output file write;
  • settings: to select the settings; an integer value must be used; the options are defined in slssimulation/sls_simulation_defs.h.

The Detector Class

It reimplements part of the functionalities of the same class from the slsDetectorPackage. In order to use it, you need to include slssimulation/Detector.h and link libSlsSimulation.so.

It currently has the limitation that it can only control one simulated detector.

The Detector::start() function will connect to the Receiver TCP/IP server, configure it and start an acquisition.

The Detector::stop() function will stop the acquisition, if still ongoing.

Indices and tables