Settings.pm 9.4 KB
Newer Older
1
2
3
4
## @file [Settings.pm]

## @class [FIJI::Settings]
#
5
# Contains helper functions to deal with FIJI Settings files.
6
7
8
9
10
11
package FIJI::Settings;

use Log::Log4perl qw(get_logger);
use Scalar::Util "looks_like_number";
use Config::Simple;

12
13
use FIJI qw(:all);

14
15
## @function read_configfile ($fiji_ini_file)
# @brief Load the FIJI Settings file containing design and FIU constants.
16
#
17
18
19
20
21
22
# \param fiji_ini_file The name of an .ini file with FIJI Settings:
#         - a 'consts' block containing the constants specified by
#           \ref _sanitize_consts.
#         - 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
23
24
25
26
#
# \returns a reference to the hash containing the read constants.
sub read_configfile {
  my $logger = get_logger();
27
28
29
30
31
  my ($fiji_ini_file) = @_;
  my $fiji_ini;
  eval { $fiji_ini = new Config::Simple($fiji_ini_file) }; # pesky library tries to die on syntax errors
  if (!defined($fiji_ini)) {
    $logger->fatal("Could not read config file \"$fiji_ini_file\": " . (defined($@) ? $@ : Config::Simple->error()));
32
33
34
    return undef;
  }

35
  my $fiji_consts = $fiji_ini->get_block("CONSTS");
36
  if (!(%$fiji_consts)) {
37
    $logger->fatal("Could not fetch CONSTS block from config file \"$fiji_ini_file\"");
38
39
    return undef;
  }
40
41
  $fiji_consts = _sanitize_consts($fiji_consts);
  if (!defined($fiji_consts)) {
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
    $logger->fatal("Design constants in FIJI Settings invalid");
    return undef;
  }

  my $fiu_num = 0;
  while (1) {
    my $fiu_name = "FIU" . $fiu_num;
    my $fiji_fiu_cfg = $fiji_ini->get_block($fiu_name);
    if (!(%$fiji_fiu_cfg)) {
      last;
    }
    my $fiji_fiu = _sanitize_fiu($fiji_fiu_cfg);
    if (!defined($fiji_fiu)) {
      $logger->fatal("Constants for $fiu_name in FIJI Settings are invalid");
      return undef;
    }
    push(@{$fiji_consts->{'FIUs'}}, $fiji_fiu);
    $fiu_num++;
    $logger->trace("Read in $fiu_name from FIJI Settings file successfully.");
  }

  if ($fiu_num == 0) {
    $logger->fatal("Could not fetch any FIU block from config file \"$fiji_ini_file\"");
    return undef;
66
  }
67
68
69
70
71
72
73
74
75
76
77

  # 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) {
      $logger->fatal(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
  }

  $logger->info("Successfully read in design constants and $fiu_num FIU definitions from FIJI Settings file.");
78
79
80
81
  return $fiji_consts;
}


82
83
84
85
sub _bla {
}

## @function _sanitize_fiu (%$fiu_ref)
86
87
# @brief Convert and sanity check FIJI Settings.
#
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# \param fiu_ref a reference to a hash containing FIJI Settings for a
#                single FIU.
#
# \returns A new hash with all constants required in the FIU settings
#          in sanitized form, or undef on errors.
sub _sanitize_fiu {
  my $logger = get_logger();
  my ($fiu_ref) = @_;
  if (ref($fiu_ref) ne 'HASH') {
    $logger->error("Parameter is not a reference to a hash (containing FIU constants).");
    return undef;
  }

  my $new_hash = {};
  # Iterate over FIUMAP hash from FIJI.pm and set defaults if need be
  # FIXME: part of the loop almost identical to _sanitize_consts below
  foreach my $k (keys(FIUMAP)) {
    my $ini_name = FIUMAP->{$k}->{'ini_name'};
    if (exists($fiu_ref->{$ini_name})) {
      $new_hash->{$k} = $fiu_ref->{$ini_name};
      $logger->trace(sprintf("Copying setting %s (%s) = %s.", $k, $ini_name, $fiu_ref->{$ini_name}));
    } else {
      if (exists(FIUMAP->{$k}->{default})) {
        $new_hash->{$k} = FIUMAP->{$k}->{default};
        $logger->trace(sprintf("Adding default constant: %s (%s) = %s.", $k, $ini_name, FIUMAP->{$k}->{default}));
      } else {
        $logger->error(sprintf("%s is missing from FIJI constants.", $ini_name));
        return undef;
      }
    }

    # convert non-decimal (hexadecimal, binary, octal) values to decimal
    # my $orig = $new_hash->{$k};
    # $new_hash->{$k} = oct($orig) if $orig =~ /^0/;
    # $logger->trace("Converted value of $k (\"$orig\") to \"$new_hash->{$k}\".") if ($orig ne $new_hash->{$k});
    # if (!looks_like_number($new_hash->{$k})) {
      # $logger->error("$orig does not look like a number.");
      # return undef;
    # }
  }

  # check for sane values
  # if (($new_hash->{FIU_CFG_BITS} <= 0)) {
      # $logger->error("FIU_CFG_BITS is <= 0.");
      # return undef;
  # }

  return $fiu_ref;
}

