package RFC::CGas;
#$Id: CGas.pm,v 1.70 2021/01/26 08:25:37 sqko Exp $

#######################################################################
#
#
#      RFC::CGas
#
#
# This class defines the behaviour of container gas modules.
# A container gas instance is a virtual device containing two RFC::Gas
# or compatible devices. The API for RFC::CGas instances is identical to 
# RFC::Gas instances with the sole exception of the controler() member
# function which returns a list of devices instead of a single device.
# The benefit of having an almost identical API to RFC::Gas devices is 
# tha an CGas instance can contain RFC::CGas instances as well as 
# normal RFC::Gas instances. 
#
# The reason for RFC::CGas devices is that they are intended for cases 
# where a single gas line contains more than one gas controler for 
# handling vastly differing flow ranges as most MFC's can only give an
# accuracy of 1 percent of fullscale value. By using a RFC::Cgas container,
# the possiblele range of flow values can be extended beyond this.
#
# Beware that you do not inadvertedly create an infinite recursion if
# more than one container device is used!
# 
# Note that in order for the container module to work properly, remember to
# set correct values for 'cutoff_report' for the individual gas names
# in the container as this setting isused to determine if the gas is shut off!
# Incorrect setting of this may cause wrong flow values to be logged! 
#
#######################################################################

use strict;
use warnings;
use RFC::Header;
use RFC::BaseDevice;
use RFC::Cache;
our @ISA = qw(RFC::BaseDevice);

BEGIN {
    use Exporter ();
    our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
    $VERSION = 1.0;
    %EXPORT_TAGS = (
        'standard'=>[],
                    );
    Exporter::export_ok_tags('standard');
    Exporter::export_tags('standard');
    @ISA = qw(Exporter);
}

sub new()
{
    my $class = shift;
    my $self = $class->SUPER::new(@_);
    $self->{'_type'} = 'Multiline';
    $self->{'_info_string'} = "Remember to correctly set 'cutoff_report' for tte gasses in the container as flows may be reported wrongly otherwise!";
    $self->{'_setup_tags'} = ['class','mode','device_1','device_2','maxflow','maxflow_set','cutoff_set','cutoff_report','shift_up','shift_down','steps','sleep','link','title','show_plot','control_name','control_value','master_device','slave_flow','use_cache','include_tally'];
    $self->{'_setup_tags_readonly'} = ['mode','maxflow','cutoff_set'];
    $self->{'_reload_tags'} = ['class','mode','device_1','device_2','shift_up','shift_down'];
    $self->{'_desc'} = {
	'class' => 'Device type',
        'gas' => 'Name of gas controlled by this device',
        'mode' => 'Device control mode',
	'device_1' => 'Device name for first gas device',
	'device_2' => 'Device name for first gas device',
        'maxflow' => 'Maximum flow rate (l/hour), readonly',
        'maxflow_set' => 'Maximum allowable flow rate (l/hour)',
        'cutoff_set' => 'Cutoff flow rate (force close if set below this value), readonly',
        'cutoff_report' => 'Cutoff flow rate for report generation, flows below this level is treated as 0',
	'shift_up' => 'Flow level where control shifts from small to large device, default is maxflow of low flow device',
	'shift_down' => 'Flow level where control shifts from large to small device, default is 80 percent of maxflow of low flow device',
	'steps' => 'Number of steps in flow shift between devices',
	'sleep' => 'Wait time in seconds on each step in a shift between devices',
        'link' => 'Optional gas device name for linking purposes, If a gas (parent) links to an other gas device (child) and the flow for the child device is above the cutoff value, the flow rate reported by the parent device is set to 0 irrespectively of actual/assumed flow rate',
        'title' => 'Optional title',
        'control_name' => 'Name of control valve device (relay) if any, used mainly if gas is part of a gas group',
        'control_value' => 'control valve relay status for allowing flow, used mainly if gas is part of a gas group',
        'master_device' => 'Device name for the master device in case current device is a slave device (locked to have X percent of master device flow rate)',
        'slave_flow' => 'Percentage of master device flow rate that current device is supposed to have',
        'show_plot'=>'Determines if the current device data is to be shown in the daily data plots',
        'use_cache'=>'Determines if persisten caching of read values is allowed',
	'include_tally' => 'Indicates if the flow of this gas is to be included in any taly of gas use',
    };
    $self->{'_default'} = {
	'class' => 'Multiline',
        'mode' => 'Automatic',
        'maxflow_set' => 0,
        'cutoff_report' => 0,
        'cutoff_set' => 0,
        'link' => '',
        'control_value' => 0,
	'steps' => 5,
	'sleep' => 1,
	'shift_up' => 1,
	'shift_down' => 0.8,
        'slave_flow' => 100,
        'show_plot'=>'Yes',
        'use_cache'=>'No',
	'include_tally' => 'Yes',
    };
    bless $self,$class;
    $self->{'_dev1'} = undef;
    $self->{'_dev2'} = undef;
    $self->{'_read_names'} = ['read','setpoint'];
    $self->{'_set_names'} = ['setflow','set'];
    $self->{'_values_mode'} = ['Manual','Automatic'];
    $self->{'_values_class'} = ['Normal','Multiline'];
    $self->{'_values_include_tally'} = ['Yes','No'];
    my @gaslist = ();
    foreach my $gas ($self->rig->avaliable_devices('gas'))
    {
	next if ($gas eq $self->name);
	push @gaslist,$gas;
    }
    $self->{'_section'} = 'gas_'.$self->name();
    $self->{'_values_device_1'} = ['',@gaslist];
    $self->{'_values_device_2'} = ['',@gaslist];
    $self->{'_values_control_name'} = ['',$self->rig->avaliable_devices('relay')];
    my @list = ();
    foreach my $n ($self->rig->avaliable_devices('gas'))
    {
        push @list,$n unless ($n eq $self->name);
    }
    $self->{'_values_master_device'} = ['',@list];
    $self->{'_set_fn_names'} = ['setflow','set']; # List of function names which can trigger a notify event
    $self->{'_file'} = SemaforeFile->new($userdir.'rig'.$self->rig->name.'/gas_'.$self->name,'/home/celltest/Gas_rig'.$self->rig->name.'.lock');
    unless ($self->{'_file'}->exist)
    {
        ### Create file with rw for all           ###
        ### Yes I know 666 is the number of evil! ###
        $self->{'_file'}->lock_ex;
        $self->{'_file'}->writeline('0.00');
        chmod 0666, $self->{'_file'}->filename;
        $self->{'_file'}->unlock;
    }
    $self->{'_linkdevices'} = [];
    return $self->init;
}

