Skip to content

Commit

Permalink
Add SwValueCont, ApplicationValueSpecification
Browse files Browse the repository at this point in the history
  • Loading branch information
cogu committed Nov 7, 2023
1 parent 5653b5b commit 18a8bba
Show file tree
Hide file tree
Showing 6 changed files with 390 additions and 43 deletions.
24 changes: 13 additions & 11 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,25 @@ The name in the parenthesis after each element is the name used in the XML schem

* Value checker for positive integers

#### XML - Value specification elements

* TextValueSpecification | TEXT-VALUE-SPECIFICATION
* NumericalValueSpecification | NUMERICAL-VALUE-SPECIFICATION
* NotAvailableValueSpecification | NOT-AVAILABLE-VALUE-SPECIFICATION
* ArrayValueSpecification | ARRAY-VALUE-SPECIFICATION
* RecordValueSpecification | RECORD-VALUE-SPECIFICATION

#### XML - Data type elements

* ValueList | VALUE-LIST

#### XML - Calibration elements

* SwValues | AR:SW-VALUES
* ValueGroup | AR:VALUE-GROUP
* SwAxisCont | AR:SW-AXIS-CONT
* SwAValueCont | SW-VALUE-CONT
* SwAxisCont | SW-AXIS-CONT
* SwValues | SW-VALUES
* ValueGroup | VALUE-GROUP

#### XML - Value specification elements

* ApplicationValueSpecification | APPLICATION-VALUE-SPECIFICATION
* ArrayValueSpecification | ARRAY-VALUE-SPECIFICATION
* NotAvailableValueSpecification | NOT-AVAILABLE-VALUE-SPECIFICATION
* NumericalValueSpecification | NUMERICAL-VALUE-SPECIFICATION
* RecordValueSpecification | RECORD-VALUE-SPECIFICATION
* TextValueSpecification | TEXT-VALUE-SPECIFICATION

## [v0.5.0] - 2023-10-27

Expand Down
79 changes: 73 additions & 6 deletions src/autosar/xml/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -2456,13 +2456,45 @@ def __init__(self,
sw_axis_index: int | str | None = None,
sw_array_size: ValueList | None = None,
sw_values_phys: SwValues | None = None) -> None:
self.category = category # .CATEGORY
self.category: ar_enum.CalibrationAxisCategory = None # .CATEGORY
self.unit_ref: UnitRef = None # .UNIT-REF
self._assign_optional('unit_ref', unit_ref, UnitRef)
self.unit_display_name = unit_display_name # .UNIT-DISPLAY-NAME"
self.sw_axis_index = sw_axis_index # .SW-AXIS-INDEX
self.sw_array_size = sw_array_size # .SW-ARRAYSIZE
self.sw_values_phys = sw_values_phys # .SW-VALUES-PHYS
self.unit_display_name: SingleLanguageUnitNames = None # .UNIT-DISPLAY_NAME
self.sw_axis_index: int | str = None # .SW-AXIS-INDEX
self.sw_array_size: ValueList = None # .SW-ARRAYSIZE
self.sw_values_phys: SwValues = None # .SW-VALUES-PHYS
self._assign_optional('category', category, ar_enum.CalibrationAxisCategory)
self._assign_optional_strict('unit_ref', unit_ref, UnitRef)
self._assign_optional_strict('unit_display_name', unit_display_name, SingleLanguageUnitNames)
if sw_axis_index is not None:
if isinstance(sw_axis_index, (int, str)):
self.sw_axis_index = sw_axis_index
else:
error_msg = "Invalid type for parameter 'sw_axis_index'. Expected 'int' or 'str', "
raise TypeError(error_msg + f"got '{str(type(sw_axis_index))}'")
self._assign_optional_strict('sw_array_size', sw_array_size, ValueList)
self._assign_optional_strict('sw_values_phys', sw_values_phys, SwValues)


class SwValueCont(ARObject):
"""
Complex-type AR:SW-VALUE-CONT
Type: Concrete
Tag variants: SW-VALUE-CONT
"""

def __init__(self,
unit_ref: UnitRef | None = None,
unit_display_name: SingleLanguageUnitNames | None = None,
sw_array_size: ValueList | None = None,
sw_values_phys: SwValues | None = None) -> None:
self.unit_ref: UnitRef = None # .UNIT-REF
self.unit_display_name: SingleLanguageUnitNames = None # .UNIT-DISPLAY_NAME
self.sw_array_size: ValueList = None # .SW-ARRAYSIZE
self.sw_values_phys: SwValues = None # .SW-VALUES-PHYS
self._assign_optional_strict('unit_ref', unit_ref, UnitRef)
self._assign_optional_strict('unit_display_name', unit_display_name, SingleLanguageUnitNames)
self._assign_optional_strict('sw_array_size', sw_array_size, ValueList)
self._assign_optional_strict('sw_values_phys', sw_values_phys, SwValues)


