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);
}
......
This diff is collapsed.
......@@ -24,6 +24,7 @@ Construct Tk::Widget 'FIJISettingsViewer';
my $fr_design; # labled frame surrounding widgets representing design constant
my $fr_fius; # labled frame surrounding widgets representing design constant
my $widget_background;
sub ClassInit {
......@@ -34,6 +35,7 @@ sub ClassInit {
return $self;
}
sub Populate {
my $logger = get_logger();
my($self, $args) = @_;
......@@ -47,6 +49,7 @@ sub Populate {
${$self->{'settings'}}->{'FIUs'} = [];
}
}
# FIXME: add an option to store a CODE reference that is called when any field is invalid
$self->SUPER::Populate($args);
$self->_populate_widget($self);
$self->update();
......@@ -64,6 +67,7 @@ sub update {
# design panel #
################
# Ugly hack to retrieve the design constants widgets.
# Alternatively to below one could store the respective widgets separately.
# To limit the complexity elsewhere we jump though a few hoops here.
# 1. fetch the widgets comprising the GUI for the design constants
......@@ -74,7 +78,8 @@ sub update {
my @design_widgets = ${${$fr_design->children}[0]->children}[1]->children;
my $const_cnt = @design_widgets;
for (my $i = 3; $i < $const_cnt; $i += 3) {
my ($namew, $unitw, $valw) = @design_widgets[$i..$i+3];
# The order of the widgets depends on their construction time(!)
my ($valw, $namew, $unitw) = @design_widgets[$i..$i+3];
my $name = $namew->cget('-text');
my $k = FIJI::ini2constkey($name);
if (!defined($k)) {
......@@ -87,7 +92,8 @@ sub update {
return;
}
$logger->trace("Connect widget ($name) with new settings instance hash ($k)");
$valw->configure('-textvariable' => \${$self->{'settings'}}->{'design'}->{$k});
$valw->{'fiji_backend_ref'} = \${$self->{'settings'}}->{'design'}->{$k};
$valw->configure('-text' => ${$self->{'settings'}}->{'design'}->{$k});
}
##############
......@@ -168,16 +174,14 @@ sub _populate_widget {
'-column' => $i++,
);
}
# $fr_design->Label(
# -text => "Control",
# )->grid(
# '-row' => 0,
# '-column' => $i++,
# '-columnspan' => 2,
# );
my $designmap = DESIGNMAP;
my $entry;
foreach my $k (qw(FREQUENCY BAUDRATE TIMER_WIDTH)) {
$entry = $fr_design->Entry(
'-text' => ${$self->{'settings'}}->{'design'}->{$k},
'-width' => -1,
);
Tk::grid(
$fr_design->Label(
'-text' => DESIGNMAP->{$k}->{'ini_name'},
......@@ -185,10 +189,6 @@ sub _populate_widget {
$fr_design->Label(
'-text' => DESIGNMAP->{$k}->{'unit'},
),
$fr_design->Entry(
'-textvariable' => \${$self->{'settings'}}->{'design'}->{$k},
'-width' => -1,
),
# $fr_design->Button(
# -text => 'Defaults',
# -command => [\&_save, $self],
......@@ -198,9 +198,28 @@ sub _populate_widget {
# $btn_save->configure(-state => $state);
# },
# ),
$entry,
'-sticky' => 'ew'
);
$entry->configure(
'-validate' => 'key',
'-validatecommand' => [\&_validate_design_entry, $entry, $k],
);
$entry->bind('<Control-a>',
sub {
my $w = shift;
$w->selectionRange(0,'end');
$w->icursor('end');
},
);
# $entry->bind('<KeyRelease>',
# sub {
# my $entry_var = ${$entry->cget('-textvariable')};
# $self->_highlight_widget($entry, (FIJI::Settings::validate_design_value($k, \$entry_var)));
# }
# );
}
$widget_background = $entry->cget('-bg');
##############
# FIUs panel #
......@@ -208,6 +227,7 @@ sub _populate_widget {
$self->_add_fiu_panel($fr);
}
sub _add_fiu_panel {
my($self, $fr) = @_;
......@@ -277,23 +297,65 @@ sub _add_fiu ($$) {
# forward declarations of widgets used in callbacks
my $lfsr_button = $fr_fius->Checkbutton();
my $mask_entry = $fr_fius->Entry(
'-textvariable' => \$fiu->{'FIU_LFSR_MASK'},
'-width' => -1,
'-justify' => 'right',
);
$mask_entry->{'fiji_backend_ref'} = \$fiu->{'FIU_LFSR_MASK'};
$mask_entry->configure('-text' => sprintf("0x%x", $fiu->{'FIU_LFSR_MASK'}));
$mask_entry->configure(
'-validate' => 'key',
'-validatecommand' => [\&_validate_fiu_entry, $mask_entry, 'FIU_LFSR_MASK'],
);
$mask_entry->bind('<Control-a>',
sub {
my $w = shift;
$w->selectionRange(0,'end');
$w->icursor('end');
},
);
my $so_entry = $fr_fius->Entry(
'-textvariable' => \$fiu->{'FIU_LFSR_STUCK_OPEN_BIT'},
'-width' => -1,
'-justify' => 'center',
);
$so_entry->{'fiji_backend_ref'} = \$fiu->{'FIU_LFSR_STUCK_OPEN_BIT'};
$so_entry->configure('-text' => $fiu->{'FIU_LFSR_STUCK_OPEN_BIT'});
$so_entry->configure(
'-validate' => 'key',
'-validatecommand' => [\&_validate_fiu_entry, $so_entry, 'FIU_LFSR_STUCK_OPEN_BIT'],
);
$so_entry->bind('<Control-a>',
sub {
my $w = shift;
$w->selectionRange(0,'end');
$w->icursor('end');
},
);
# $so_entry->bind('<KeyRelease>',
# sub {
# my $entry_var = ${$so_entry->cget('-textvariable')};
# $self->_highlight_widget($so_entry, (FIJI::Settings::validate_fiu_value('FIU_LFSR_STUCK_OPEN_BIT', \$entry_var)));
# }
# );
my $lbl = $fr_fius->Label(
'-text' => "FIU$i",
);
my $net_entry = $fr_fius->Entry(
'-textvariable' => \$fiu->{'FIU_NET_NAME'},
'-width' => 25,
);
$net_entry->bind('<Control-a>',
sub {
my $w = shift;
$w->selectionRange(0,'end');
$w->icursor('end');
},
);
my $model_menu = $fr_fius->Optionmenu(
'-options' => FIU_MODEL->{'values'},
'-width' => -1,
......@@ -315,7 +377,7 @@ sub _add_fiu ($$) {
},
);
$model_menu->configure(
-command => sub {
'-command' => sub {
my $logger = get_logger();
my $model = shift;
$logger->trace("model is now: $model");
......@@ -335,6 +397,7 @@ sub _add_fiu ($$) {
'-variable' => \$fiu->{'FIU_LFSR_EN'},
'-command' => [\&_set_fields_by_button, $self, $lfsr_button, $mask_entry ],
);
Tk::grid(
$lbl,
$net_entry,
......@@ -358,6 +421,7 @@ sub _add_fiu ($$) {
);
}
sub _update_fields {
my($self,
$lbl,
......@@ -371,9 +435,6 @@ sub _update_fields {
) = @_;
my $logger = get_logger();
# update LFSR mask first
$self->_set_fields_by_button($lfsr_button, $mask_entry);
my $model = ${$model_menu->cget('-variable')};
if ($model eq 'RUNTIME' ||
$model eq 'STUCK_OPEN') {
......@@ -412,4 +473,44 @@ sub _set_fields {
}
}
sub _validate_design_entry {
return _validate_entry(DESIGNMAP, @_);
}
sub _validate_fiu_entry {
return _validate_entry(FIUMAP, @_);
}
sub _validate_entry {
my ($map, $widget, $name, $new, $diff, $old, $char_idx, $type) = @_;
my $new_bak = $new;
my $ok = FIJI::Settings::validate_value($map, $name, \$new);
_highlight_widget($widget, (!$ok));
if ($ok) {
${$widget->{'fiji_backend_ref'}} = $new;
$widget->configure('-validate' => 'key');
}
return 1; # always allow the new value and show the user what happened.
}
sub _highlight_widget ($$) {
my($widget, $enable) = @_;
if ($enable) {
$widget->configure('-bg' => 'orange red');
} else {
# the 3rd element returned for '-bg' is the default background, usually.
# Apparently it is something darker on Linux so the following does
# not work as intended. :(
# $widget->configure('-bg' => ($widget->configure('-bg'))[3]);
# Work around: store the entry background color at creation time and
# use that instead.
$widget->configure('-bg' => $widget_background);
}
}
1;
......@@ -3,6 +3,7 @@ FIU_NUM=8
TIMER_WIDTH=32
ID=0x0123
BAUDRATE=115200
FREQUENCY=50e6
[FIU0]
NET_NAME=siegfried
......@@ -14,27 +15,48 @@ LFSR_MASK=0x0000
[FIU1]
NET_NAME=bla1
FAULT_MODEL=PASS_THRU
ENABLED_BY_LFSR=0
LFSR_BIT_FOR_STUCK_OPEN=0
LFSR_MASK=0x0
[FIU2]
NET_NAME=bla2
FAULT_MODEL=STUCK_OPEN
ENABLED_BY_LFSR=0
LFSR_BIT_FOR_STUCK_OPEN=0
LFSR_MASK=0x0
[FIU3]
NET_NAME=bla3
FAULT_MODEL=SEU
ENABLED_BY_LFSR=0
LFSR_BIT_FOR_STUCK_OPEN=0
LFSR_MASK=0x0
[FIU4]
NET_NAME=bla4
FAULT_MODEL=STUCK_AT_1
ENABLED_BY_LFSR=0
LFSR_BIT_FOR_STUCK_OPEN=0
LFSR_MASK=0x0
[FIU5]
NET_NAME=bla5
FAULT_MODEL=STUCK_AT_0
ENABLED_BY_LFSR=0
LFSR_BIT_FOR_STUCK_OPEN=0
LFSR_MASK=0x0
[FIU6]
NET_NAME=bla6
FAULT_MODEL=DELAY
ENABLED_BY_LFSR=0
LFSR_BIT_FOR_STUCK_OPEN=0
LFSR_MASK=0x0
[FIU7]
NET_NAME=bla7
# FAULT_MODEL=FAIL
FAULT_MODEL=RUNTIME
ENABLED_BY_LFSR=0
LFSR_BIT_FOR_STUCK_OPEN=0
LFSR_MASK=0x0
......@@ -39,7 +39,7 @@ sub main {
return 1;
}
my $fiji_settings = FIJI::Settings::read_settingsfile($cfg{"cli.fiji_cfg"});
my $fiji_settings = FIJI::Settings->new('download', $cfg{"cli.fiji_cfg"});
return 1 if !defined($fiji_settings);
my $fiji_consts = $fiji_settings->{'design'};
# use Data::Dumper;
......@@ -70,7 +70,7 @@ sub main {
}
# default arm duration to maximum/2
my $default_arm_dur = oct("0x" . ("FF" x ($fiji_consts->{'ARM_DURATION_WIDTH'}/8))) / 2;
my $default_arm_dur = oct("0x" . ("FF" x ($fiji_consts->{'TIMER_WIDTH'}/8))) / 2;
printf("Enter the duration of the ARM timer (default: 0x%x): ", $default_arm_dur);
my $arm_duration = <STDIN>;
last unless defined $arm_duration;
......@@ -79,7 +79,7 @@ sub main {
$logger->debug("arm duration is $arm_duration.");
# default arm duration to maximum/2
my $default_inj_dur = oct("0x" . ("FF" x ($fiji_consts->{'INJECT_DURATION_WIDTH'}/8))) / 2;
my $default_inj_dur = oct("0x" . ("FF" x ($fiji_consts->{'TIMER_WIDTH'}/8))) / 2;
printf("Enter the duration of the INJECT timer (default: 0x%x): ", $default_inj_dur);
my $inject_duration = <STDIN>;
last unless defined $inject_duration;
......
......@@ -109,7 +109,7 @@ sub _ctrl_frame {
$logger->debug("User aborted open action");
return;
}
my $tmp_settings = FIJI::Settings->new($filename, $self->{'settings'});
my $tmp_settings = FIJI::Settings->new('setup', $filename, $self->{'settings'});
if (!defined($tmp_settings)) {
my $msg = "Settings file $filename could not be loaded correctly";
$logger->error($msg);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment