Esempio n. 1
0
    def _build_elements(self):
        self._user_elements = []
        self._physical_elements = {}
        self._physical_elements_set = set()

        pool = self._get_pool()
        for user_element_id in self._user_element_ids:
            # an internal element
            internal = isinstance(user_element_id, int)
            if internal:
                try:
                    user_element = pool.get_element(id=user_element_id)
                except KeyError:
                    self._pending = True
                    self._user_elements = None

                    self._physical_elements = None
                    self._physical_elements_set = None
                    raise
                internal = self._is_managed_element(user_element)
                if not internal:
                    user_element_id = user_element.get_source()
            # a tango channel or non internal element (ex: ioregister or motor
            # in measurement group)
            if not internal:
                # TODO: for Taurus4 compatibility
                validator = TangoAttributeNameValidator()
                params = validator.getParams(user_element_id)
                if params is None:
                    user_element_id = "tango://%s" % user_element_id
                    params = validator.getParams(user_element_id)
                params['pool'] = self._get_pool()
                user_element = PoolExternalObject(**params)
            self.add_user_element(user_element)
        self._pending = False
Esempio n. 2
0
    def _build_elements(self):
        self._user_elements = []
        self._physical_elements = {}
        self._physical_elements_set = set()

        pool = self._get_pool()
        for user_element_id in self._user_element_ids:
            # an internal element
            internal = type(user_element_id) is int
            if internal:
                try:
                    user_element = pool.get_element(id=user_element_id)
                except KeyError:
                    self._pending = True
                    self._user_elements = None

                    self._physical_elements = None
                    self._physical_elements_set = None
                    raise
                internal = self._is_managed_element(user_element)
                if not internal:
                    user_element_id = user_element.get_source()
            # a tango channel or non internal element (ex: ioregister or motor
            # in measurement group)
            if not internal:
                validator = TangoAttributeNameValidator()
                params = validator.getParams(user_element_id)
                params['pool'] = self._get_pool()
                user_element = PoolExternalObject(**params)
            self.add_user_element(user_element)
        self._pending = False
Esempio n. 3
0
    def set_configuration_from_user(self, cfg, propagate=1):
        config = {}
        user_elements = self.get_user_elements()
        pool = self.pool

        timer_name = cfg.get('timer', user_elements[0].full_name)
        monitor_name = cfg.get('monitor', user_elements[0].full_name)
        config['timer'] = pool.get_element_by_full_name(timer_name)
        config['monitor'] = pool.get_element_by_full_name(monitor_name)
        config['controllers'] = controllers = {}

        for c_name, c_data in cfg['controllers'].items():
            # discard controllers which don't have items (garbage)
            ch_count = 0
            for u_data in c_data['units'].values():
                ch_count += len(u_data['channels'])
            if ch_count == 0:
                continue

            external = c_name.startswith('__')
            if external:
                ctrl = c_name
            else:
                ctrl = pool.get_element_by_full_name(c_name)
                assert ctrl.get_type() == ElementType.Controller
            controllers[ctrl] = ctrl_data = {}
            ctrl_data['units'] = units = {}
            for u_id, u_data in c_data['units'].items():
                # discard units which don't have items (garbage)
                if len(u_data['channels']) == 0:
                    continue
                units[u_id] = unit_data = dict(u_data)
                unit_data['id'] = u_data.get('id', u_id)
                if not external and ctrl.is_timerable():
                    unit_data['timer'] = pool.get_element_by_full_name(
                        u_data['timer'])
                    unit_data['monitor'] = pool.get_element_by_full_name(
                        u_data['monitor'])
                    unit_data['trigger_type'] = u_data['trigger_type']
                unit_data['channels'] = channels = {}
                for ch_name, ch_data in u_data['channels'].items():
                    if external:
                        validator = TangoAttributeNameValidator()
                        params = validator.getParams(ch_data['full_name'])
                        params['pool'] = self.pool
                        channel = PoolExternalObject(**params)
                    else:
                        channel = pool.get_element_by_full_name(ch_name)
                    channels[channel] = dict(ch_data)

        config['label'] = cfg.get('label', self.name)
        config['description'] = cfg.get('description', self.DFT_DESC)
        self.set_configuration(config, propagate=propagate)
Esempio n. 4
0
    def set_configuration_from_user(self, cfg, propagate=1):
        config = {}
        user_elements = self.get_user_elements()
        pool = self.pool

        timer_name = cfg.get('timer', user_elements[0].full_name)
        monitor_name = cfg.get('monitor', user_elements[0].full_name)
        config['timer'] = pool.get_element_by_full_name(timer_name)
        config['monitor'] = pool.get_element_by_full_name(monitor_name)
        config['controllers'] = controllers = {}

        for c_name, c_data in cfg['controllers'].items():
            # discard controllers which don't have items (garbage)
            ch_count = 0
            for u_data in c_data['units'].values():
                ch_count += len(u_data['channels'])
            if ch_count == 0:
                continue

            external = c_name.startswith('__')
            if external:
                ctrl = c_name
            else:
                ctrl = pool.get_element_by_full_name(c_name)
                assert ctrl.get_type() == ElementType.Controller
            controllers[ctrl] = ctrl_data = {}
            ctrl_data['units'] = units = {}
            for u_id, u_data in c_data['units'].items():
                # discard units which don't have items (garbage)
                if len(u_data['channels']) == 0:
                    continue
                units[u_id] = unit_data = dict(u_data)
                unit_data['id'] = u_data.get('id', u_id)
                if not external and ctrl.is_timerable():
                    unit_data['timer'] = pool.get_element_by_full_name(u_data['timer'])
                    unit_data['monitor'] = pool.get_element_by_full_name(u_data['monitor'])
                    unit_data['trigger_type'] = u_data['trigger_type']
                unit_data['channels'] = channels = {}
                for ch_name, ch_data in u_data['channels'].items():
                    if external:
                        validator = TangoAttributeNameValidator()
                        params = validator.getParams(ch_data['full_name'])
                        params['pool'] = self.pool
                        channel = PoolExternalObject(**params)
                    else:
                        channel = pool.get_element_by_full_name(ch_name)
                    channels[channel] = dict(ch_data)

        config['label'] = cfg.get('label', self.name)
        config['description'] = cfg.get('description', self.DFT_DESC)
        self.set_configuration(config, propagate=propagate)
Esempio n. 5
0
    def create_measurement_group(self, **kwargs):
        name = kwargs['name']
        elem_ids = kwargs["user_elements"]

        kwargs['pool'] = self
        kwargs["pool_name"] = self.name

        td = TYPE_MAP_OBJ[ElementType.MeasurementGroup]
        klass = td.klass
        auto_full_name = td.auto_full_name

        full_name = kwargs.get("full_name", auto_full_name.format(**kwargs))
        kwargs.pop('pool_name')

        self.check_element(name, full_name)

        for elem_id in elem_ids:
            if isinstance(elem_id, int):
                self.pool.get_element(id=elem_id)
            else:
                tg_attr_validator = TangoAttributeNameValidator()
                params = tg_attr_validator.getParams(elem_id)
                if params is None:
                    raise Exception("Invalid channel name %s" % elem_id)

        eid = kwargs.get('id')
        if eid is None:
            kwargs['id'] = eid = self.get_new_id()
        else:
            self.reserve_id(eid)

        elem = klass(**kwargs)

        ret = self.add_element(elem)
        self.fire_event(EventType("ElementCreated"), elem)
        return ret
