Commit 65415550 authored by Stefan Tauner's avatar Stefan Tauner
Browse files

fiji_scripts: settings revamp

 - get rid of separate ARM and INJECT DURATION widths
 - allow for different external and internal representation of values
 - highlight invalid user entries
 - validation of settings depends on tool flow phase (e.g. setup)
parent 84a8f49e
......@@ -13,58 +13,54 @@ use warnings;
# Fields:
# - ini_name = key name in FIJI Settings file
# - unit = (optional) physical unit
# - not_supplied = (optional) not to be set by the user (but generated e.g. by fiji_instrument)
# - type = (optional) enables type-specific conversions and tests:
# numeric: values must be oct, hex, binary strings looking like a real number.
# natural: values must be oct, hex, binary strings looking like a real number.
# hexadecimal: values must be hexadecimal numbers.
# boolean: will be convert to a truth value by Perl semantics
# values = (optional) an array reference listing all valid values (emulates an enum)
# default = (optional) default value if not given in file and not determinable otherwise
# - values = (optional) an array reference listing all valid values (emulates an enum)
# - phases_opt = (optional) list of phases (subset of "setup", "instrument", "download")
# where no value must be present in input (e.g. ID is only necessary while downloading).
# - default = (optional) default value if not given in file and not determinable otherwise
my %designmap;
BEGIN {
%designmap = (
ID => {
ini_name => "ID",
type => 'numeric',
not_supplied => 1,
type => 'hexadecimal',
phases_opt => [qw(setup instrument)], # generated in instrumentation
},
FIU_NUM => {
ini_name => "FIU_NUM",
type => 'numeric',
not_supplied => 1, # auto-generated
type => 'natural',
phases_opt => [qw(setup instrument download)], # auto-generated if need be
},
BAUDRATE => {
ini_name => "BAUDRATE",
default => 115200,
type => 'numeric',
type => 'natural',
unit => 'bps',
},
FREQUENCY => {
ini_name => "FREQUENCY",
default => 50e8,
type => 'numeric',
type => 'natural',
unit => 'Hz',
},
FIU_CFG_BITS => {
ini_name => "FIU_CFG_BITS",
default => 3,
type => 'numeric',
not_supplied => 1, # currently not user-configurable
type => 'natural',
phases_opt => [qw(setup instrument download)], # currently not user-configurable at all
},
TIMER_WIDTH => {
ini_name => "TIMER_WIDTH",
default => 32,
type => 'numeric',
type => 'natural',
unit => 'bits',
},
ARM_DURATION_WIDTH => {
ini_name => "ARM_DUR_WIDTH",
type => 'numeric',
not_supplied => 1, # derived from TIMER_WIDTH if need be
},
INJECT_DURATION_WIDTH => {
ini_name => "INJECT_DUR_WIDTH",
type => 'numeric',
not_supplied => 1, # derived from TIMER_WIDTH if need be
values => sub {
my $val = shift;
return $val % 8 == 0 && $val > 0 && $val <= 64;
}
},
);
}
......@@ -77,26 +73,31 @@ BEGIN {
%fiumap = (
FIU_NET_NAME => {
ini_name => "NET_NAME",
phases_opt => [qw(setup)], # defaults to undef
},
FIU_MODEL => {
ini_name => "FAULT_MODEL",
default => "RUNTIME",
values => [qw(RUNTIME PASS_THRU STUCK_AT_0 STUCK_AT_1 STUCK_OPEN DELAY SEU)],
phases_opt => [qw(setup)],
},
FIU_LFSR_EN => {
ini_name => "ENABLED_BY_LFSR",
default => 0,
type => 'boolean',
phases_opt => [qw(setup)],
},
FIU_LFSR_MASK => {
ini_name => "LFSR_MASK",
default => 0,
type => 'numeric',
type => 'hexadecimal',
phases_opt => [qw(setup)],
},
FIU_LFSR_STUCK_OPEN_BIT => {
ini_name => "LFSR_BIT_FOR_STUCK_OPEN",
default => 0,
type => 'numeric',
type => 'natural',
phases_opt => [qw(setup)],
},
);
}
......
......@@ -122,7 +122,7 @@ sub reset_comm {
push(@bytes, 0x00);
# Everything else
for (my $i = 0; $i < $consts_ref->{'ARM_DURATION_WIDTH'} / 8 + $consts_ref->{'INJECT_DURATION_WIDTH'} / 8 + 2; $i++) {
for (my $i = 0; $i < 2 * $consts_ref->{'TIMER_WIDTH'} / 8 + 2; $i++) {
push(@bytes, 0x00);
}
if (_send_bitstream($port, \pack('C*', @bytes), 1000) != scalar(@bytes)) {
......@@ -150,7 +150,7 @@ sub reset_comm {
# - payload: a byte array representing the FIU configuration
# - arm_duration and inject_duration (optional):
# initialization values for the arm and injection duration counters (minus one, actually).
# - consts: a reference to a hash representing FIJI constants (see \ref FIJI::Settings::_sanitize_consts).
# - consts: a reference to a hash representing FIJI constants (see \ref FIJI::Settings::_sanitize_design).
# The following values are optional booleans and hence not checked:
# - reset
# - trigger
......@@ -204,10 +204,9 @@ sub sanitize_config {
$logger->error(sprintf("Configuration value \"%s\" is negative (%d).", $k, $config_ref->{$k}));
return 1;
}
my $width_name = uc($k)."_WIDTH"; # availablity must have been checked with FIJI::Settings::_sanitize_consts already
my $max_val = 2 ** $consts_ref->{$width_name} - 1;
my $max_val = 2 ** $consts_ref->{'TIMER_WIDTH'} - 1;
if ($config_ref->{$k} > $max_val) {
$logger->error(sprintf("Configuration value \"%s\" is too big (%d) for %d bits.", $k, $config_ref->{$k}, $consts_ref->{$width_name}));
$logger->error(sprintf("Configuration value \"%s\" is too big (%d) for %d bits.", $k, $config_ref->{$k}, $consts_ref->{'TIMER_WIDTH'}));
return 1;
}
}
......@@ -256,7 +255,7 @@ sub send_config {
$arm_duration_en = 1;
}
my @arm_duration_arr;
for (my $i = 0; $i < $consts_ref->{'ARM_DURATION_WIDTH'} / 8; $i++) {
for (my $i = 0; $i < $consts_ref->{'TIMER_WIDTH'} / 8; $i++) {
push(@arm_duration_arr, ($arm_duration >> ($i * 8)) & 0xFF);
}
......@@ -267,7 +266,7 @@ sub send_config {
$inject_duration_en = 1;
}
my @inject_duration_arr;
for (my $i = 0; $i < $consts_ref->{'INJECT_DURATION_WIDTH'} / 8; $i++) {
for (my $i = 0; $i < $consts_ref->{'TIMER_WIDTH'} / 8; $i++) {
push(@inject_duration_arr, ($inject_duration >> ($i * 8)) & 0xFF);
}
......
......@@ -15,36 +15,64 @@ use Config::Simple;
use FIJI qw(:all);
## @function new ($phase, $fiji_ini_file, $existing_settings)
# Create a new settings instance.
#
# \param $phase Tool flow phase the settings need to be compatible with.
# \param $fiji_ini_file (optional) Path to the configuration file to read.
# \param $existing_settings (optional) An instance to reuse and return
# after overwriting existing values with defaults and any values
# read from file. Existing values will not be validated.
# Superfluous elements not present in the existing hash will be
# removed, e.g. FIUs.
sub new ($;$$) {
my $logger = get_logger();
my ($class, $fiji_ini_file, $existing_settings) = @_;
my ($class, $phase, $fiji_ini_file, $existing_settings) = @_;
my $fiji_settings_ref;
# if there are no existing settings yet, create some with default values
if (!defined($existing_settings)) {
$fiji_settings_ref = {};
$fiji_settings_ref->{'design'} = {};
_set_defaults(DESIGNMAP, $fiji_settings_ref->{'design'}, $phase);
$fiji_settings_ref = bless($fiji_settings_ref, $class);
if (!ref($fiji_settings_ref) || !UNIVERSAL::can($fiji_settings_ref,'can')) {
$logger->error("Could not bless FIJI::Settings class from \"$fiji_ini_file\".");
return undef;
}
} else {
$fiji_settings_ref = $existing_settings;
}
my $settings_ref;
if (defined($fiji_ini_file)) {
$settings_ref = read_settingsfile($fiji_ini_file, $existing_settings);
if (!defined($settings_ref)) {
$fiji_settings_ref = read_settingsfile($phase, $fiji_ini_file, $fiji_settings_ref);
if (!defined($fiji_settings_ref)) {
return undef;
}
if (defined($existing_settings)) {
return $existing_settings;
}
} else {
# Without any config file as input, simply create an empty settings
# hash with default design constants.
my $consts_ref = {};
my $ret = _set_defaults(DESIGNMAP, $consts_ref);
if (!defined($ret)) {
$logger->error("Could not set defaults for design constants.");
return undef;
}
$settings_ref = { 'design' => $consts_ref };
$fiji_settings_ref->{'FIUs'} = ();
}
my $r = bless($settings_ref, $class);
if (!ref($r) || !UNIVERSAL::can($r,'can')) {
$logger->error("Could not bless FIJI::Settings class from \"$fiji_ini_file\".");
return undef;
return $fiji_settings_ref;
}
sub _export_value {
my $logger = get_logger();
my ($map_ref, $k, $v_ref) = @_;
if (defined($map_ref->{$k}->{'type'})) {
my $orig = ${$v_ref};
if ($map_ref->{$k}->{'type'} eq 'hexadecimal') {
${$v_ref} = sprintf("0x%x", $orig);
# } elsif ($map_ref->{$k}->{'type'} eq 'natural') {
# } elsif ($map_ref->{$k}->{'type'} eq 'boolean') {
$logger->trace("Converted value of $k (\"$orig\") to \"${$v_ref}\".") if ($orig ne ${$v_ref});
}
# } elsif (defined($map_ref->{$k}->{'values'})) {
}
return $r;
}
## @method save ($fiji_ini_file)
......@@ -53,7 +81,7 @@ sub new ($;$$) {
# @ATTENTION Will happily overwrite existing files!
#
# \param fiji_ini_file The file name to write the FIJI Settings to.
sub save ($$) {
sub save ($) {
my $logger = get_logger();
my ($self, $fiji_ini_file) = @_;
return "No file name given" if !defined($fiji_ini_file);
......@@ -74,8 +102,13 @@ sub save ($$) {
if ($key eq "FIUs") {
foreach my $fiu (@{$val}) {
my $ini_fiu;
foreach my $k (keys $fiu) {
$ini_fiu->{FIUMAP->{$k}->{'ini_name'}} = $fiu->{$k};
_export_value(FIUMAP, $k, \$$fiu{$k});
# Copy value to new hash with external naming.
my $ini_name = FIUMAP->{$k}->{'ini_name'};
$ini_fiu->{$ini_name} = $fiu->{$k};
$logger->trace(sprintf("Renaming setting %s -> %s (=%s).", $k, $ini_name, defined($ini_fiu->{$ini_name}) ? $ini_fiu->{$ini_name} : "undef"));
}
$fiji_ini->set_block("FIU" . $fiu_cnt++, $ini_fiu);
}
......@@ -88,6 +121,9 @@ sub save ($$) {
return $err;
}
$design_ref->{'FIU_NUM'} = $fiu_cnt;
foreach my $key (keys $design_ref) {
_export_value(DESIGNMAP, $key, \$$design_ref{$key});
}
$fiji_ini->set_block("CONSTS", $design_ref);
if (!defined($fiji_ini->write($fiji_ini_file))) {
......@@ -102,9 +138,11 @@ sub save ($$) {
## @function read_settingsfile ($fiji_ini_file)
# @brief Load the FIJI Settings file containing design and FIU constants.
#
# \param $phase Tool flow phase the settings stored in the given file
# need to be compatible with.
# \param fiji_ini_file The name of an .ini file with FIJI Settings:
# - a 'consts' block containing the constants specified by
# \ref _sanitize_consts.
# \ref _sanitize_design.
# - at least one FIU block named "FIU<number>" where "<number>"
# is a strictly increasing integer starting with 0 containing
# the constants for the respective FIU, see \ref _sanitize_fiu
......@@ -112,7 +150,7 @@ sub save ($$) {
# \returns a reference to the hash containing the read constants.
sub read_settingsfile {
my $logger = get_logger();
my ($fiji_ini_file, $existing_settings) = @_;
my ($phase, $fiji_ini_file, $existing_settings) = @_;
my $fiji_ini;
eval { $fiji_ini = new Config::Simple($fiji_ini_file) }; # pesky library tries to die on syntax errors
if (!defined($fiji_ini)) {
......@@ -120,27 +158,45 @@ sub read_settingsfile {
return undef;
}
my $fiji_consts = $fiji_ini->get_block("CONSTS");
if (!(%$fiji_consts)) {
my $fiji_design_cfg = $fiji_ini->get_block("CONSTS");
if (!(%$fiji_design_cfg)) {
$logger->error("Could not fetch CONSTS block from config file \"$fiji_ini_file\"");
return undef;
}
$fiji_consts = _sanitize_consts($fiji_consts);
if (!defined($fiji_consts)) {
$logger->error("Design constants in FIJI Settings invalid");
my $fiji_design = _rename_import(DESIGNMAP, $fiji_design_cfg);
if (!defined($fiji_design)) {
$logger->error("Design constants do not match the FIJI Settings naming scheme.");
return undef;
}
my $fiji_settings_ref;
if (defined($existing_settings)) {
$fiji_settings_ref = $existing_settings;
if (!blessed($fiji_settings_ref) || !$fiji_settings_ref->isa("FIJI::Settings")) {
if (!blessed($existing_settings) || !$existing_settings->isa("FIJI::Settings")) {
$logger->error("Given settings are not of type FIJI::Settings.");
return undef;
}
$fiji_settings_ref->{'design'} = {};
# overwrite existing Design Constants
foreach my $k (keys($fiji_design)) {
$existing_settings->{'design'}->{$k} = $fiji_design->{$k};
}
$fiji_design = $existing_settings->{'design'};
if (defined($existing_settings->{'FIUs'})) {
$fiji_settings_ref->{'FIUs'} = $existing_settings->{'FIUs'};
} else {
$fiji_settings_ref->{'FIUs'} = ();
}
} else {
$fiji_settings_ref->{'FIUs'} = ();
}
$fiji_settings_ref->{'design'} = $fiji_consts;
# sanitize and validate read design constants
$fiji_design = _sanitize_design($fiji_design, $phase);
if (!defined($fiji_design)) {
$logger->error("Design constants in FIJI Settings invalid");
return undef;
}
$fiji_settings_ref->{'design'} = $fiji_design;
my $fiu_num = 0;
while (1) {
......@@ -149,12 +205,35 @@ sub read_settingsfile {
if (!(%$fiji_fiu_cfg)) {
last;
}
my $fiji_fiu = _sanitize_fiu($fiji_fiu_cfg);
my $fiji_fiu = _rename_import(FIUMAP, $fiji_fiu_cfg);
if (!defined($fiji_design)) {
$logger->error("FIU constants of $fiu_name do not match the FIJI Settings naming scheme.");
return undef;
}
my $tmp_fiu = {};
_set_defaults(FIUMAP, $tmp_fiu, $phase);
if (defined($existing_settings)) {
my $ex_fiu = @{$existing_settings->{'FIUs'}}[$fiu_num];
if (defined($ex_fiu)) {
# overwrite default entries
foreach my $k (keys($ex_fiu)) {
$tmp_fiu->{$k} = $ex_fiu->{$k};
}
}
# overwrite existing FIU entries
# $logger->trace("Overwriting values of $fiu_name.") if (defined($ex_fiu) && scalar(keys($ex_fiu)) > 0);
foreach my $k (keys($fiji_fiu)) {
$tmp_fiu->{$k} = $fiji_fiu->{$k};
}
$fiji_fiu = $tmp_fiu;
}
$fiji_fiu = _sanitize_fiu($fiji_fiu, $phase);
if (!defined($fiji_fiu)) {
$logger->error("Constants for $fiu_name in FIJI Settings are invalid");
return undef;
}
push(@{$fiji_settings_ref->{'FIUs'}}, $fiji_fiu);
@{$fiji_settings_ref->{'FIUs'}}[$fiu_num] = $fiji_fiu;
$fiu_num++;
$logger->trace("Read in $fiu_name from FIJI Settings file successfully.");
}
......@@ -166,114 +245,166 @@ sub read_settingsfile {
# FIU_NUM is optional in the Settings file... if it was set check that
# it corresponds to the number of FIU<number> blocks.
if (defined($fiji_consts->{'FIU_NUM'}) && $fiji_consts->{'FIU_NUM'} != $fiu_num) {
if (defined($fiji_design->{'FIU_NUM'}) && $fiji_design->{'FIU_NUM'} != $fiu_num) {
$logger->error(FIU_NUM->{'ini_name'} . " does not match the numbers of FIU blocks found.");
return undef;
} else {
$fiji_consts->{'FIU_NUM'} = $fiu_num; # assume the best if FIU_NUM constant is not given
$fiji_design->{'FIU_NUM'} = $fiu_num; # assume the best if FIU_NUM constant is not given
}
splice(@{$fiji_settings_ref->{'FIUs'}}, $fiu_num);
$logger->info("Successfully read in design constants and $fiu_num FIU definitions from FIJI Settings file.");
return $fiji_settings_ref;
}
## @function set_fiu_defaults (%$fiu_ref)
## @method set_fiu_defaults (%$fiu_ref)
# @brief Overwrite existing fields (if defined) with defaults defined in FIJI.pm.
#
# FIXME: almost 1:1 copy from _set_defaults
sub set_fiu_defaults ($) {
my $logger = get_logger();
my ($self, $consts_ref) = @_;
my $map_ref = FIUMAP;
return _set_defaults(FIUMAP, $consts_ref);
}
## @function _set_defaults (%$map_ref, %$consts_ref)
# @brief Set defaults according to FIJI.pm.
sub _set_defaults {
my $logger = get_logger();
my ($map_ref, $consts_ref, $phase) = @_;
foreach my $k (keys($map_ref)) {
my $ini_name = $map_ref->{$k}->{'ini_name'};
if (exists($map_ref->{$k}->{'default'})) {
$consts_ref->{$k} = $map_ref->{$k}->{default};
# If the default key is there but its value is undef then
# the value will be set somewhere else later (used for e.g. FIU_NUM)
if (!defined($consts_ref->{$k})) {
next;
# Set default only if it is not mandatory in the given phase.
if (!defined($phase) || scalar(grep {$_ eq $phase} @{$map_ref->{$k}->{'phases_opt'}}) > 0) {
$consts_ref->{$k} = $map_ref->{$k}->{default};
$logger->trace(sprintf("Adding default constant: %s (%s) = %s.", $k, $map_ref->{$k}->{'ini_name'}, $map_ref->{$k}->{default}));
}
$logger->trace(sprintf("Adding default constant: %s (%s) = %s.", $k, $ini_name, $map_ref->{$k}->{default}));
} elsif ($map_ref->{$k}->{'not_supplied'}) {
$consts_ref->{$k} = undef;
}
}
}
## @function _set_defaults (%$map_ref, %$consts_ref)
# @brief Set defaults according to FIJI.pm.
#
# The functions compares the given constants to the defaults and rules
# in FIJI.pm.
sub _set_defaults {
my $logger = get_logger();
my ($map_ref, $consts_ref) = @_;
# my $new_hash = {};
# Iterating over respective hash from FIJI.pm and set defaults if need be
foreach my $k (keys($map_ref)) {
my $ini_name = $map_ref->{$k}->{'ini_name'};
if (exists($consts_ref->{$ini_name})) {
if ($ini_name ne $k) {
$consts_ref->{$k} = $consts_ref->{$ini_name};
$logger->trace(sprintf("Copying setting %s (%s) = %s.", $k, $ini_name, defined($consts_ref->{$ini_name}) ? $consts_ref->{$ini_name} : "undef"));
delete $consts_ref->{$ini_name};
sub validate_design_value {
my ($k, $v_ref) = @_;
return validate_value(DESIGNMAP, $k, $v_ref);
}
sub validate_fiu_value {
my ($k, $v_ref) = @_;
return validate_value(FIUMAP, $k, $v_ref);
}
# Do validation (and conversation from external->internal representation)
sub validate_value ($$$;$) {
my $logger = get_logger();
my ($map_ref, $k, $v_ref, $log_func) = @_;
$log_func = \&Log::Log4perl::Logger::trace if !defined($log_func);
if (defined($map_ref->{$k}->{'type'})) {
my $orig = ${$v_ref};
if ($map_ref->{$k}->{'type'} eq 'hexadecimal') {
if ($orig !~ /^(0|(0[xX][[:xdigit:]]+))$/) {
$log_func->($logger, "$k: $orig does not look like a natural hexadecimal number.");
return 0;
}
} else {
if (exists($map_ref->{$k}->{'default'})) {
$consts_ref->{$k} = $map_ref->{$k}->{default};
# If the default key is there but its value is undef then
# the value will be set somewhere else later (used for e.g. FIU_NUM)
if (!defined($consts_ref->{$k})) {
next;
}
$logger->trace(sprintf("Adding default constant: %s (%s) = %s.", $k, $ini_name, $map_ref->{$k}->{default}));
} elsif ($map_ref->{$k}->{'not_supplied'}) {
next;
} else {
$logger->error(sprintf("%s is missing from FIJI Settings.", $ini_name));
return undef;
${$v_ref} = hex($orig);
# Check for natural value range. Should never trigger due to the regex above.
if (${$v_ref} < 0) {
$log_func->($logger, "$k: $orig is negative.");
return 0;
}
} elsif ($map_ref->{$k}->{'type'} eq 'natural') {
# Match hexadecimal, binary, octal and decimal numbers (the latter also in scientic notation)
if ($orig !~ /^(0|(0(x[0-9a-fA-F]+|[0-7]+))|(0b[01]+)|([1-9][0-9]*(e(-[0-9])?[0-9]+)?))$/) {
$log_func->($logger, "$k: $orig does not look like a number.");
return 0;
}
# convert non-decimal (hexadecimal, binary, octal) values to decimal
${$v_ref} = oct($orig) if $orig =~ /^0/;
if (!looks_like_number(${$v_ref})) {
$log_func->($logger, "$k: $orig does not look like a number.");
return 0;
}
# Check for natural value range. Should never trigger due to the regex above.
if (${$v_ref} < 0) {
$log_func->($logger, "$k: $orig is negative.");
return 0;
}
} elsif ($map_ref->{$k}->{'type'} eq 'boolean') {
# convert strings to binary if need be
if (!defined($orig)) {
$log_func->($logger, "$k: \"undef\" is not a boolean value.");
return 0;
} elsif (lc($orig) eq 'true') {
$orig = 1;
} elsif (lc($orig) eq 'false') {
$orig = 0;
}
if (($orig ne '0') && ($orig ne '1')) {
$log_func->($logger, "$k: \"$orig\" does not look like a boolean value.");
return 0;
}
# ensure proper boolean value, i.e. 0 or 1
${$v_ref} = (!!$orig) ? 1 : 0;
}
$logger->trace("Converted value of $k (\"$orig\") to \"${$v_ref}\".") if ($orig ne ${$v_ref});
}
if (defined($map_ref->{$k}->{'type'})) {
my $orig = $consts_ref->{$k};
if ($map_ref->{$k}->{'type'} eq 'numeric') {
# convert non-decimal (hexadecimal, binary, octal) values to decimal
$consts_ref->{$k} = oct($orig) if $orig =~ /^0/;
if (!looks_like_number($consts_ref->{$k})) {
$logger->error("$orig does not look like a number.");
return undef;
}
} elsif ($map_ref->{$k}->{'type'} eq 'boolean') {
# convert strings to binary if need be
if (!defined($orig)) {
$logger->error("\"undef\" is not a boolean value.");
return undef;
} elsif (lc($orig) eq 'true') {
$orig = 1;
} elsif (lc($orig) eq 'false') {
$orig = 0;
}
if (($orig ne '0') && ($orig ne '1')) {
$logger->error("\"$orig\" does not look like a boolean value.");
return undef;
}
# ensure proper boolean value, i.e. 0 or 1
$consts_ref->{$k} = (!!$orig) ? 1 : 0;
if (defined($map_ref->{$k}->{'values'})) {
my $values_ref = $map_ref->{$k}->{'values'};
if (ref($values_ref) eq 'ARRAY') {
# Look for given value in allowed values
if (scalar(grep {$_ eq ${$v_ref}} @{$values_ref}) == 0) {
$log_func->($logger, "$k: ${$v_ref} is not allowed. Allowed values are: " . join(", ", @{$map_ref->{$k}->{'values'}}));
return 0;
}
$logger->trace("Converted value of $k (\"$orig\") to \"$consts_ref->{$k}\".") if ($orig ne $consts_ref->{$k});
} elsif (defined($map_ref->{$k}->{'values'})) {
if (!grep {$_ eq $consts_ref->{$k}} @{$map_ref->{$k}->{'values'}}) {
$logger->error("$consts_ref->{$k} is not allowed. Allowed values are: " . join(", ", @{$map_ref->{$k}->{'values'}}));
return undef;
} elsif (ref($values_ref) eq 'CODE') {
if (!$values_ref->(${$v_ref})) {
$log_func->($logger, "$k: ${$v_ref} is not allowed.");
return 0;
}
}
}
return 1;
}
# @function _rename_import (%$map_ref, %$consts_ref)
# Rename and convert entries in consts_ref according to map_ref.
#
# This function takes a hash of FIJI Settings and converts its contents
# to the respective internal representation. This allows to use different
# names and value representations in the external file than within the
# implementation.
#
# \returns $consts_ref, or undef on errors
sub _rename_import {
my $logger = get_logger();
my ($map_ref, $consts_ref) = @_;
if (ref($consts_ref) ne 'HASH') {
$logger->error("Parameter is not a reference to a hash (containing design constants).");
return undef;
}
# Iterating over respective hash from FIJI.pm and rename the entries
# to match our internal naming scheme.
foreach my $k (keys($map_ref)) {
my $ini_name = $map_ref->{$k}->{'ini_name'};
if (exists($consts_ref->{$ini_name}) && $ini_name ne $k) {
$consts_ref->{$k} = $consts_ref->{$ini_name};