# Constant and value specifications
Expand Down Expand Up @@ -2636,6 +2668,41 @@ def append(self, field: ValueSpeficationElement):
raise TypeError(f"Invalid type for 'field': {str(type(field))}")
self.fields.append(field)


class ApplicationValueSpecification(ValueSpecification):
"""
Complex-type AR:APPLICATION-VALUE-SPECIFICATION
Type: Concrete
Tag variants: APPLICATION-VALUE-SPECIFICATION
"""

def __init__(self,
label: str | None = None,
category: str | None = None,
sw_axis_conts: SwAxisCont | list[SwAxisCont] | None = None,
sw_value_cont: SwValueCont | None = None
) -> None:
super().__init__(label)
self.category: str = None
self.sw_axis_conts: list[SwAxisCont] = []
self.sw_value_cont: SwValueCont = None
self._assign_optional_strict("category", category, str)
self._assign_optional_strict("sw_value_cont", sw_value_cont, SwValueCont)
if sw_axis_conts is not None:
if isinstance(sw_axis_conts, SwAxisCont):
self.sw_axis_conts.append(sw_axis_conts)
elif isinstance(sw_axis_conts, list):
for elem in sw_axis_conts:
if isinstance(elem, SwAxisCont):
self.sw_axis_conts.append(elem)
else:
error_msg = "sw_axis_conts: Elements in list must of type SwAxisCont."
raise TypeError(error_msg + f" Got {str(type(elem))}")
else:
error_msg = "sw_axis_conts: argument must be either SwAxisCont or list[SwAxisCont]."
raise TypeError(error_msg + f" Got {str(type(sw_axis_conts))}")


# !!UNFINISHED!! Port Interfaces