Esempio n. 6
0
    def create_measurement_group(self, **kwargs):
        name = kwargs['name']
        elem_ids = kwargs["user_elements"]

        kwargs['pool'] = self
        kwargs["pool_name"] = self.name

        td = TYPE_MAP_OBJ[ElementType.MeasurementGroup]
        klass = td.klass
        auto_full_name = td.auto_full_name

        full_name = kwargs.get("full_name", auto_full_name.format(**kwargs))
        kwargs.pop('pool_name')

        self.check_element(name, full_name)

        for elem_id in elem_ids:
            if isinstance(elem_id, int):
                self.pool.get_element(id=elem_id)
            else:
                tg_attr_validator = TangoAttributeNameValidator()
                params = tg_attr_validator.getParams(elem_id)
                if params is None:
                    raise Exception("Invalid channel name %s" % elem_id)

        eid = kwargs.get('id')
        if eid is None:
            kwargs['id'] = eid = self.get_new_id()
        else:
            self.reserve_id(eid)

        elem = klass(**kwargs)

        ret = self.add_element(elem)
        self.fire_event(EventType("ElementCreated"), elem)
        return ret
Esempio n. 7
0
    def set_configuration_from_user(self, cfg, to_fqdn=True):
        """Load measurement configuration from serializable data structure."""
        user_elements = self._parent.get_user_elements()
        if len(user_elements) == 0:
            # All channels were disabled
            raise ValueError('The configuration has all the channels disabled')

        pool = self._parent.pool

        label = cfg.get('label', self._parent.name)
        description = cfg.get('description', self.DFT_DESC)

        timerable_ctrls = {AcqSynch.HardwareGate: [],
                           AcqSynch.HardwareStart: [],
                           AcqSynch.HardwareTrigger: [],
                           AcqSynch.SoftwareStart: [],
                           AcqSynch.SoftwareTrigger: [],
                           AcqSynch.SoftwareGate: []}
        zerod_ctrls = []
        synch_ctrls = []
        other_ctrls = []
        master_timer_sw = None
        master_monitor_sw = None
        master_timer_sw_start = None
        master_monitor_sw_start = None
        master_timer_idx_sw = float("+inf")
        master_monitor_idx_sw = float("+inf")
        master_timer_idx_sw_start = float("+inf")
        master_monitor_idx_sw_start = float("+inf")
        user_elem_ids = {}
        channel_acq_synch = {}
        ctrl_acq_synch = {}
        user_config = {}

        user_config['controllers'] = {}
        user_config['label'] = label
        user_config['description'] = description

        for ctrl_name, ctrl_data in cfg['controllers'].items():
            # backwards compatibility for measurement groups created before
            # implementing feature-372:
            # https://sourceforge.net/p/sardana/tickets/372/
            # WARNING: this is one direction backwards compatibility - it just
            # reads channels from the units, but does not write channels to the
            # units back
            if 'units' in ctrl_data:
                ctrl_data = ctrl_data['units']['0']
            # discard controllers which don't have items (garbage)
            ch_count = len(ctrl_data['channels'])
            if ch_count == 0:
                continue

            external = ctrl_name.startswith('__')
            if external:
                ctrl = ctrl_name
            else:
                if to_fqdn:
                    ctrl_name = _to_fqdn(ctrl_name, logger=self._parent)
                ctrl = pool.get_element_by_full_name(ctrl_name)
                assert ctrl.get_type() == ElementType.Controller

            user_config['controllers'][ctrl_name] = user_config_ctrl = {}
            ctrl_conf = {}

            synchronizer = ctrl_data.get('synchronizer', 'software')
            conf_synch = None
            if synchronizer is None or synchronizer == 'software':
                ctrl_conf['synchronizer'] = 'software'
                user_config_ctrl['synchronizer'] = 'software'
            else:
                if to_fqdn:
                    synchronizer = _to_fqdn(synchronizer,
                                            logger=self._parent)

                user_config_ctrl['synchronizer'] = synchronizer
                pool_synch = pool.get_element_by_full_name(synchronizer)
                pool_synch_ctrl = pool_synch.controller
                conf_synch = SynchronizerConfiguration(pool_synch)
                conf_synch_ctrl = None
                if len(synch_ctrls) > 0:
                    conf_synch_ctrl = None
                    for conf_ctrl in synch_ctrls:
                        if pool_synch_ctrl == conf_ctrl.element:
                            conf_synch_ctrl = conf_ctrl
                if conf_synch_ctrl is None:
                    conf_synch_ctrl = ControllerConfiguration(pool_synch_ctrl)
                conf_synch_ctrl.add_channel(conf_synch)
                synch_ctrls.append(conf_synch_ctrl)
                ctrl_conf['synchronizer'] = conf_synch

            try:
                synchronization = ctrl_data['synchronization']
            except KeyError:
                # backwards compatibility for configurations before SEP6
                try:
                    synchronization = ctrl_data['trigger_type']
                    msg = ("trigger_type configuration parameter is deprecated"
                           " in favor of synchronization. Re-apply "
                           "configuration in order to upgrade.")
                    self._parent.warning(msg)
                except KeyError:
                    synchronization = AcqSynchType.Trigger

            ctrl_conf['synchronization'] = synchronization
            user_config_ctrl['synchronization'] = synchronization

            acq_synch = None
            if external:
                ctrl_item = ExternalControllerConfiguration(ctrl)
            elif ctrl.is_timerable():
                is_software = synchronizer == 'software'
                acq_synch = AcqSynch.from_synch_type(is_software,
                                                     synchronization)
                ctrl_acq_synch[ctrl] = acq_synch
                ctrl_item = TimerableControllerConfiguration(ctrl, ctrl_conf)
            else:
                ctrl_item = ControllerConfiguration(ctrl, ctrl_conf)

            ctrl_enabled = False
            if 'channels' in ctrl_data:
                user_config_ctrl['channels'] = user_config_channel = {}
            for ch_name, ch_data in ctrl_data['channels'].items():
                if external:
                    validator = TangoAttributeNameValidator()
                    full_name = ch_data.get('full_name', ch_name)
                    params = validator.getParams(full_name)
                    params['pool'] = pool
                    channel = PoolExternalObject(**params)
                else:
                    if to_fqdn:
                        ch_name = _to_fqdn(ch_name, logger=self._parent)
                    channel = pool.get_element_by_full_name(ch_name)
                ch_data = self._fill_channel_data(channel, ch_data)
                user_config_channel[ch_name] = ch_data
                ch_item = ChannelConfiguration(channel, ch_data)
                ch_item.controller = ctrl_item
                ctrl_item.add_channel(ch_item)
                if ch_item.enabled:
                    if external:
                        id_ = channel.full_name
                    else:
                        id_ = channel.id
                    user_elem_ids[ch_item.index] = id_

                if ch_item.enabled:
                    ctrl_enabled = True

                if acq_synch is not None:
                    channel_acq_synch[channel] = acq_synch
            if not external and ctrl.is_timerable():
                ctrl_item.update_timer()
                ctrl_item.update_monitor()
                user_config_ctrl['timer'] = ctrl_item.timer.full_name
                user_config_ctrl['monitor'] = ctrl_item.monitor.full_name
            # Update synchronizer state
            if conf_synch is not None:
                conf_synch.enabled = ctrl_enabled

            ctrl_item.validate()

            if external:
                other_ctrls.append(ctrl_item)
            elif ctrl.is_timerable():
                timerable_ctrls[acq_synch].append(ctrl_item)
                # Find master timer/monitor the system take the channel with
                # less index
                if acq_synch in (AcqSynch.SoftwareTrigger,
                                 AcqSynch.SoftwareGate):
                    if ctrl_item.timer.index < master_timer_idx_sw:
                        master_timer_sw = ctrl_item.timer
                        master_timer_idx_sw = ctrl_item.timer.index
                    if ctrl_item.monitor.index < master_monitor_idx_sw:
                        master_monitor_sw = ctrl_item.monitor
                        master_monitor_idx_sw = ctrl_item.monitor.index
                elif acq_synch == AcqSynch.SoftwareStart:
                    if ctrl_item.timer.index < master_timer_idx_sw_start:
                        master_timer_sw_start = ctrl_item.timer
                        master_timer_idx_sw_start = ctrl_item.timer.index
                    if ctrl_item.monitor.index < master_monitor_idx_sw_start:
                        master_monitor_sw_start = ctrl_item.monitor
                        master_monitor_idx_sw_start = ctrl_item.monitor.index
            elif ctrl.get_ctrl_types()[0] == ElementType.ZeroDExpChannel:
                zerod_ctrls.append(ctrl_item)

        # Update synchronizer controller states
        for conf_synch_ctrl in synch_ctrls:
            conf_synch_ctrl.update_state()

        # Fill user configuration with measurement group's timer & monitor
        # This is a backwards compatibility cause the measurement group's
        # timer & monitor are not used
        if master_timer_sw is not None:
            user_config['timer'] = master_timer_sw.full_name
        elif master_timer_sw_start is not None:
            user_config['timer'] = master_timer_sw_start.full_name
        else:
            user_config['timer'] = cfg['timer']

        if master_monitor_sw is not None:
            user_config['monitor'] = master_monitor_sw.full_name
        elif master_monitor_sw_start is not None:
            user_config['monitor'] = master_monitor_sw_start.full_name
        else:
            user_config['monitor'] = cfg['monitor']

        # Update internals values
        self._label = label
        self._description = description
        self._timerable_ctrls = timerable_ctrls
        self._zerod_ctrls = zerod_ctrls
        self._synch_ctrls = synch_ctrls
        self._other_ctrls = other_ctrls
        self._master_timer_sw = master_timer_sw
        self._master_monitor_sw = master_monitor_sw
        self._master_timer_sw_start = master_timer_sw_start
        self._master_monitor_sw_start = master_monitor_sw_start
        self._user_confg = user_config
        self._channel_acq_synch = channel_acq_synch
        self._ctrl_acq_synch = ctrl_acq_synch

        # sorted ids may not be consecutive (if a channel is disabled)
        indexes = sorted(user_elem_ids.keys())
        user_elem_ids_list = [user_elem_ids[idx] for idx in indexes]
        for conf_synch_ctrl in synch_ctrls:
            for conf_synch in conf_synch_ctrl.get_channels(enabled=True):
                user_elem_ids_list.append(conf_synch.id)
        self._parent.set_user_element_ids(user_elem_ids_list)

        self.changed = True