## @function _sanitize_consts (%$consts_ref)
# @brief Convert and sanity check FIJI Settings for the whole design.
#
# NOTE: The function returns a reference to a *new* hashmap that contains
#       only the design constants!
#
# This function takes a hash of design settings and converts it to the
145
146
147
148
149
150
151
152
# respective internal representation. This allows to use different
# names in the external file than within the implementation.
#
# First, this function sets some default values for missing constants if
# there is a default stored for the respective constant in FIJI.pm.
# If there is no default available it has to be a mandatory value and
# hence the function returns non-0 in that case.
#
153
154
155
156
157
158
# ARM_DURATION_WIDTH and INJECT_DURATION_WIDTH are handled differently
# because they are not official FIJI Settings because there is only a
# single timer (yet). However, the Perl implementation supports
# independent timer widths named as above. If they are not given in
# consts_ref then the value of TIMER_WIDTH is used. If that is not given
# either the default value for TIMER_WIDTH is used.
159
160
161
#
# The second part of the function deals with sanity checks for the values
# themselves. It checks for the following conditions:
162
163
164
#
#   - FIU_NUM: > 0
#   - FIU_CFG_BITS: > 0
165
#   - ARM_DURATION_WIDTH, INJECT_DURATION_WIDTH: > 0, multiple of 8
166
167
168
#   - ID: > 0, < 2^15-1
#   - BAUDRATE: > 0
#
169
# \param consts_ref a reference to a hash containing some design settings
170
#
171
172
# \returns A new hash with all constants required in the design settings
#          in sanitized form, or undef on errors.
173
174
175
176
sub _sanitize_consts {
  my $logger = get_logger();
  my ($consts_ref) = @_;
  if (ref($consts_ref) ne 'HASH') {
177
    $logger->error("Parameter is not a reference to a hash (containing design constants).");
178
179
180
181
182
183
    return undef;
  }

  # Special cases of defaults handled separately here.
  # Set ARM_DURATION_WIDTH and INJECT_DURATION_WIDTH to TIMER_WIDTH (or its default)
  foreach my $k ('ARM_DURATION_WIDTH', 'INJECT_DURATION_WIDTH') {
184
    if (!exists($consts_ref->{DESIGNMAP->{$k}->{'ini_name'}})) {
185
      if (exists($consts_ref->{'TIMER_WIDTH'})) {
186
187
        $consts_ref->{DESIGNMAP->{$k}->{'ini_name'}} = $consts_ref->{'TIMER_WIDTH'};
        $logger->trace(sprintf("Using TIMER_WIDTH value as default for %s (%s).", DESIGNMAP->{$k}->{'ini_name'}, $consts_ref->{'TIMER_WIDTH'}));
188
      } else {
189
190
        $consts_ref->{DESIGNMAP->{$k}->{'ini_name'}} = TIMER_WIDTH->{'default'};
        $logger->trace(sprintf("Using TIMER_WIDTH default as default for %s (%s).", DESIGNMAP->{$k}->{'ini_name'}, TIMER_WIDTH->{default}));
191
192
      }
    }
193
194
  }

195
  my $new_consts = {};
196
197
198
  # Iterating over DESIGNMAP hash from FIJI.pm and set defaults if need be
  foreach my $k (keys(DESIGNMAP)) {
    my $ini_name = DESIGNMAP->{$k}->{'ini_name'};
199
200
201
202
    if (exists($consts_ref->{$ini_name})) {
      $new_consts->{$k} = $consts_ref->{$ini_name};
      $logger->trace(sprintf("Copying setting %s (%s) = %s.", $k, $ini_name, $consts_ref->{$ini_name}));
    } else {
203
204
205
206
207
208
209
210
      if (exists(DESIGNMAP->{$k}->{default})) {
        $new_consts->{$k} = DESIGNMAP->{$k}->{default};
        $logger->trace(sprintf("Adding default constant: %s (%s) = %s.", $k, $ini_name, DESIGNMAP->{$k}->{default}));
        # If the default key is there but its value is undef then
        # the value will be set somewhere else later (used for FIU_NUM)
        if (!defined($new_consts->{$k})) {
          next;
        }
211
      } else {
212
        $logger->error(sprintf("%s is missing from FIJI constants.", $ini_name));
213
214
        return undef;
      }
215
216
    }

217
    my $orig = $new_consts->{$k};
218
219
220
221
222
223
224
225
    # convert non-decimal (hexadecimal, binary, octal) values to decimal
    if (DESIGNMAP->{$k}->{is_numeric}) {
      $new_consts->{$k} = oct($orig) if $orig =~ /^0/;
      $logger->trace("Converted value of $k (\"$orig\") to \"$new_consts->{$k}\".") if ($orig ne $new_consts->{$k});
      if (!looks_like_number($new_consts->{$k})) {
        $logger->error("$orig does not look like a number.");
        return undef;
      }
226
227
228
    }
  }

229
230
  # check for sane values
  if (($new_consts->{FIU_CFG_BITS} <= 0)) {
231
      $logger->error("FIU_CFG_BITS is <= 0.");
232
      return undef;
233
  }
234
235
236
  if (($new_consts->{ARM_DURATION_WIDTH} <= 0) || ($new_consts->{ARM_DURATION_WIDTH} % 8 != 0)) {
      $logger->error("ARM_DURATION_WIDTH is invalid ($new_consts->{ARM_DURATION_WIDTH}).");
      return undef;
237
  }
238
239
240
  if (($new_consts->{INJECT_DURATION_WIDTH} <= 0) || (($new_consts->{INJECT_DURATION_WIDTH} % 8) != 0)) {
      $logger->error("INJECT_DURATION_WIDTH is invalid ($new_consts->{INJECT_DURATION_WIDTH}).");
      return undef;
241
  }
242
243
244
  if (($new_consts->{ID} <= 0) || ($new_consts->{ID} > (2**15 - 1))) {
      $logger->error("ID is invalid ($new_consts->{ID}).");
      return undef;
245
  }
246
  if (($new_consts->{BAUDRATE} <= 0)) {
247
      $logger->error("BAUDRATE missing is <= 0.");
248
      return undef;
249
  }
250
  return $new_consts;
251
252
253
}

1;