sub include_tally()
{
    my $self = shift;
    return 0 if ($self->{'_include_tally'} && $self->{'_include_tally'} =~ /no/i);
    return 1;
}


sub is_pressure
{
    my $self = shift;
    return 0;
}

sub DESTROY
{
    my $self = shift;
    $self->{'_file'}->DESTROY() if ($self->{'_file'});
    return undef;
}


sub readonly_value($)
{
    my $self = shift;
    my $tag = shift;
    return undef unless ($tag);
    return $self->mode() if ($tag eq 'mode');
    return $self->maxflow() if ($tag eq 'maxflow');
    return $self->cutoff_set() if ($tag eq 'cutoff_set');
    return undef;
}

sub Accept
{
    my $self = shift;
    my $visitor= shift;
    return undef if ($self->{'_seen_visitors'}{$visitor});
    $self->die("Error: Device '$self', not properly initialised: one or more of the devices in container could not be initialised!") unless ($self->{'_dev1'} && $self->{'_dev2'});
    $self->{'_dev1'}->Accept($visitor);
    $self->{'_dev2'}->Accept($visitor);
    $visitor->VisitComplex($self);
    $self->{'_seen_visitors'}{$visitor} = 1;
    return undef;
}


sub gas()
{
    my $self = shift;
    $self->die("Error: Device '$self', not properly initialised: one or more of the devices in container could not be initialised!") unless ($self->{'_dev1'} && $self->{'_dev2'});
    my $data = RFC::Cache->new();
    my $flow1 = $self->{'_dev1'}->read($data);
    if ($flow1 > $self->{'_dev1'}->cutoff_set(@_))
    {
	return $self->{'_dev1'}->gas(@_);
    }
    else
    {
	return $self->{'_dev2'}->gas(@_);
    }
}

sub read_cutoff
{
    my $self = shift;
    my $val = $self->read(@_);
    $val = 0 if ($self->cutoff_report && $val < $self->cutoff_report);
    return $val;
}

sub accuracy()
{
    my $self = shift;
    $self->die("Error: Device '$self', not properly initialised: one or more of the devices in container could not be initialised!") unless ($self->{'_dev1'} && $self->{'_dev2'});
    my $ac1 = $self->{'_dev1'}->accuracy(@_);
    my $ac2 = $self->{'_dev2'}->accuracy(@_);
    return $ac2 if ($ac1 > $ac2);
    return $ac1;
}

sub maxflow()
{
    my $self = shift;
    my $m1 = 0;
    my $m2 = 0;
    $m1 = $self->{'_dev1'}->maxflow(@_) if ($self->{'_dev1'});
    $m2 = $self->{'_dev2'}->maxflow(@_) if ($self->{'_dev2'});
    return $m1 + $m2;
}

sub setpoint()
{
    my $self = shift;
    my $m1 = 0;
    my $m2 = 0;
    $m1 = $self->{'_dev1'}->setpoint(@_) if ($self->{'_dev1'});
    $m2 = $self->{'_dev2'}->setpoint(@_) if ($self->{'_dev2'});
    return $m1 + $m2;
}

sub maxflow_set()
{
    my $self = shift;
    return $self->{'_maxflow_set'} if ($self->{'_maxflow_set'} && $self->{'_maxflow_set'} < $self->maxflow);
    return $self->maxflow(@_);
}

sub control_device()
{
    my $self = shift;
    return $self->{'_control_device'};
}

sub control_value()
{
    my $self = shift;
    return $self->{'_control_value'};
}

sub controler()
{
    my $self = shift;
    return ($self->{'_dev1'}->controler,$self->{'_dev2'}->controler);
}

sub attatch_multiplex($)
{
    my $self = shift;
    $self->die("Error: More than one gas multiplexer was attempted to be attatched to $self") if ($self->{'_multiplex'});
    $self->{'_multiplex'} = shift;
}

sub test()
{
    my $self = shift;
    my $ok = 1;
    return 0 unless ($self->{'_dev1'} && $self->{'_dev2'});
    $ok = 0 unless ($self->{'_dev1'}->test);
    $ok = 0 unless ($self->{'_dev2'}->test);
    return $ok;
}

sub test_string()
{
    my $self = shift;
    my $string = 'Gas '.$self->name.' Flow: '.$self->read(@_)."\n";
    $string .= 'Device 1: '.$self->{'_dev1'}->test_string(@_)."\n" if ($self->{'_dev1'});
    $string .= 'Device 2: '.$self->{'_dev2'}->test_string(@_)."\n" if ($self->{'_dev2'});
    $string .= $self->{'_control_device'}->test_string(@_) if ($self->{'_control_device'});
    return $string;
}


sub init()
{
    my $self = shift;
    foreach my $tag ($self->setup_tags())
    {
	next if ($tag eq 'shift_up' || $tag eq 'shift_down');
        $self->{'_'.$tag} = $self->get_default($tag);
        my $conf = $self->get_conf($tag);
        $self->{'_'.$tag} = $conf if (defined($conf) && $conf =~ /\w/);
    }
    ## Init devices in container ###
    my $d1 = $self->rig->get_device('gas',$self->{'_device_1'});
    my $d2 = $self->rig->get_device('gas',$self->{'_device_2'});
    unless ($d1)
    {
	### Implicitly initilaise device d1 ###
	$d1 = $self->rig->init_device('gas',$self->{'_device_1'});
	$d1->readstring_ignore(1) if ($d1);
    }
    unless ($d2)
    {
	### Implicitly initilaise device d2 ###
	$d2 = $self->rig->init_device('gas',$self->{'_device_2'});
	$d2->readstring_ignore(1) if ($d2);
    }
    if ($d1 && $d2)
    {
	foreach my $d ($d1,$d2)
	{
	    next unless ($d->is_pressure);
	    $self->die("Error: Gasses connected to a pressure controler can not be used in a gas conatiner device! Gas device '".$d->name."' appears to be a gas pressure device!");
	}
	### Class invariant: Device 1 has lower maxflow than device 2 ###
	if ($d1->maxflow() < $d2->maxflow())
	{
	    $self->{'_dev1'} = $d1;
	    $self->{'_dev2'} = $d2;	
	}
	else
	{
	    $self->{'_dev1'} = $d2;
	    $self->{'_dev2'} = $d1;
	} 
	$self->{'_mode'} = 'Automatic';
    }
    $self->{'_control_device'} = $self->rig->relay($self->{'_control_name'});
    $self->{'_section'} = 'gas_'.$self->name;
    my @devlist = ();
    @devlist = ($self->{'_dev1'}->controler,$self->{'_dev2'}->controler) if ($self->{'_dev1'} && $self->{'_dev2'});
    my @multlist = ();
    foreach my $d (@devlist)
    {
	next unless $d;
	my $m = $d->multiplexer;
	push @multlist,$m if ($m);
    }
    if (@multlist)
    {
	my $mname = $multlist[0]->name;
	$self->{'_multiplex'} = $multlist[0];
	foreach my $d (@multlist)
	{
	    $self->die("Error! One or more of the gas devices has different gas multiplexer asociated with it, configuration ambigious!") unless ($d->name eq $mname);
	}
    }
    $self->{'_mdev'} = undef;
    if ($self->{'_master_device'})
    {
        my $dev = $self->rig->init_device('gas',$self->{'_master_device'});
        $self->die("Could not get a device instance for master device '".$self->{'_master_device'}."'!") unless ($dev);
        $self->die("A device can not be slave to an other slave device!") if ($dev->master);
        $self->{'_mdev'} = $dev;
        $dev->attatch_observer(\$self);
        $self->{'_readonly'} = 1; ### A slave device can not  be directly controlled, only indirectly ###
    }
    $self->{'_cutoff_set'} = $self->cutoff_set();
    if (!$self->{'_dev1'} || $self->get_conf('shift_up'))
    {
        $self->{'_shift_up'} = $self->get_default('shift_up');
        my $conf = $self->get_conf('shift_up');
        $self->{'_shift_up'} = $conf if (defined($conf) && $conf =~ /\w/);
    }
    else
    {
	$self->{'_shift_up'} = $self->{'_dev1'}->maxflow();
	$self->{'_default'}{'shift_up'} = $self->{'_dev1'}->maxflow();
    }
    if (!$self->{'_dev1'} || $self->get_conf('shift_down'))
    {
        $self->{'_shift_down'} = $self->get_default('shift_down');
        my $conf = $self->get_conf('shift_down');
        $self->{'_shift_down'} = $conf if (defined($conf) && $conf =~ /\w/);
    }
    else
    {
	$self->{'_shift_down'} = $self->{'_dev1'}->maxflow() * 0.8;
    }    
    if ($self->{'_dev1'})
    {
	$self->{'_default'}{'shift_up'} = $self->{'_dev1'}->maxflow();
	$self->{'_default'}{'shift_down'} = $self->{'_dev1'}->maxflow() * 0.8;
    }
    return $self;
}

sub observe()
{
    my $self = shift;
    my $action = shift;
    if ($action && $action eq 'setflow' && $self->{'_mdev'})
    {
        my $flow = shift;
        $flow = $flow * $self->{'_slave_flow'} / 100;
        return $self->setflow($flow,@_);
    }
}

sub debug()
{
    my $self = shift;
    $self->SUPER::debug(@_);
    if (@_)
    {
        #### Pass on debug level to all objects honoring this ###
        $self->{'_file'}->debug($self->{'_debug'});
    }
    return $self->{'_debug'};
}


sub setflow($)
{
    my $self = shift;
    my $flow = shift;
    my $data = RFC::Cache->new();
    $self->die("Could not set flow for device '$self', one or more of the devices in container could not be initialised!") unless ($self->{'_dev1'} && $self->{'_dev2'});
    if ($flow > $self->maxflow_set)
    {
        $self->writedebug("Flow to be set for $self was above maximum, setting maximum flow");
	$self->proglog("Flow to be set for $self was above maximum, setting maximum flow",@_);
        $flow = $self->maxflow_set;
    }
    my $oldflow = $self->read($data);
    my $dev1_flow = $self->{'_dev1'}->read($data);
    my $dev2_flow = $self->{'_dev2'}->read($data);
    $self->writedebug("Setting flow for ".$self->name." to $flow");
    if ($flow > $self->{'_dev2'}->maxflow)
    {
	### Handle flow above maximum for high range controler ###
	if (($flow - $self->{'_dev2'}->maxflow()) > $self->{'_dev1'}->cutoff_set())
	{
	    $self->{'_dev2'}->setflow($self->{'_dev2'}->maxflow,@_);
	    $self->{'_dev1'}->setflow($flow - $self->{'_dev2'}->maxflow(),@_);
	}
	else
	{
	    ### Make sure that the low flow device's cutoff_set does not ###
	    ### result in wrong flow                                     ###
	    $self->{'_dev2'}->setflow($flow - $self->{'_dev1'}->cutoff_set(),@_);
	    $self->{'_dev1'}->setflow($self->{'_dev1'}->cutoff_set(),@_);	    
	}
	$self->{'_file'}->writeline(sprintf("%.4f",$flow));
	return $self->set_notify($flow);

    }
    if ($flow < $self->cutoff_set)
    {
	$self->writedebug("Flow to be set for $self was below cutoff (".$self->cutoff_set." L/h), setting 0 L/h");
	$self->proglog("Flow for $self was to be set to below the cutoff limit (".$self->cutoff_set." L/h), setting 0 L/hour",@_) unless ($flow == 0);
	$self->proglog("Setting flow for $self to 0 L/hour",@_);
	$self->{'_dev1'}->setflow(0,@_);
	$self->{'_dev2'}->setflow(0,@_);
	$self->{'_file'}->writeline(sprintf("%.4f",0));
	return $self->set_notify(0);
    }
    $self->{'_file'}->writeline(sprintf("%.4f",$flow));
    $self->proglog("Setting flow for $self to $flow L/hour",@_);
    ### Class invariant: Device 1 has lower maxflow than device 2 ###    
    if ($oldflow < $self->cutoff_set)
    {
	if ($flow > $self->{'_shift_up'})
	{
	    $self->{'_dev1'}->setflow(0,@_);
	    return $self->set_notify($self->{'_dev2'}->setflow($flow,@_));
	}
	else
	{
	    $self->{'_dev2'}->setflow(0,@_);
	    return $self->set_notify($self->{'_dev1'}->setflow($flow,@_));
	}
    }
    if ($oldflow <= $self->{'_shift_up'} && $flow > $self->{'_shift_up'})
    {
	if ($dev1_flow > $self->{'_dev1'}->cutoff_set)
	{
	    ### Shift flow from dev 1 to dev2 ###
	    $self->shift_dev($self->{'_dev1'},$self->{'_dev2'},$oldflow,@_);
	}
	$self->{'_dev1'}->setflow(0,@_);
	return $self->set_notify($self->{'_dev2'}->setflow($flow,@_));
    }
    if ($oldflow >= $self->{'_shift_down'} && $flow < $self->{'_shift_down'})
    {
	my $dev1max = $self->{'_dev1'}->maxflow;
	if ($dev2_flow > $dev1max)
	{
	    $self->{'_dev2'}->setflow($dev1max,@_);
	    $self->{'_dev1'}->setflow(0,@_);
	    sleep($self->{'_sleep'});
	    $oldflow = $dev1max;
	}
	if ($dev2_flow > $self->{'_dev2'}->cutoff_set)
	{
	    ### Shift flow from dev 2 to dev1 ###
	    $self->shift_dev($self->{'_dev2'},$self->{'_dev1'},$oldflow,@_);
	}
	$self->{'_dev2'}->setflow(0,@_);
	return $self->set_notify($self->{'_dev1'}->setflow($flow,@_));
    }
    if ($dev2_flow > $self->{'_dev2'}->cutoff_set)
    {
	$self->{'_dev1'}->setflow(0,@_);
	return $self->set_notify($self->{'_dev2'}->setflow($flow,@_));
    }
    else
    {
	$self->{'_dev2'}->setflow(0,@_);
	return $self->set_notify($self->{'_dev1'}->setflow($flow,@_));
    }   
}

sub set_notify($)
{
    my $self = shift;
    my $flow = shift;
    my $i = 0;
    ### Find if setflow was called from set() ###
    while(my ($package,$filename,$line,$subroutine) = caller($i++))
    {
	## NOP, only nesc3esarry to get max $i
    }
    my ($p,$fname,$line,$subroutine) = caller($i-2);
    return $flow if ($subroutine && $subroutine =~ /\:set$/);
    my @response = $self->notify('setflow',$flow,@_);
    return $flow unless (@response);
    my $str = join(', ',@response);
    return $str;
}

sub set
{
    my $self = shift;
    $self->setflow(@_);
    ### Make sure that the 'set' command is passed on (althiough the setflow command passes a setflow command on as well)
    return $self->notify('set',@_);
}

sub shift_dev($$)
{
    my $self = shift;
    my $d1 = shift;
    my $d2 = shift;
    my $flow = shift;
    my $n = $self->{'_steps'};
    for (my $x = 1; $x <= $n; $x++)
    {
	my $f1 = $flow * ( $n - $x ) / $n;
	my $f2 = $flow * $x  / $n;
	$d1->setflow($f1,@_);
	$d2->setflow($f2,@_);
	sleep($self->{'_sleep'});
    }
}