Esempio n. 8
0
    def set_configuration_from_user(self, cfg, propagate=1, to_fqdn=True):
        config = {}
        user_elements = self.get_user_elements()
        pool = self.pool
        timer_name = cfg.get('timer', user_elements[0].full_name)
        monitor_name = cfg.get('monitor', user_elements[0].full_name)
        if to_fqdn:
            timer_name = _to_fqdn(timer_name, logger=self)
        config['timer'] = pool.get_element_by_full_name(timer_name)
        if to_fqdn:
            monitor_name = _to_fqdn(monitor_name, logger=self)
        config['monitor'] = pool.get_element_by_full_name(monitor_name)
        config['controllers'] = controllers = {}

        for c_name, c_data in cfg['controllers'].items():
            # backwards compatibility for measurement groups created before
            # implementing feature-372:
            # https://sourceforge.net/p/sardana/tickets/372/
            # WARNING: this is one direction backwards compatibility - it just
            # reads channels from the units, but does not write channels to the
            # units back
            if 'units' in c_data:
                c_data = c_data['units']['0']
            # discard controllers which don't have items (garbage)
            ch_count = len(c_data['channels'])
            if ch_count == 0:
                continue

            external = c_name.startswith('__')
            if external:
                ctrl = c_name
            else:
                if to_fqdn:
                    c_name = _to_fqdn(c_name, logger=self)
                ctrl = pool.get_element_by_full_name(c_name)
                assert ctrl.get_type() == ElementType.Controller
            controllers[ctrl] = ctrl_data = {}

            # exclude external and not timerable elements
            if not external and ctrl.is_timerable():
                timer_name = c_data['timer']
                if to_fqdn:
                    timer_name = _to_fqdn(timer_name, logger=self)
                timer = pool.get_element_by_full_name(timer_name)
                ctrl_data['timer'] = timer
                monitor_name = c_data['monitor']
                if to_fqdn:
                    monitor_name = _to_fqdn(monitor_name, logger=self)
                monitor = pool.get_element_by_full_name(monitor_name)
                ctrl_data['monitor'] = monitor
                synchronizer = c_data.get('synchronizer')
                # for backwards compatibility purposes
                # protect measurement groups without synchronizer defined
                if synchronizer is None:
                    synchronizer = 'software'
                elif synchronizer != 'software':
                    if to_fqdn:
                        synchronizer = _to_fqdn(synchronizer, logger=self)
                    synchronizer = pool.get_element_by_full_name(synchronizer)
                ctrl_data['synchronizer'] = synchronizer
                try:
                    synchronization = c_data['synchronization']
                except KeyError:
                    # backwards compatibility for configurations before SEP6
                    synchronization = c_data['trigger_type']
                    msg = ("trigger_type configuration parameter is deprecated"
                           " in favor of synchronization. Re-apply "
                           "configuration in order to upgrade.")
                    self.warning(msg)
                ctrl_data['synchronization'] = synchronization
            ctrl_data['channels'] = channels = {}
            for ch_name, ch_data in c_data['channels'].items():
                if external:
                    validator = TangoAttributeNameValidator()
                    params = validator.getParams(ch_data['full_name'])
                    params['pool'] = self.pool
                    channel = PoolExternalObject(**params)
                else:
                    if to_fqdn:
                        ch_name = _to_fqdn(ch_name, logger=self)
                    channel = pool.get_element_by_full_name(ch_name)
                channels[channel] = dict(ch_data)

        config['label'] = cfg.get('label', self.name)
        config['description'] = cfg.get('description', self.DFT_DESC)

        self.set_configuration(config, propagate=propagate, to_fqdn=to_fqdn)
