Skip to content

Commit

Permalink
Merge pull request #1332 from OpenC3/array_widget
Browse files Browse the repository at this point in the history
Allow array index in VALUE widget
  • Loading branch information
jmthomas authored Jun 17, 2024
2 parents 9c9d8e4 + 2e9be0b commit 31f5499
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ SCREEN AUTO AUTO 1.0
VERTICAL
TITLE "<%= target_name %> Instrument Array Data"
ARRAY <%= target_name %> HEALTH_STATUS ARY
LABELVALUE <%= target_name %> HEALTH_STATUS ARY[0] RAW
LABELVALUE <%= target_name %> HEALTH_STATUS ARY[1] WITH_UNITS
ARRAY <%= target_name %> HEALTH_STATUS ARY 300 65 nil 8 FORMATTED
ARRAY <%= target_name %> HEALTH_STATUS ARY2 300 65 nil 5 WITH_UNITS
TEXTBOX <%= target_name %> HEALTH_STATUS ARY 200 65
TEXTBOX <%= target_name %> HEALTH_STATUS ARY2 300 200
TEXTBOX <%= target_name %> HEALTH_STATUS ARY2 300 65
ARRAY <%= target_name %> HEALTH_STATUS GROUND1STATUS 300 65 nil 8 FORMATTED
ARRAY <%= target_name %> HEALTH_STATUS GROUND2STATUS 300 65 nil 5 WITH_UNITS
END
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ SCREEN AUTO AUTO 1.0
VERTICAL
TITLE "<%= target_name %> Instrument Array Data"
ARRAY <%= target_name %> HEALTH_STATUS ARY
LABELVALUE <%= target_name %> HEALTH_STATUS ARY[0] RAW
LABELVALUE <%= target_name %> HEALTH_STATUS ARY[1] WITH_UNITS
ARRAY <%= target_name %> HEALTH_STATUS ARY 300 65 nil 8 FORMATTED
ARRAY <%= target_name %> HEALTH_STATUS ARY2 300 65 nil 5 WITH_UNITS
TEXTBOX <%= target_name %> HEALTH_STATUS ARY 200 65
TEXTBOX <%= target_name %> HEALTH_STATUS ARY2 300 200
TEXTBOX <%= target_name %> HEALTH_STATUS ARY2 300 65
ARRAY <%= target_name %> HEALTH_STATUS GROUND1STATUS 300 65 nil 8 FORMATTED
ARRAY <%= target_name %> HEALTH_STATUS GROUND2STATUS 300 65 nil 5 WITH_UNITS
END
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,15 @@ export default {
},
computed: {
labelName() {
let label = this.parameters[2]
// Remove double bracket escaping. This means they actually have an item
// with a bracket in the name, not an array index.
if (label.includes('[[')) {
label = label.replace('[[', '[').replace(']]', ']')
}
// LabelWidget uses index 0 from the parameters prop
// so create an array with the label text in the first position
return [this.parameters[2] + ':']
return [label + ':']
},
valueParameters() {
return [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export default {
grayLevel: 80,
grayRate: 5,
valueId: null,
arrayIndex: null,
viewDetails: false,
contextMenuShown: false,
x: 0,
Expand Down Expand Up @@ -96,8 +97,17 @@ export default {
// See store.js for how this is set
if (this.screen) {
if (this.screen.screenValues[this.valueId]) {
this.curValue = this.screen.screenValues[this.valueId][0]
if (
this.arrayIndex !== null &&
this.screen.screenValues[this.valueId][0]
) {
this.curValue =
this.screen.screenValues[this.valueId][0][this.arrayIndex]
} else {
this.curValue = this.screen.screenValues[this.valueId][0]
}
}
// }
} else {
this.curValue = null
}
Expand Down Expand Up @@ -190,6 +200,18 @@ export default {
created() {
// If they're not passing us the value and limitsState we have to register
if (this.value === null || this.limitsState === null) {
// Remove double bracket escaping. This means they actually have an item
// with a bracket in the name, not an array index.
if (this.parameters[2].includes('[[')) {
this.parameters[2] = this.parameters[2]
.replace('[[', '[')
.replace(']]', ']')
} else if (this.parameters[2].includes('[')) {
// Brackets mean array indexes (normally, but see above)
let match = this.parameters[2].match(/\[(\d+)\]/)
this.arrayIndex = parseInt(match[1])
this.parameters[2] = this.parameters[2].replace(match[0], '')
}
this.valueId = `${this.parameters[0]}__${this.parameters[1]}__${
this.parameters[2]
}__${this.getType()}`
Expand Down
7 changes: 5 additions & 2 deletions openc3/lib/openc3/config/config_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@ def verify_num_parameters(min_num_params, max_num_params, usage = "")
end

# Verifies the indicated parameter in the config doesn't start or end
# with an underscore, doesn't contain a double underscore, doesn't contain
# spaces and doesn't start with a close bracket.
# with an underscore, doesn't contain a double underscore or double bracket,
# doesn't contain spaces and doesn't start with a close bracket.
#
# @param [Integer] index The index of the parameter to check
def verify_parameter_naming(index, usage = "")
Expand All @@ -259,6 +259,9 @@ def verify_parameter_naming(index, usage = "")
if param.include? '__'
raise Error.new(self, "Parameter #{index} (#{param}) for #{@keyword} cannot contain a double underscore ('__').", usage, @url)
end
if param.include? '[[' or param.include? ']]'
raise Error.new(self, "Parameter #{index} (#{param}) for #{@keyword} cannot contain double brackets ('[[' or ']]').", usage, @url)
end
if param.include? ' '
raise Error.new(self, "Parameter #{index} (#{param}) for #{@keyword} cannot contain a space (' ').", usage, @url)
end
Expand Down
14 changes: 11 additions & 3 deletions openc3/python/openc3/config/config_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ def verify_num_parameters(self, min_num_params, max_num_params, usage=""):
if max_num_params and self.parameters[max_num_params : max_num_params + 1]:
raise ConfigParser.Error(self, f"Too many parameters for {self.keyword}.", usage, self.url)

# Verifies the indicated parameter in the config doesn't start or
# with an underscore, doesn't contain a double underscore, doesn't contain
# spaces and doesn't start with a close bracket.
# Verifies the indicated parameter in the config doesn't start or end
# with an underscore, doesn't contain a double underscore or double bracket,
# doesn't contain spaces and doesn't start with a close bracket.
#
# self.param [Integer] index The index of the parameter to check
def verify_parameter_naming(self, index, usage=""):
Expand All @@ -142,6 +142,14 @@ def verify_parameter_naming(self, index, usage=""):
self.url,
)

if "[[" in param or "]]" in param:
raise ConfigParser.Error(
self,
f"Parameter {index} ({param}) for {self.keyword} cannot contain double brackets ('[[' or ']]').",
usage,
self.url,
)

if " " in param:
raise ConfigParser.Error(
self,
Expand Down
48 changes: 17 additions & 31 deletions openc3/python/test/config/test_config_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ def test_verifies_the_maximum_number_of_parameters(self):

def test_verifies_parameters_do_not_have_bad_characters(self):
tf = tempfile.NamedTemporaryFile(mode="w+t")
line = "KEYWORD BAD1_ BAD__2 'BAD 3' }BAD_4"
line = "KEYWORD BAD1_ BAD__2 'BAD 3' }BAD_4 BAD[[5]]"
tf.writelines(line)
tf.seek(0)

Expand Down Expand Up @@ -382,6 +382,12 @@ def test_verifies_parameters_do_not_have_bad_characters(self):
self.cp.verify_parameter_naming,
4,
)
self.assertRaisesRegex(
ConfigParser.Error,
"cannot contain double brackets",
self.cp.verify_parameter_naming,
5,
)
tf.close()

def test_returns_an_error(self):
Expand Down Expand Up @@ -472,9 +478,7 @@ def test_tfn_returns_values_that_dont_convert(self):
def test_converts_string_constants_to_numbers(self):
for val in range(1, 65):
# Unsigned
self.assertEqual(
ConfigParser.handle_defined_constants("MIN", "UINT", val), 0
)
self.assertEqual(ConfigParser.handle_defined_constants("MIN", "UINT", val), 0)
self.assertEqual(
ConfigParser.handle_defined_constants("MAX", "UINT", val),
(2**val - 1),
Expand All @@ -492,9 +496,7 @@ def test_converts_string_constants_to_numbers(self):
for val in [8, 16, 32, 64]:
# Unsigned
self.assertEqual(ConfigParser.handle_defined_constants(f"MIN_UINT{val}"), 0)
self.assertEqual(
ConfigParser.handle_defined_constants(f"MAX_UINT{val}"), (2**val - 1)
)
self.assertEqual(ConfigParser.handle_defined_constants(f"MAX_UINT{val}"), (2**val - 1))
# Signed
self.assertEqual(
ConfigParser.handle_defined_constants(f"MIN_INT{val}"),
Expand All @@ -506,38 +508,22 @@ def test_converts_string_constants_to_numbers(self):
)

# Float
self.assertLess(
ConfigParser.handle_defined_constants("MIN", "FLOAT", 32), -3.4 * 10**38
)
self.assertLess(
ConfigParser.handle_defined_constants("MIN_FLOAT32"), -3.4 * 10**38
)
self.assertGreater(
ConfigParser.handle_defined_constants("MAX", "FLOAT", 32), 3.4 * 10**38
)
self.assertGreater(
ConfigParser.handle_defined_constants("MAX_FLOAT32"), 3.4 * 10**38
)
self.assertLess(ConfigParser.handle_defined_constants("MIN", "FLOAT", 32), -3.4 * 10**38)
self.assertLess(ConfigParser.handle_defined_constants("MIN_FLOAT32"), -3.4 * 10**38)
self.assertGreater(ConfigParser.handle_defined_constants("MAX", "FLOAT", 32), 3.4 * 10**38)
self.assertGreater(ConfigParser.handle_defined_constants("MAX_FLOAT32"), 3.4 * 10**38)
self.assertEqual(
ConfigParser.handle_defined_constants("MIN", "FLOAT", 64),
-sys.float_info.max,
)
self.assertEqual(
ConfigParser.handle_defined_constants("MIN_FLOAT64"), -sys.float_info.max
)
self.assertEqual(ConfigParser.handle_defined_constants("MIN_FLOAT64"), -sys.float_info.max)
self.assertEqual(
ConfigParser.handle_defined_constants("MAX", "FLOAT", 64),
sys.float_info.max,
)
self.assertEqual(
ConfigParser.handle_defined_constants("MAX_FLOAT64"), sys.float_info.max
)
self.assertEqual(
ConfigParser.handle_defined_constants("POS_INFINITY"), float("inf")
)
self.assertEqual(
ConfigParser.handle_defined_constants("NEG_INFINITY"), float("-inf")
)
self.assertEqual(ConfigParser.handle_defined_constants("MAX_FLOAT64"), sys.float_info.max)
self.assertEqual(ConfigParser.handle_defined_constants("POS_INFINITY"), float("inf"))
self.assertEqual(ConfigParser.handle_defined_constants("NEG_INFINITY"), float("-inf"))
self.assertRaisesRegex(
AttributeError,
"Invalid bit size 16 for FLOAT type.",
Expand Down
41 changes: 21 additions & 20 deletions openc3/spec/config/config_parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# GNU Affero General Public License for more details.

# Modified by OpenC3, Inc.
# All changes Copyright 2022, OpenC3, Inc.
# All changes Copyright 2024, OpenC3, Inc.
# All Rights Reserved
#
# This file may also be used under the terms of a commercial license
Expand Down Expand Up @@ -116,7 +116,7 @@ module OpenC3
tf.puts "<%= render '#{subdir_path}' %>"
tf.close

@cp.parse_file(tf.path) do |keyword, params|
@cp.parse_file(tf.path) do |keyword, _params|
expect(keyword).to eql "SUBDIR"
end
tf.unlink
Expand All @@ -133,7 +133,7 @@ module OpenC3
tf.puts "<%= render '#{tf2.path}' %>"
tf.close

@cp.parse_file(tf.path) do |keyword, params|
@cp.parse_file(tf.path) do |keyword, _params|
expect(keyword).to eql "ABSOLUTE"
end
tf.unlink
Expand Down Expand Up @@ -337,7 +337,7 @@ module OpenC3
tf.close

lines = []
@cp.parse_file(tf.path, true) do |keyword, params|
@cp.parse_file(tf.path, true) do |_keyword, _params|
lines << @cp.line
end
expect(lines).to include("# This is a comment")
Expand Down Expand Up @@ -389,7 +389,7 @@ module OpenC3
tf.puts line
tf.close

@cp.parse_file(tf.path) do |keyword, params|
@cp.parse_file(tf.path) do |keyword, _params|
expect(keyword).to eql "KEYWORD"
expect { @cp.verify_num_parameters(1, 1) }.to raise_error(ConfigParser::Error, "Not enough parameters for KEYWORD.")
end
Expand All @@ -402,7 +402,7 @@ module OpenC3
tf.puts line
tf.close

@cp.parse_file(tf.path) do |keyword, params|
@cp.parse_file(tf.path) do |keyword, _params|
expect(keyword).to eql "KEYWORD"
expect { @cp.verify_num_parameters(1, 1) }.to raise_error(ConfigParser::Error, "Too many parameters for KEYWORD.")
end
Expand All @@ -413,15 +413,16 @@ module OpenC3
describe "verify_parameter_naming" do
it "verifies parameters do not have bad characters" do
tf = Tempfile.new('unittest')
line = "KEYWORD BAD1_ BAD__2 'BAD 3' }BAD_4"
line = "KEYWORD BAD1_ BAD__2 'BAD 3' }BAD_4 BAD[[5]]"
tf.puts line
tf.close

@cp.parse_file(tf.path) do |keyword, params|
@cp.parse_file(tf.path) do |_keyword, _params|
expect { @cp.verify_parameter_naming(1) }.to raise_error(ConfigParser::Error, /cannot end with an underscore/)
expect { @cp.verify_parameter_naming(2) }.to raise_error(ConfigParser::Error, /cannot contain a double underscore/)
expect { @cp.verify_parameter_naming(3) }.to raise_error(ConfigParser::Error, /cannot contain a space/)
expect { @cp.verify_parameter_naming(4) }.to raise_error(ConfigParser::Error, /cannot start with a close bracket/)
expect { @cp.verify_parameter_naming(5) }.to raise_error(ConfigParser::Error, /cannot contain double brackets/)
end
tf.unlink
end
Expand All @@ -434,7 +435,7 @@ module OpenC3
tf.puts line
tf.close

@cp.parse_file(tf.path) do |keyword, params|
@cp.parse_file(tf.path) do |_keyword, _params|
error = @cp.error("Hello")
expect(error.message).to eql "Hello"
expect(error.keyword).to eql "KEYWORD"
Expand All @@ -453,7 +454,7 @@ module OpenC3
tf.close

expect {
@cp.parse_file(tf.path) do |keyword, params|
@cp.parse_file(tf.path) do |keyword, _params|
if keyword == "KEYWORD1"
raise @cp.error("Invalid KEYWORD1")
end
Expand Down Expand Up @@ -540,26 +541,26 @@ module OpenC3
(1..64).each do |val|
# Unsigned
expect(ConfigParser.handle_defined_constants("MIN", :UINT, val)).to eql 0
expect(ConfigParser.handle_defined_constants("MAX", :UINT, val)).to eql (2**val - 1)
expect(ConfigParser.handle_defined_constants("MAX", :UINT, val)).to eql((2**val) - 1)
# Signed
expect(ConfigParser.handle_defined_constants("MIN", :INT, val)).to eql (-(2**val) / 2)
expect(ConfigParser.handle_defined_constants("MAX", :INT, val)).to eql ((2**val) / 2 - 1)
expect(ConfigParser.handle_defined_constants("MIN", :INT, val)).to eql(-(2**val) / 2)
expect(ConfigParser.handle_defined_constants("MAX", :INT, val)).to eql(((2**val) / 2) - 1)
end
[8, 16, 32, 64].each do |val|
# Unsigned
expect(ConfigParser.handle_defined_constants("MIN_UINT#{val}")).to eql 0
expect(ConfigParser.handle_defined_constants("MAX_UINT#{val}")).to eql (2**val - 1)
expect(ConfigParser.handle_defined_constants("MAX_UINT#{val}")).to eql((2**val) - 1)
# Signed
expect(ConfigParser.handle_defined_constants("MIN_INT#{val}")).to eql (-(2**val) / 2)
expect(ConfigParser.handle_defined_constants("MAX_INT#{val}")).to eql ((2**val) / 2 - 1)
expect(ConfigParser.handle_defined_constants("MIN_INT#{val}")).to eql(-(2**val) / 2)
expect(ConfigParser.handle_defined_constants("MAX_INT#{val}")).to eql(((2**val) / 2) - 1)
end
# Float
expect(ConfigParser.handle_defined_constants("MIN_FLOAT32")).to be <= -3.4 * 10**38
expect(ConfigParser.handle_defined_constants("MAX_FLOAT32")).to be >= 3.4 * 10**38
expect(ConfigParser.handle_defined_constants("MIN_FLOAT64")).to eql (-Float::MAX)
expect(ConfigParser.handle_defined_constants("MIN_FLOAT32")).to be <= -3.4 * (10**38)
expect(ConfigParser.handle_defined_constants("MAX_FLOAT32")).to be >= 3.4 * (10**38)
expect(ConfigParser.handle_defined_constants("MIN_FLOAT64")).to eql(-Float::MAX)
expect(ConfigParser.handle_defined_constants("MAX_FLOAT64")).to eql Float::MAX
expect(ConfigParser.handle_defined_constants("POS_INFINITY")).to eql Float::INFINITY
expect(ConfigParser.handle_defined_constants("NEG_INFINITY")).to eql (-Float::INFINITY)
expect(ConfigParser.handle_defined_constants("NEG_INFINITY")).to eql(-Float::INFINITY)
end

it "complains about undefined strings" do
Expand Down

0 comments on commit 31f5499

Please sign in to comment.