Expand Down
64 changes: 64 additions & 0 deletions src/autosar/xml/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ def __init__(self,
'NOT-AVAILABLE-VALUE-SPECIFICATION': self._read_not_available_value_specification,
'ARRAY-VALUE-SPECIFICATION': self._read_array_value_specification,
'RECORD-VALUE-SPECIFICATION': self._read_record_value_specification,
'APPLICATION-VALUE-SPECIFICATION': self._read_application_value_specification,
}
self.switcher_non_collectable = { # Non-collectable, used only for unit testing
# Documentation elements
Expand Down Expand Up @@ -169,6 +170,7 @@ def __init__(self,
# CalibrationData elements
'SW-VALUES-PHYS': self._read_sw_values,
'SW-AXIS-CONT': self._read_sw_axis_cont,
'SW-VALUE-CONT': self._read_sw_value_cont,
# Reference elements
'PHYSICAL-DIMENSION-REF': self._read_physical_dimension_ref,
'APPLICATION-DATA-TYPE-REF': self._read_application_data_type_ref,
Expand Down Expand Up @@ -2172,6 +2174,39 @@ def _read_value_specification_group(self, child_elements: ChildElementMap, data:
if xml_child is not None:
data["label"] = xml_child.text

def _read_application_value_specification(self,
xml_element: ElementTree.Element
) -> ar_element.ApplicationValueSpecification:
"""
Reads complex-type AR:APPLICATION-VALUE-SPECIFICATION
Type: Concrete
"""
data = {}
child_elements = ChildElementMap(xml_element)
self._read_value_specification_group(child_elements, data)
self._read_application_value_specification_group(child_elements, data)
self._report_unprocessed_elements(child_elements)
element = ar_element.ApplicationValueSpecification(**data)
return element

def _read_application_value_specification_group(self,
child_elements: ChildElementMap, data: dict) -> None:
"""
Reads group AR:APPLICATION-VALUE-SPECIFICATION
"""
xml_child = child_elements.get("CATEGORY")
if xml_child is not None:
data["category"] = xml_child.text
xml_child = child_elements.get("SW-AXIS-CONTS")
if xml_child is not None:
elements = []
for xml_grand_child in xml_child.findall("./SW-AXIS-CONT"):
elements.append(self._read_sw_axis_cont(xml_grand_child))
data["sw_axis_conts"] = elements
xml_child = child_elements.get("SW-VALUE-CONT")
if xml_child is not None:
data["sw_value_cont"] = self._read_sw_value_cont(xml_child)

# CalibrationData elements

def _read_sw_values(self,
Expand Down Expand Up @@ -2270,6 +2305,35 @@ def _read_sw_axis_cont_group(self, child_elements: ChildElementMap, data: dict)
if xml_child is not None:
data["sw_values_phys"] = self._read_sw_values(xml_child)

def _read_sw_value_cont(self, xml_element: ElementTree.Element) -> ar_element.SwValueCont:
"""
Reads complex-type AR:SW-VALUE-CONT
Type: Concrete
"""
data = {}
child_elements = ChildElementMap(xml_element)
self._read_sw_value_cont_group(child_elements, data)
self._report_unprocessed_elements(child_elements)
element = ar_element.SwValueCont(**data)
return element

def _read_sw_value_cont_group(self, child_elements: ChildElementMap, data: dict) -> None:
"""
Reads group AR:SW-VALUE-CONT
"""
xml_child = child_elements.get("UNIT-REF")
if xml_child is not None:
data["unit_ref"] = self._read_unit_ref(xml_child)
xml_child = child_elements.get("UNIT-DISPLAY-NAME")
if xml_child is not None:
data["unit_display_name"] = self._read_single_language_unit_names(xml_child)
xml_child = child_elements.get("SW-ARRAYSIZE")
if xml_child is not None:
data["sw_array_size"] = self._read_value_list(xml_child)
xml_child = child_elements.get("SW-VALUES-PHYS")
if xml_child is not None:
data["sw_values_phys"] = self._read_sw_values(xml_child)

# UNFINISHED ELEMENTS - NEEDS REFACTORING

def _read_sender_receiver_interface(self, xml_element: ElementTree.Element) -> None:
Expand Down
58 changes: 58 additions & 0 deletions src/autosar/xml/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ def __init__(self) -> None:
'NotAvailableValueSpecification': self._write_not_available_value_specification,
'ArrayValueSpecification': self._write_array_value_specification,
'RecordValueSpecification': self._write_record_value_specification,
'ApplicationValueSpecification': self._write_application_value_specification,
}
# Elements used only for unit test purposes
self.switcher_non_collectable = {
Expand Down Expand Up @@ -248,6 +249,7 @@ def __init__(self) -> None:
# CalibrationData elements
'SwValues': self._write_sw_values,
'SwAxisCont': self._write_sw_axis_cont,
'SwValueCont': self._write_sw_value_cont,
# Reference elements
'PhysicalDimensionRef': self._write_physical_dimension_ref,
'ApplicationDataTypeRef': self._write_application_data_type_ref,
Expand Down Expand Up @@ -1841,6 +1843,34 @@ def _write_record_value_specification_group(self, elem: ar_element.RecordValueSp
self._write_value_specification_element(field)
self._leave_child()

def _write_application_value_specification(self, elem: ar_element.ApplicationValueSpecification) -> None:
"""
Writes complex-type AR:APPLICATION-VALUE-SPECIFICATION
"""
assert isinstance(elem, ar_element.ApplicationValueSpecification)
tag = "APPLICATION-VALUE-SPECIFICATION"
if elem.is_empty:
self._add_content(tag)
else:
self._add_child(tag)
self._write_value_specification_group(elem)
self._write_application_specification_group(elem)
self._leave_child()

def _write_application_specification_group(self, elem: ar_element.ApplicationValueSpecification) -> None:
"""
Writes group AR:APPLICATION-VALUE-SPECIFICATION
"""
if elem.category is not None:
self._add_content("CATEGORY", str(elem.category))
if elem.sw_axis_conts:
self._add_child("SW-AXIS-CONTS")
for child in elem.sw_axis_conts:
self._write_sw_axis_cont(child)
self._leave_child()
if elem.sw_value_cont is not None:
self._write_sw_value_cont(elem.sw_value_cont)

def _write_value_specification_group(self, elem: ar_element.ValueSpecification) -> None:
"""
Writes group AR:VALUE-SPECIFICATION
Expand Down Expand Up @@ -1938,3 +1968,31 @@ def _write_sw_axis_cont_group(self, elem: ar_element.SwAxisCont) -> None:
self._write_value_list(elem.sw_array_size)
if elem.sw_values_phys is not None:
self._write_sw_values(elem.sw_values_phys)

def _write_sw_value_cont(self, elem: ar_element.SwValueCont) -> None:
"""
Writes Complex-type SW-VALUE-CONT
Type: Concrete
"""
assert isinstance(elem, ar_element.SwValueCont)
tag = "SW-VALUE-CONT"
if elem.is_empty:
self._add_content(tag)
else:
self._add_child(tag)
self._write_sw_value_cont_group(elem)
self._leave_child()

def _write_sw_value_cont_group(self, elem: ar_element.SwValueCont) -> None:
"""
Writes group SW-VALUE-CONT
Type: Concrete
"""
if elem.unit_ref is not None:
self._write_unit_ref(elem.unit_ref)
if elem.unit_display_name is not None:
self._write_single_language_unit_names(elem.unit_display_name, "UNIT-DISPLAY-NAME")
if elem.sw_array_size is not None:
self._write_value_list(elem.sw_array_size)
if elem.sw_values_phys is not None:
self._write_sw_values(elem.sw_values_phys)
70 changes: 70 additions & 0 deletions tests/xml/test_calibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,5 +261,75 @@ def test_read_write_sw_values_phys(self):
self.assertEqual(elem.sw_values_phys.values, [1])


class TestSwValueCont(unittest.TestCase):

def test_read_write_empty(self):
element = ar_element.SwValueCont()
writer = autosar.xml.Writer()
xml = writer.write_str_elem(element)
self.assertEqual(xml, '<SW-VALUE-CONT/>')
reader = autosar.xml.Reader()
elem: ar_element.SwValueCont = reader.read_str_elem(xml)
self.assertIsInstance(elem, ar_element.SwValueCont)

def test_read_write_unit_ref(self):
element = ar_element.SwValueCont(unit_ref=ar_element.UnitRef("/Units/MyUnit"))
writer = autosar.xml.Writer()
xml = '''<SW-VALUE-CONT>
<UNIT-REF DEST="UNIT">/Units/MyUnit</UNIT-REF>
</SW-VALUE-CONT>'''

self.assertEqual(writer.write_str_elem(element), xml)
reader = autosar.xml.Reader()
elem: ar_element.SwValueCont = reader.read_str_elem(xml)
self.assertIsInstance(elem, ar_element.SwValueCont)
self.assertEqual(str(elem.unit_ref), "/Units/MyUnit")

def test_read_write_unit_display_name(self):
unit_display_name = ar_element.SingleLanguageUnitNames("Km/h")
element = ar_element.SwValueCont(unit_display_name=unit_display_name)
writer = autosar.xml.Writer()
xml = '''<SW-VALUE-CONT>
<UNIT-DISPLAY-NAME>Km/h</UNIT-DISPLAY-NAME>
</SW-VALUE-CONT>'''

self.assertEqual(writer.write_str_elem(element), xml)
reader = autosar.xml.Reader()
elem: ar_element.SwValueCont = reader.read_str_elem(xml)
self.assertIsInstance(elem, ar_element.SwValueCont)
self.assertEqual(str(elem.unit_display_name), "Km/h")

def test_read_write_sw_array_size(self):
element = ar_element.SwValueCont(sw_array_size=ar_element.ValueList([1, 2]))
writer = autosar.xml.Writer()
xml = '''<SW-VALUE-CONT>
<SW-ARRAYSIZE>
<V>1</V>
<V>2</V>
</SW-ARRAYSIZE>
</SW-VALUE-CONT>'''

self.assertEqual(writer.write_str_elem(element), xml)
reader = autosar.xml.Reader()
elem: ar_element.SwValueCont = reader.read_str_elem(xml)
self.assertIsInstance(elem, ar_element.SwValueCont)
self.assertEqual(elem.sw_array_size.values, [1, 2])

def test_read_write_sw_values_phys(self):
element = ar_element.SwValueCont(sw_values_phys=ar_element.SwValues(1))
writer = autosar.xml.Writer()
xml = '''<SW-VALUE-CONT>
<SW-VALUES-PHYS>
<V>1</V>
</SW-VALUES-PHYS>
</SW-VALUE-CONT>'''

self.assertEqual(writer.write_str_elem(element), xml)
reader = autosar.xml.Reader()
elem: ar_element.SwValueCont = reader.read_str_elem(xml)
self.assertIsInstance(elem, ar_element.SwValueCont)
self.assertEqual(elem.sw_values_phys.values, [1])


if __name__ == '__main__':
unittest.main()
Loading

0 comments on commit 18a8bba

Please sign in to comment.