Esempio n. 9
0
    def set_configuration_from_user(self, cfg, to_fqdn=True):
        """Load measurement configuration from serializable data structure."""
        user_elements = self._parent.get_user_elements()
        if len(user_elements) == 0:
            # All channels were disabled
            raise ValueError('The configuration has all the channels disabled')

        pool = self._parent.pool

        label = cfg.get('label', self._parent.name)
        description = cfg.get('description', self.DFT_DESC)

        timerable_ctrls = {
            AcqSynch.HardwareGate: [],
            AcqSynch.HardwareStart: [],
            AcqSynch.HardwareTrigger: [],
            AcqSynch.SoftwareStart: [],
            AcqSynch.SoftwareTrigger: [],
            AcqSynch.SoftwareGate: []
        }
        zerod_ctrls = []
        synch_ctrls = []
        other_ctrls = []
        master_timer_sw = None
        master_monitor_sw = None
        master_timer_sw_start = None
        master_monitor_sw_start = None
        master_timer_idx_sw = float("+inf")
        master_monitor_idx_sw = float("+inf")
        master_timer_idx_sw_start = float("+inf")
        master_monitor_idx_sw_start = float("+inf")
        user_elem_ids = {}
        channel_acq_synch = {}
        ctrl_acq_synch = {}
        user_config = {}

        user_config['controllers'] = {}
        user_config['label'] = label
        user_config['description'] = description

        for ctrl_name, ctrl_data in cfg['controllers'].items():
            # backwards compatibility for measurement groups created before
            # implementing feature-372:
            # https://sourceforge.net/p/sardana/tickets/372/
            # WARNING: this is one direction backwards compatibility - it just
            # reads channels from the units, but does not write channels to the
            # units back
            if 'units' in ctrl_data:
                ctrl_data = ctrl_data['units']['0']
            # discard controllers which don't have items (garbage)
            ch_count = len(ctrl_data['channels'])
            if ch_count == 0:
                continue

            external = ctrl_name.startswith('__')
            if external:
                ctrl = ctrl_name
            else:
                if to_fqdn:
                    ctrl_name = _to_fqdn(ctrl_name, logger=self._parent)
                ctrl = pool.get_element_by_full_name(ctrl_name)
                assert ctrl.get_type() == ElementType.Controller

            user_config['controllers'][ctrl_name] = user_config_ctrl = {}
            ctrl_conf = {}

            synchronizer = ctrl_data.get('synchronizer', 'software')
            conf_synch = None
            if synchronizer is None or synchronizer == 'software':
                ctrl_conf['synchronizer'] = 'software'
                user_config_ctrl['synchronizer'] = 'software'
            else:
                if to_fqdn:
                    synchronizer = _to_fqdn(synchronizer, logger=self._parent)

                user_config_ctrl['synchronizer'] = synchronizer
                pool_synch = pool.get_element_by_full_name(synchronizer)
                pool_synch_ctrl = pool_synch.controller
                conf_synch = SynchronizerConfiguration(pool_synch)
                conf_synch_ctrl = None
                if len(synch_ctrls) > 0:
                    conf_synch_ctrl = None
                    for conf_ctrl in synch_ctrls:
                        if pool_synch_ctrl == conf_ctrl.element:
                            conf_synch_ctrl = conf_ctrl
                if conf_synch_ctrl is None:
                    conf_synch_ctrl = ControllerConfiguration(pool_synch_ctrl)
                conf_synch_ctrl.add_channel(conf_synch)
                synch_ctrls.append(conf_synch_ctrl)
                ctrl_conf['synchronizer'] = conf_synch

            try:
                synchronization = ctrl_data['synchronization']
            except KeyError:
                # backwards compatibility for configurations before SEP6
                try:
                    synchronization = ctrl_data['trigger_type']
                    msg = ("trigger_type configuration parameter is deprecated"
                           " in favor of synchronization. Re-apply "
                           "configuration in order to upgrade.")
                    self._parent.warning(msg)
                except KeyError:
                    synchronization = AcqSynchType.Trigger

            ctrl_conf['synchronization'] = synchronization
            user_config_ctrl['synchronization'] = synchronization

            acq_synch = None
            if external:
                ctrl_item = ExternalControllerConfiguration(ctrl)
            elif ctrl.is_timerable():
                is_software = synchronizer == 'software'
                acq_synch = AcqSynch.from_synch_type(is_software,
                                                     synchronization)
                ctrl_acq_synch[ctrl] = acq_synch
                ctrl_item = TimerableControllerConfiguration(ctrl, ctrl_conf)
            else:
                ctrl_item = ControllerConfiguration(ctrl, ctrl_conf)

            ctrl_enabled = False
            if 'channels' in ctrl_data:
                user_config_ctrl['channels'] = user_config_channel = {}
            for ch_name, ch_data in ctrl_data['channels'].items():
                if external:
                    validator = TangoAttributeNameValidator()
                    full_name = ch_data.get('full_name', ch_name)
                    params = validator.getParams(full_name)
                    params['pool'] = pool
                    channel = PoolExternalObject(**params)
                else:
                    if to_fqdn:
                        ch_name = _to_fqdn(ch_name, logger=self._parent)
                    channel = pool.get_element_by_full_name(ch_name)
                ch_data = self._fill_channel_data(channel, ch_data)
                user_config_channel[ch_name] = ch_data
                ch_item = ChannelConfiguration(channel, ch_data)
                ch_item.controller = ctrl_item
                ctrl_item.add_channel(ch_item)
                if ch_item.enabled:
                    if external:
                        id_ = channel.full_name
                    else:
                        id_ = channel.id
                    user_elem_ids[ch_item.index] = id_

                if ch_item.enabled:
                    ctrl_enabled = True

                if acq_synch is not None:
                    channel_acq_synch[channel] = acq_synch
            if not external and ctrl.is_timerable():
                ctrl_item.update_timer()
                ctrl_item.update_monitor()
                user_config_ctrl['timer'] = ctrl_item.timer.full_name
                user_config_ctrl['monitor'] = ctrl_item.monitor.full_name
            # Update synchronizer state
            if conf_synch is not None:
                conf_synch.enabled = ctrl_enabled

            ctrl_item.validate()

            if external:
                other_ctrls.append(ctrl_item)
            elif ctrl.is_timerable():
                timerable_ctrls[acq_synch].append(ctrl_item)
                # Find master timer/monitor the system take the channel with
                # less index
                if acq_synch in (AcqSynch.SoftwareTrigger,
                                 AcqSynch.SoftwareGate):
                    if ctrl_item.timer.index < master_timer_idx_sw:
                        master_timer_sw = ctrl_item.timer
                        master_timer_idx_sw = ctrl_item.timer.index
                    if ctrl_item.monitor.index < master_monitor_idx_sw:
                        master_monitor_sw = ctrl_item.monitor
                        master_monitor_idx_sw = ctrl_item.monitor.index
                elif acq_synch == AcqSynch.SoftwareStart:
                    if ctrl_item.timer.index < master_timer_idx_sw_start:
                        master_timer_sw_start = ctrl_item.timer
                        master_timer_idx_sw_start = ctrl_item.timer.index
                    if ctrl_item.monitor.index < master_monitor_idx_sw_start:
                        master_monitor_sw_start = ctrl_item.monitor
                        master_monitor_idx_sw_start = ctrl_item.monitor.index
            elif ctrl.get_ctrl_types()[0] == ElementType.ZeroDExpChannel:
                zerod_ctrls.append(ctrl_item)

        # Update synchronizer controller states
        for conf_synch_ctrl in synch_ctrls:
            conf_synch_ctrl.update_state()

        # Fill user configuration with measurement group's timer & monitor
        # This is a backwards compatibility cause the measurement group's
        # timer & monitor are not used
        if master_timer_sw is not None:
            user_config['timer'] = master_timer_sw.full_name
        elif master_timer_sw_start is not None:
            user_config['timer'] = master_timer_sw_start.full_name
        else:
            user_config['timer'] = cfg['timer']

        if master_monitor_sw is not None:
            user_config['monitor'] = master_monitor_sw.full_name
        elif master_monitor_sw_start is not None:
            user_config['monitor'] = master_monitor_sw_start.full_name
        else:
            user_config['monitor'] = cfg['monitor']

        # Update internals values
        self._label = label
        self._description = description
        self._timerable_ctrls = timerable_ctrls
        self._zerod_ctrls = zerod_ctrls
        self._synch_ctrls = synch_ctrls
        self._other_ctrls = other_ctrls
        self._master_timer_sw = master_timer_sw
        self._master_monitor_sw = master_monitor_sw
        self._master_timer_sw_start = master_timer_sw_start
        self._master_monitor_sw_start = master_monitor_sw_start
        self._user_confg = user_config
        self._channel_acq_synch = channel_acq_synch
        self._ctrl_acq_synch = ctrl_acq_synch

        # sorted ids may not be consecutive (if a channel is disabled)
        indexes = sorted(user_elem_ids.keys())
        user_elem_ids_list = [user_elem_ids[idx] for idx in indexes]
        for conf_synch_ctrl in synch_ctrls:
            for conf_synch in conf_synch_ctrl.get_channels(enabled=True):
                user_elem_ids_list.append(conf_synch.id)
        self._parent.set_user_element_ids(user_elem_ids_list)

        self.changed = True