sub cutoff_set()
{
    my $self = shift;
    my $m1 = 0;
    my $m2 = 0;
    $m1 = $self->{'_dev1'}->cutoff_set if ($self->{'_dev1'});
    $m2 = $self->{'_dev2'}->cutoff_set if ($self->{'_dev2'});
    return $m1 if ($m1 < $m2);
    return $m2;
}

sub cutoff_report()
{
    my $self = shift;
    return $self->{'_cutoff_report'} if ($self->{'_cutoff_report'});
    my $m1 = 0;
    my $m2 = 0;
    $m1 = $self->{'_dev1'}->cutoff_report if ($self->{'_dev1'});
    $m2 = $self->{'_dev2'}->cutoff_report if ($self->{'_dev2'});
    return $m1 if ($m1 < $m2);
    return $m2;
}

sub bool
{
    my $self = shift;
    my $flow = $self->read(@_);
    return 0 if ($flow <= 0 || ($self->cutoff_report() && $flow < $self->cutoff_report()));
    return 1;
}

sub read_nocache
{
    my $self = shift;
    $self->die("Could not read flow for device '$self', one or more of the devices in container could not be initialised!") unless ($self->{'_dev1'} && $self->{'_dev2'});
    my $res = undef;
    my $data = undef;
    if (@_)
    {
        $data = $_[0];
    }
    else
    {
	$data = RFC::Cache->new();
	$data->debug($self->debug()) if ($self->debug);
    }
    $self->check_cache($data);
    my $flow1 = $self->{'_dev1'}->read_cutoff($data);
    my $flow2 = $self->{'_dev2'}->read_cutoff($data);
    my $gas1 = $self->{'_dev1'}->gas();
    my $gas2 = $self->{'_dev2'}->gas();
    if ($gas1 eq $gas2)
    {
	### Reset error lock ###
	$self->rig->unset_warning($self);
    }
    else
    {
	my $str = "Alert: Device 1 and 2 for multiline gas device $self does not report the same gas name! Reported names: '$gas1' and '$gas2', Gas flow possibly corrupt!";
        $self->rig->warning_mail($self,$str);
        $self->writedebug($str);
    }
    my $flow =  $flow1 + $flow2;
    if ($self->{'_link'})
    {
        $self->load_link unless (@{$self->{'_linkdevices'}});
        foreach my $dev (@{$self->{'_linkdevices'}})
        {
            my $cutoff = $dev->cutoff_set;
            my $linkflow = $dev->read($data);
            $flow = 0 if ($linkflow > $cutoff);
        }
    }
    $self->writedebug("Flow for $self was $flow");
    my $str = time .' '.$self->name.' '.$flow;
    $self->rig->kanaldata($str) unless ($self->readstring_ignore);
    my $dev = $self->{'_multiplex'};
    if ($flow > 0 && $dev && $dev->gas && $dev->gas ne $self->name)
    {
        $flow = 0;
    }
    $self->set_cache($flow);
    $self->{'_last_read'} = Time::HiRes::time;
    return $flow;
}

sub print_config()
{
    my $self = shift;
    my @arr = ();
    push @arr,'Name: '.$self->name;
    push @arr,'Type: '.$self->type;
    push @arr,'Mode: '.$self->mode;
    push @arr,'Device_1_maxflow: '.$self->{'_dev1'}->maxflow;
    push @arr,$self->{'_dev1'}->print_config;
    push @arr,'Device_2_maxflow: '.$self->{'_dev2'}->maxflow;
    push @arr,$self->{'_dev2'}->print_config;
    push @arr,$self->{'_multiplex'}->print_config if ($self->{'_multiplex'});
    push @arr,$self->{'_control_device'}->print_config if ($self->{'_control_device'});
    return join (', ',@arr);
}

sub load_link
{
    my $self = shift;
    if ($self->{'_link'})
    {
        my @list = split(/\s*\,\s*/,$self->{'_link'});
        foreach my $name (@list)
        {
            my $dev = $self->rig->get_device('gas',$name);
            unless ($dev)
            {
                $dev = RFC::Device::new_GAS($self->rig,$dev);
                $self->rig->register_gas($dev) if ($dev);
            }
            $self->die("Error: Could not get device for link gas $name!") unless ($dev);
            push @{$self->{'_linkdevices'}},$dev;
        }
    }
}


return 1;
