Skip to content

Writing a MCA controller

To add an MCA controller, it is needed to write a new controller class in module bliss.controllers.mca. This controller class musst inherate from BaseMca class located in module bliss/controller/mca/base.py.

The following methods has to be implemented for the new controller.

initialisation methods

  • initialize_attributes(self) : This method is called after reading the configuration and before performing hardware init. It is mainly used to define private attributes needed by the controller class. If needed, the configuration is accessible through self._config attribute.

  • initialize_hardware(self) : method used to instantiate communication with the controller. It is called after initialize_attributes(). If communication failed, should raise an exception.

  • finalize(self) : called before mca object is deleted in bliss, typically on shell exit. Used to close communication channel.

detector information methods

  • detector_brand(self) : Return one of the detector brand from the Brand enum found in bliss/controllers/mca/base.py.

  • detector_type(self) : Return one of the detector type from the DetectorType enum found in bliss/controllers/mca/base.py.

  • elements(self) : Return a tuple of detector element number (ex: (1, 2, 3, 4)). These element numbers will be used to reference detector elements in data sent to bliss (details in data event).

  • spectrum_size(self) : Return the length of the spectrums (ex: 4096). Spectrum length is supposed to be the same for all elements of the detector.

  • spectrum_size(self, size) : Set if possible the new spectrum size. If not possible an error is raised.

  • spectrum_range(self) : Return the spectrum range. By default the spectrum range returned is (0, spectrum_size - 1).

  • spectrum_range(self, first_last_tuple) : Set the spectrum range if possible (ex: (512, 2048)). If not possible an error is raised.

acquisition methods

acquisition modes

Some controllers may accept different acquisition mode. The available mode are defined in the enum AcquisitionMode found in bliss/controllers/xia/counter.py. Only 2 modes are defined:

  • MCA mode : acquire full spectrum and computes ROIs counters on it.

  • HWSCA mode : ROIs are programmed on the controller which output the defined ROIs as frequency signal. Those signals are usually plugged in a counter/timer board. No data are then managed by the MCA bliss object.

The following methods has to be overwritten only if your controller support other acquisition mode than default MCA one.

  • supported_acquisition_modes(self) : Return list of supported modes taken from AcquisitionMode. By default, it return AcquisitionMode.MCA.

  • acquisition_mode(self) : Return the current acquisition mode.

  • acquisition_mode(self, mode) : Set the current acquisition mode.

preset modes

When using an MCA in a software controlled way, we can usually define a preset to control the end of acquisition. Standard preset modes are defined in the PresetMode enum found in bliss/controllers/xia/base.py. Preset modes supported are:

  • NONE : no preset. Acquisition needs to stopped by software command.
  • REALTIME : acquisition will stop when realtime reaches set value.
  • LIVETIME : acquisition will stop when livetime reaches set value.
  • EVENTS : acquisition will stop when output counts reaches set value.
  • TRIGGERS : acquisition will stop when input counts reaches set value.

The following methods have to be implemented to define preset mode:

  • supported_preset_modes(self) : Return the list of supported preset mode taken from PresetMode enum.

  • preset_mode(self) : Return current preset mode.

  • preset_mode(self, mode) : Set current preset mode.

  • preset_value(self) : Return current preset value. Unit of value depends on preset mode configured.

  • preset_value(self, value) : Set current preset value. Unit of value depends on preset mode configured.

trigger modes

Trigger modes are defined in TriggerMode enum defined in bliss/controllers/mca/base.py. Defined trigger modes are:

  • SOFTWARE : No hardware synchronization. Acquisition will be started by software command. Depending on preset mode configured, acquisition will be stopped by software (NONE preset) or by the controller itself (all other preset modes).
  • SYNC : Each external signal trigger received will instantiate a memory reading on the controller. N triggers generates N spectrums. Acquisition starts on software start command.
  • GATE : Acquisition is gated for each point by external signal.

The following methods have to be implemented.

  • supported_trigger_modes(self) : Return list of supported trigger modes.

  • trigger_mode(self) : Get the current trigger mode.

  • trigger_mode(self, value) : Set the current trigger mode.

When using one of the hardware trigger mode (SYNC or GATE), the number of points acquired will be defined by the property hardware_points. Following methods are used to define this property:

  • hardware_points(self) : return number of points set.

  • hardware_points(self, value) : set number of points for next acquisition.

controller buffer

Some controllers can managed an internal buffer. Following methods are available to define the size of this buffer. These methods are mandatory as long as your controller supports one of the hardware trigger mode.

  • block_size(self) : return current block size ( = number of spectrum of one detector element which can be kept in controller memory)

  • block_size(self, value) : sets the block size.

Some controller API uses an internal polling loop to transfer spectrums from controller to PC memory. Some accepts to configure the rate of this polling loop. Following methods are provided to configure it.

  • refresh_rate(self) : return current refresh rate

  • refresh_rate(self, value) : set controller refresh rate

acquisition commands

The acquisition is managed in bliss by the acquisition object McaAcquisitionSlave defined in bliss/scanning/acquisition/mca.py. In the prepare() phase, all acquisition parameters will be set. This includes preset mode/value, trigger mode, hardware points, block size (see details in acquisition object workflow). Once all acquisition parameters are set, the following methods will be used by the acquisition object to manage the acquisition.

  • start_acquisition(self) : if trigger mode is either SYNC or GATE, it will be called to start an acquisition.

  • start_hardware_reading(self) : if trigger mode is either SYNC or GATE, it will be called just after start_acquisition(). It is the place to start the hardware reading task, but this method should not block. It must spawn a hardware reading loop which should send a data event for each point (see data event).

  • trigger(self) : in a software-base acquisition (ie. trigger mode set to SOFT), it will be called for each point in the scan. For each scan point, this method should:

    • start one point acquisition
    • wait end of acquisition
    • read spectrum and statistics and send a data event (see data event).
  • stop_acquisition(self) : stop current acquisition.

  • wait_hardware_reading(self) : if trigger mode is either SYNC or GATE, it will be called just after the stop_acquisition(). This methods should block until all hardware buffer has been read.

  • is_acquiring(self) : return True/False

acquisition object workflow

As the MCA controller is integrated in bliss scans using acquisition object MCAAcquisitionSlave, it is important to keep in mind the acquisition object workflow when writing a new controller. There is 2 way of working, depending if acquisition is hardware triggered or not:

  • For SOFT trigger mode:

    • during prepare acquisition phase :
      • set trigger_mode
      • set spectrum_size
      • set refresh_rate
      • set preset_mode to REALTIME
      • set preset_value to acquisition time
    • call trigger() for each point in the scan
    • when all data points received or stop requested:
      • call stop_acquisition()
  • For SYNC or GATE trigger modes:

    • during prepare acquisition phase :
      • set trigger_mode
      • set spectrum_size
      • set refresh_rate
      • set hardware_points
      • set block_size
    • call start_acquisition() once for all points
    • call start_hardware_reading() once for all points
    • when all data points received or stop requested:
      • call stop_acquisition()
      • call wait_hardware_reading()

data event

From the MCA controller, data (spectrums and statistic counters) are sent to the acquisition object (and the bliss data management) using events. This data event has to be fired by trigger() methods for SOFT triggers and hardware reading task for SYNC and GATE trigger modes. The way to send event is as follow:

from bliss.common import event

class MyMcaController(BaseMca):
    def trigger(self):
        ...
        event.send(self, "data", (spectra, statistics))
        ...

One event is sent for each data point. In each event, data contains spectrums and statistics value for all detector elements.

spectra is a dictionnary with element number as keys and numpy array as value:

    spectra = {}
    for i in self.elements:
        spectra[i] = numpy.array(data)

statistics is also a dictionnary with element number as keys and Stats named tuple as value. The Stats definition is in bliss/controller/mca/counter.py.

    statistics = {}
    for i in self.elements:
        statistics[i] = Stats(realtime_for_i,
                              trigger_livetime_for_i,
                              energy_livetime_for_i,
                              triggers_for_i,
                              events_for_i,
                              icr_for_i,
                              ocr_for_i,
                              deadtime_for_i
                        )

To advertise that all buffers has been read, controller can send a StopIteration exception:

     event.send(self, "data", StopIteration)
Any other exception sent will be re-raised to the scan engine. For example, in case of hardware buffer overrun, one can send a RuntimeError. This exeception will be re-raised by the mca acquisition object and the scan engine will stop the scan properly.

additionnal test methods on MCA base controller

Three tests methods has been added to MCA controller base class. These methods are not used in the bliss scan engine. They are there only to test a controller without using the bliss scan machinery. These functions are:

  • run_software_acquisition(self, acquisition_number, acquisition_time, polling_time) to perform a SOFT acquisition
  • run_gate_acquisition(self, acquisition_number, block_size, polling_time) to perform a GATE triggered acquisition. Gate has to be provided by an external device not managed here.
  • run_synchronized_acquisition(self, acquisition_number, block_size, polling_time) to perform a SYNC triggered acquisition. Triggers has to be provided by an external device not managed here.

In order that these tests functions works for a new controller, three methods have to implemented :

  • get_acquisition_data(self) : return acquired spectrum arrays for run_software_acquisition()
  • get_acquisition_statistics(self) : return acquired statistic named tuple for run_software_acquisition()
  • poll_data(self) : return data and statistics for multiple points during run_gate_acquisition() or run_synchronized_acquisition(). Method should return a tuple (current, data, statistics), current being the last point number, data a list of data as defined in data event, statistics a list of statistics as defined in data event.

Note

These three methods are not mandatory for operating an MCA inside BLISS. They are only used internally in the tests methods listed above.

class diagram

MCA classes