vss-tools 0.5.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vspec/__init__.py +996 -0
- vspec/loggingconfig.py +22 -0
- vspec/model/__init__.py +7 -0
- vspec/model/constants.py +307 -0
- vspec/model/exceptions.py +29 -0
- vspec/model/vsstree.py +602 -0
- vspec/py.typed +0 -0
- vspec/utils/__init__.py +23 -0
- vspec/utils/idgen_utils.py +97 -0
- vspec/utils/stringstyle.py +25 -0
- vspec/utils/vss2id_val.py +165 -0
- vspec/vspec2vss_config.py +53 -0
- vspec/vspec2x.py +191 -0
- vspec/vss2x.py +38 -0
- vspec/vssexporters/__init__.py +7 -0
- vspec/vssexporters/vss2binary.py +147 -0
- vspec/vssexporters/vss2csv.py +82 -0
- vspec/vssexporters/vss2ddsidl.py +295 -0
- vspec/vssexporters/vss2franca.py +98 -0
- vspec/vssexporters/vss2graphql.py +143 -0
- vspec/vssexporters/vss2id.py +172 -0
- vspec/vssexporters/vss2json.py +116 -0
- vspec/vssexporters/vss2jsonschema.py +159 -0
- vspec/vssexporters/vss2protobuf.py +171 -0
- vspec/vssexporters/vss2yaml.py +122 -0
- vss_tools-0.5.0.dev0.data/scripts/vspec2csv.py +29 -0
- vss_tools-0.5.0.dev0.data/scripts/vspec2ddsidl.py +29 -0
- vss_tools-0.5.0.dev0.data/scripts/vspec2franca.py +29 -0
- vss_tools-0.5.0.dev0.data/scripts/vspec2graphql.py +29 -0
- vss_tools-0.5.0.dev0.data/scripts/vspec2id.py +28 -0
- vss_tools-0.5.0.dev0.data/scripts/vspec2json.py +29 -0
- vss_tools-0.5.0.dev0.data/scripts/vspec2jsonschema.py +29 -0
- vss_tools-0.5.0.dev0.data/scripts/vspec2protobuf.py +29 -0
- vss_tools-0.5.0.dev0.data/scripts/vspec2yaml.py +29 -0
- vss_tools-0.5.0.dev0.dist-info/LICENSE +373 -0
- vss_tools-0.5.0.dev0.dist-info/METADATA +65 -0
- vss_tools-0.5.0.dev0.dist-info/RECORD +39 -0
- vss_tools-0.5.0.dev0.dist-info/WHEEL +5 -0
- vss_tools-0.5.0.dev0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2022 Contributors to COVESA
|
|
4
|
+
#
|
|
5
|
+
# This program and the accompanying materials are made available under the
|
|
6
|
+
# terms of the Mozilla Public License 2.0 which is available at
|
|
7
|
+
# https://www.mozilla.org/en-US/MPL/2.0/
|
|
8
|
+
#
|
|
9
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
10
|
+
|
|
11
|
+
# Convert vspec tree to binary format
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
import logging
|
|
15
|
+
import ctypes
|
|
16
|
+
import os.path
|
|
17
|
+
from typing import Optional
|
|
18
|
+
from vspec.model.vsstree import VSSNode, VSSType
|
|
19
|
+
from vspec.vss2x import Vss2X
|
|
20
|
+
from vspec.vspec2vss_config import Vspec2VssConfig
|
|
21
|
+
|
|
22
|
+
out_file = ""
|
|
23
|
+
_cbinary = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def createBinaryCnode(fname, nodename, nodetype, uuid, description, nodedatatype, nodemin, nodemax, unit, allowed,
|
|
27
|
+
defaultAllowed, validate, children):
|
|
28
|
+
global _cbinary
|
|
29
|
+
_cbinary.createBinaryCnode(fname, nodename, nodetype, uuid, description, nodedatatype, nodemin, nodemax, unit,
|
|
30
|
+
allowed, defaultAllowed, validate, children)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def allowedString(allowedList):
|
|
34
|
+
allowedStr = ""
|
|
35
|
+
for elem in allowedList:
|
|
36
|
+
allowedStr += hexAllowedLen(elem) + elem
|
|
37
|
+
# print("allowedstr=" + allowedStr + "\n")
|
|
38
|
+
return allowedStr
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def hexAllowedLen(allowed):
|
|
42
|
+
hexDigit1 = len(allowed) // 16
|
|
43
|
+
hexDigit2 = len(allowed) - hexDigit1*16
|
|
44
|
+
# print("Hexdigs:" + str(hexDigit1) + str(hexDigit2))
|
|
45
|
+
return "".join([intToHexChar(hexDigit1), intToHexChar(hexDigit2)])
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def intToHexChar(hexInt):
|
|
49
|
+
if (hexInt < 10):
|
|
50
|
+
return chr(hexInt + ord('0'))
|
|
51
|
+
else:
|
|
52
|
+
return chr(hexInt - 10 + ord('A'))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def export_node(node, generate_uuid, out_file):
|
|
56
|
+
nodename = str(node.name)
|
|
57
|
+
b_nodename = nodename.encode('utf-8')
|
|
58
|
+
|
|
59
|
+
nodetype = str(node.type.value)
|
|
60
|
+
b_nodetype = nodetype.encode('utf-8')
|
|
61
|
+
|
|
62
|
+
nodedescription = str(node.description)
|
|
63
|
+
b_nodedescription = nodedescription.encode('utf-8')
|
|
64
|
+
|
|
65
|
+
children = len(node.children)
|
|
66
|
+
|
|
67
|
+
nodedatatype = ""
|
|
68
|
+
nodemin = ""
|
|
69
|
+
nodemax = ""
|
|
70
|
+
nodeunit = ""
|
|
71
|
+
nodeallowed = ""
|
|
72
|
+
nodedefault = ""
|
|
73
|
+
nodeuuid = ""
|
|
74
|
+
nodevalidate = "" # exported to binary
|
|
75
|
+
|
|
76
|
+
if node.type == VSSType.SENSOR or node.type == VSSType.ACTUATOR or node.type == VSSType.ATTRIBUTE:
|
|
77
|
+
nodedatatype = str(node.datatype.value)
|
|
78
|
+
b_nodedatatype = nodedatatype.encode('utf-8')
|
|
79
|
+
|
|
80
|
+
# many optional attributes are initilized to "" in vsstree.py
|
|
81
|
+
if node.min != "":
|
|
82
|
+
nodemin = str(node.min)
|
|
83
|
+
b_nodemin = nodemin.encode('utf-8')
|
|
84
|
+
|
|
85
|
+
if node.max != "":
|
|
86
|
+
nodemax = str(node.max)
|
|
87
|
+
b_nodemax = nodemax.encode('utf-8')
|
|
88
|
+
|
|
89
|
+
if node.allowed != "":
|
|
90
|
+
nodeallowed = allowedString(node.allowed)
|
|
91
|
+
b_nodeallowed = nodeallowed.encode('utf-8')
|
|
92
|
+
|
|
93
|
+
if node.default != "":
|
|
94
|
+
nodedefault = str(node.default)
|
|
95
|
+
b_nodedefault = nodedefault.encode('utf-8')
|
|
96
|
+
|
|
97
|
+
# in case of unit or aggregate, the attribute will be missing
|
|
98
|
+
try:
|
|
99
|
+
nodeunit = str(node.unit.value)
|
|
100
|
+
except AttributeError:
|
|
101
|
+
pass
|
|
102
|
+
b_nodeunit = nodeunit.encode('utf-8')
|
|
103
|
+
|
|
104
|
+
if generate_uuid:
|
|
105
|
+
nodeuuid = node.uuid
|
|
106
|
+
b_nodeuuid = nodeuuid.encode('utf-8')
|
|
107
|
+
|
|
108
|
+
if "validate" in node.extended_attributes:
|
|
109
|
+
nodevalidate = node.extended_attributes["validate"]
|
|
110
|
+
b_nodevalidate = nodevalidate.encode('utf-8')
|
|
111
|
+
|
|
112
|
+
b_fname = out_file.encode('utf-8')
|
|
113
|
+
|
|
114
|
+
createBinaryCnode(b_fname, b_nodename, b_nodetype, b_nodeuuid, b_nodedescription, b_nodedatatype, b_nodemin,
|
|
115
|
+
b_nodemax, b_nodeunit, b_nodeallowed, b_nodedefault, b_nodevalidate, children)
|
|
116
|
+
|
|
117
|
+
for child in node.children:
|
|
118
|
+
export_node(child, generate_uuid, out_file)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class Vss2Binary(Vss2X):
|
|
122
|
+
|
|
123
|
+
def __init__(self, vspec2vss_config: Vspec2VssConfig):
|
|
124
|
+
vspec2vss_config.type_tree_supported = False
|
|
125
|
+
vspec2vss_config.no_expand_option_supported = False
|
|
126
|
+
|
|
127
|
+
def generate(self, config: argparse.Namespace, root: VSSNode, vspec2vss_config: Vspec2VssConfig,
|
|
128
|
+
data_type_root: Optional[VSSNode] = None) -> None:
|
|
129
|
+
global _cbinary
|
|
130
|
+
dllName = "../../binary/binarytool.so"
|
|
131
|
+
dllAbsPath = os.path.dirname(os.path.abspath(__file__)) + os.path.sep + dllName
|
|
132
|
+
if not os.path.isfile(dllAbsPath):
|
|
133
|
+
logging.error("The required library binarytool.so is not available, exiting!")
|
|
134
|
+
logging.info("You must build the library, "
|
|
135
|
+
"see https://github.com/COVESA/vss-tools/blob/master/binary/README.md!")
|
|
136
|
+
return
|
|
137
|
+
_cbinary = ctypes.CDLL(dllAbsPath)
|
|
138
|
+
|
|
139
|
+
_cbinary.createBinaryCnode.argtypes = (ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p,
|
|
140
|
+
ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p,
|
|
141
|
+
ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p,
|
|
142
|
+
ctypes.c_int)
|
|
143
|
+
|
|
144
|
+
logging.info("Generating binary output...")
|
|
145
|
+
out_file = config.output_file
|
|
146
|
+
export_node(root, vspec2vss_config.generate_uuid, out_file)
|
|
147
|
+
logging.info("Binary output generated in " + out_file)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2021 Contributors to COVESA
|
|
4
|
+
#
|
|
5
|
+
# This program and the accompanying materials are made available under the
|
|
6
|
+
# terms of the Mozilla Public License 2.0 which is available at
|
|
7
|
+
# https://www.mozilla.org/en-US/MPL/2.0/
|
|
8
|
+
#
|
|
9
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
10
|
+
|
|
11
|
+
# Convert vspec tree to CSV
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import logging
|
|
16
|
+
from vspec.model.vsstree import VSSNode
|
|
17
|
+
from anytree import PreOrderIter # type: ignore[import]
|
|
18
|
+
from typing import AnyStr
|
|
19
|
+
from typing import Optional
|
|
20
|
+
from vspec.vss2x import Vss2X
|
|
21
|
+
from vspec.vspec2vss_config import Vspec2VssConfig
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Write the header line
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def print_csv_header(file, uuid, entry_type: AnyStr, include_instance_column: bool):
|
|
28
|
+
arg_list = [entry_type, "Type", "DataType", "Deprecated", "Unit",
|
|
29
|
+
"Min", "Max", "Desc", "Comment", "Allowed", "Default"]
|
|
30
|
+
if uuid:
|
|
31
|
+
arg_list.append("Id")
|
|
32
|
+
if include_instance_column:
|
|
33
|
+
arg_list.append("Instances")
|
|
34
|
+
file.write(format_csv_line(arg_list))
|
|
35
|
+
|
|
36
|
+
# Format a data or header line according to the CSV standard (IETF RFC 4180)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def format_csv_line(csv_fields):
|
|
40
|
+
formatted_csv_line = ""
|
|
41
|
+
for csv_field in csv_fields:
|
|
42
|
+
formatted_csv_line = formatted_csv_line + '"' + str(csv_field).replace('"', '""') + '",'
|
|
43
|
+
return formatted_csv_line[:-1] + '\n'
|
|
44
|
+
|
|
45
|
+
# Write the data lines
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def print_csv_content(file, tree: VSSNode, uuid, include_instance_column: bool):
|
|
49
|
+
tree_node: VSSNode
|
|
50
|
+
for tree_node in PreOrderIter(tree):
|
|
51
|
+
data_type_str = tree_node.get_datatype()
|
|
52
|
+
unit_str = tree_node.get_unit()
|
|
53
|
+
arg_list = [tree_node.qualified_name('.'), tree_node.type.value, data_type_str, tree_node.deprecation,
|
|
54
|
+
unit_str, tree_node.min, tree_node.max, tree_node.description, tree_node.comment,
|
|
55
|
+
tree_node.allowed, tree_node.default]
|
|
56
|
+
if uuid:
|
|
57
|
+
arg_list.append(tree_node.uuid)
|
|
58
|
+
if include_instance_column and tree_node.instances is not None:
|
|
59
|
+
arg_list.append(tree_node.instances)
|
|
60
|
+
file.write(format_csv_line(arg_list))
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class Vss2Csv(Vss2X):
|
|
64
|
+
|
|
65
|
+
def generate(self, config: argparse.Namespace, signal_root: VSSNode, vspec2vss_config: Vspec2VssConfig,
|
|
66
|
+
data_type_root: Optional[VSSNode] = None) -> None:
|
|
67
|
+
logging.info("Generating CSV output...")
|
|
68
|
+
|
|
69
|
+
# generic entry should be written when both data types and signals are being written to the same file
|
|
70
|
+
generic_entry = data_type_root is not None and config.types_output_file is None
|
|
71
|
+
include_instance_column = not vspec2vss_config.expand_model
|
|
72
|
+
with open(config.output_file, 'w') as f:
|
|
73
|
+
signal_entry_type = "Node" if generic_entry else "Signal"
|
|
74
|
+
print_csv_header(f, vspec2vss_config.generate_uuid, signal_entry_type, include_instance_column)
|
|
75
|
+
print_csv_content(f, signal_root, vspec2vss_config.generate_uuid, include_instance_column)
|
|
76
|
+
if data_type_root is not None and generic_entry is True:
|
|
77
|
+
print_csv_content(f, data_type_root, vspec2vss_config.generate_uuid, include_instance_column)
|
|
78
|
+
|
|
79
|
+
if data_type_root is not None and generic_entry is False:
|
|
80
|
+
with open(config.types_output_file, 'w') as f:
|
|
81
|
+
print_csv_header(f, vspec2vss_config.generate_uuid, "Node", include_instance_column)
|
|
82
|
+
print_csv_content(f, data_type_root, vspec2vss_config.generate_uuid, include_instance_column)
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2022 Contributors to COVESA
|
|
4
|
+
#
|
|
5
|
+
# This program and the accompanying materials are made available under the
|
|
6
|
+
# terms of the Mozilla Public License 2.0 which is available at
|
|
7
|
+
# https://www.mozilla.org/en-US/MPL/2.0/
|
|
8
|
+
#
|
|
9
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
10
|
+
|
|
11
|
+
#
|
|
12
|
+
# Convert vspec files to DDS-IDL
|
|
13
|
+
#
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import keyword
|
|
17
|
+
import logging
|
|
18
|
+
from typing import Optional
|
|
19
|
+
|
|
20
|
+
from vspec.model.vsstree import VSSNode, VSSType
|
|
21
|
+
from vspec.vss2x import Vss2X
|
|
22
|
+
from vspec.vspec2vss_config import Vspec2VssConfig
|
|
23
|
+
|
|
24
|
+
c_keywords = [
|
|
25
|
+
"auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float",
|
|
26
|
+
"for", "goto", "if", "int", "long", "register", "return", "short", "signed", "sizeof", "static", "struct", "switch",
|
|
27
|
+
"typedef", "union", "unsigned", "void", "volatile", "while"
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
# Based on http://www.omg.org/spec/IDL/4.2/
|
|
31
|
+
idl_keywords = [
|
|
32
|
+
"abstract", "any", "alias", "attribute", "bitfield", "bitmask", "bitset", "boolean", "case", "char", "component",
|
|
33
|
+
"connector", "const", "consumes", "context", "custom", "default", "double", "exception", "emits", "enum",
|
|
34
|
+
"eventtype", "factory", "FALSE", "finder", "fixed", "float", "getraises", "home", "import", "in", "inout",
|
|
35
|
+
"interface", "local", "long", "manages", "map", "mirrorport", "module", "multiple", "native", "Object", "octet",
|
|
36
|
+
"oneway", "out", "primarykey", "private", "port", "porttype", "provides", "public", "publishes", "raises",
|
|
37
|
+
"readonly", "setraises", "sequence", "short", "string", "struct", "supports", "switch", "TRUE", "truncatable",
|
|
38
|
+
"typedef", "typeid", "typename", "typeprefix", "unsigned", "union", "uses", "ValueBase", "valuetype", "void",
|
|
39
|
+
"wchar", "wstring", "int8", "uint8", "int16", "int32", "int64", "uint16", "uint32", "uint64"
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def getAllowedName(name):
|
|
44
|
+
if (
|
|
45
|
+
name.lower() in c_keywords
|
|
46
|
+
or name.lower() in idl_keywords
|
|
47
|
+
or keyword.iskeyword(name.lower)
|
|
48
|
+
):
|
|
49
|
+
return "_" + name
|
|
50
|
+
else:
|
|
51
|
+
return name
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def get_allowed_enum_literal(name: str):
|
|
55
|
+
"""
|
|
56
|
+
Check if this is is an allowed literal name, if not add prefix.
|
|
57
|
+
|
|
58
|
+
Background:
|
|
59
|
+
|
|
60
|
+
In VSS '123' is a perfectly fine string literal, usable as allowed value for a string.
|
|
61
|
+
The current exporter (this file) translated it previously to 123 which is not a valid DSS IDL literal.
|
|
62
|
+
Adding an underscore as prefix makes the generated IDL ok, but then gives problems if generating for example
|
|
63
|
+
Python code by Eclipse Cyclone DDS idlc Python Backend.
|
|
64
|
+
By that reason we now add a regular character instead.
|
|
65
|
+
"""
|
|
66
|
+
if name[0].isdigit():
|
|
67
|
+
return "d" + name
|
|
68
|
+
return name
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
idlFileBuffer = []
|
|
72
|
+
|
|
73
|
+
dataTypesMap_covesa_dds = {"uint8": "octet",
|
|
74
|
+
"int8": "octet",
|
|
75
|
+
"uint16": "unsigned short",
|
|
76
|
+
"int16": "short",
|
|
77
|
+
"uint32": "unsigned long",
|
|
78
|
+
"int32": "long",
|
|
79
|
+
"uint64": "unsigned long long",
|
|
80
|
+
"int64": "long long",
|
|
81
|
+
"boolean": "boolean",
|
|
82
|
+
"float": "float",
|
|
83
|
+
"double": "double",
|
|
84
|
+
"string": "string"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def export_node(node, generate_uuid, generate_all_idl_features):
|
|
89
|
+
"""
|
|
90
|
+
This method is used to traverse VSS node and to create corresponding DDS IDL buffer string
|
|
91
|
+
"""
|
|
92
|
+
global idlFileBuffer
|
|
93
|
+
datatype = None
|
|
94
|
+
unit = None
|
|
95
|
+
min = None
|
|
96
|
+
max = None
|
|
97
|
+
defaultValue = None
|
|
98
|
+
allowedValues = None
|
|
99
|
+
arraysize = None
|
|
100
|
+
|
|
101
|
+
if node.type == VSSType.BRANCH:
|
|
102
|
+
idlFileBuffer.append("module " + getAllowedName(node.name))
|
|
103
|
+
idlFileBuffer.append("{")
|
|
104
|
+
for child in node.children:
|
|
105
|
+
export_node(child, generate_uuid, generate_all_idl_features)
|
|
106
|
+
idlFileBuffer.append("};")
|
|
107
|
+
idlFileBuffer.append("")
|
|
108
|
+
else:
|
|
109
|
+
isEnumCreated = False
|
|
110
|
+
# check if there is a need to create enum (based on the usage of allowed values)
|
|
111
|
+
if node.allowed != "":
|
|
112
|
+
"""
|
|
113
|
+
enum should be enclosed under module block to avoid namespec conflict
|
|
114
|
+
module name for enum is chosen as the node name +
|
|
115
|
+
"""
|
|
116
|
+
if (node.datatype.value in ["string", "string[]"]):
|
|
117
|
+
idlFileBuffer.append("module " + getAllowedName(node.name) + "_M")
|
|
118
|
+
idlFileBuffer.append("{")
|
|
119
|
+
idlFileBuffer.append("enum " + getAllowedName(node.name) +
|
|
120
|
+
"Values{"+str(",".join(get_allowed_enum_literal(item) for item in node.allowed)) +
|
|
121
|
+
"};")
|
|
122
|
+
isEnumCreated = True
|
|
123
|
+
idlFileBuffer.append("};")
|
|
124
|
+
allowedValues = str(node.allowed)
|
|
125
|
+
else:
|
|
126
|
+
print(f"Warning: VSS2IDL can only handle allowed values for string type, "
|
|
127
|
+
f"signal {node.name} has type {node.datatype.value}")
|
|
128
|
+
|
|
129
|
+
idlFileBuffer.append("struct " + getAllowedName(node.name))
|
|
130
|
+
idlFileBuffer.append("{")
|
|
131
|
+
if generate_uuid:
|
|
132
|
+
idlFileBuffer.append("string uuid;")
|
|
133
|
+
# fetching value of datatype and obtaining the equivalent DDS type
|
|
134
|
+
try:
|
|
135
|
+
datatype_str = node.get_datatype()
|
|
136
|
+
if node.has_datatype():
|
|
137
|
+
if datatype_str in dataTypesMap_covesa_dds:
|
|
138
|
+
datatype = str(dataTypesMap_covesa_dds[datatype_str])
|
|
139
|
+
elif '[' in datatype_str:
|
|
140
|
+
nodevalueArray = datatype_str.split("[", 1)
|
|
141
|
+
if str(nodevalueArray[0]) in dataTypesMap_covesa_dds:
|
|
142
|
+
datatype = str(dataTypesMap_covesa_dds[str(nodevalueArray[0])])
|
|
143
|
+
arraysize = '[' + str(arraysize) + nodevalueArray[1]
|
|
144
|
+
else: # no primitive type. this is custom
|
|
145
|
+
datatype = datatype_str.replace(".", "::") # custom data type
|
|
146
|
+
|
|
147
|
+
except AttributeError:
|
|
148
|
+
pass
|
|
149
|
+
# fetching value of unit
|
|
150
|
+
try:
|
|
151
|
+
unit = str(node.unit.value)
|
|
152
|
+
except AttributeError:
|
|
153
|
+
pass
|
|
154
|
+
|
|
155
|
+
if node.min != "":
|
|
156
|
+
min = str(node.min)
|
|
157
|
+
if node.max != "":
|
|
158
|
+
max = str(node.max)
|
|
159
|
+
if node.default != "":
|
|
160
|
+
defaultValue = node.default
|
|
161
|
+
if isinstance(defaultValue, str) and not isEnumCreated:
|
|
162
|
+
defaultValue = "\""+defaultValue+"\""
|
|
163
|
+
|
|
164
|
+
if datatype is not None:
|
|
165
|
+
# adding range if min and max are specified in vspec file
|
|
166
|
+
if min is not None and max is not None and generate_all_idl_features:
|
|
167
|
+
idlFileBuffer.append("@range(min=" + str(min) + " ,max=" + str(max) + ")")
|
|
168
|
+
|
|
169
|
+
if allowedValues is None:
|
|
170
|
+
if defaultValue is None:
|
|
171
|
+
idlFileBuffer.append(
|
|
172
|
+
("sequence<" + datatype + "> value" if arraysize is not None else datatype + " value") + ";")
|
|
173
|
+
else:
|
|
174
|
+
# default values in IDL file are not accepted by CycloneDDS/FastDDS :
|
|
175
|
+
# these values can be generated if --all-idl-features is set as True
|
|
176
|
+
idlFileBuffer.append(
|
|
177
|
+
("sequence<" + datatype + "> value" if arraysize is not None else datatype + " value") +
|
|
178
|
+
(" default " + str(defaultValue) if generate_all_idl_features else "") + ";")
|
|
179
|
+
else:
|
|
180
|
+
# this is the case where allowed values are provided, accordingly contents are converted to enum
|
|
181
|
+
if defaultValue is None:
|
|
182
|
+
idlFileBuffer.append(getAllowedName(node.name)+"_M::"+getAllowedName(node.name)+"Values value;")
|
|
183
|
+
else:
|
|
184
|
+
# default values in IDL file are not accepted by CycloneDDS/FastDDS :
|
|
185
|
+
# these values can be generated if --all-idl-features is set as True
|
|
186
|
+
idlFileBuffer.append(
|
|
187
|
+
getAllowedName(node.name) + "_M::" + getAllowedName(node.name) +
|
|
188
|
+
"Values value" + (" " + str(defaultValue) if generate_all_idl_features else "") + ";")
|
|
189
|
+
|
|
190
|
+
if unit is not None:
|
|
191
|
+
idlFileBuffer.append(("" if generate_all_idl_features else "//") + "const string unit=\"" + unit + "\";")
|
|
192
|
+
|
|
193
|
+
idlFileBuffer.append(("" if generate_all_idl_features else "//") + "const string type =\"" +
|
|
194
|
+
str(node.type.value) + "\";")
|
|
195
|
+
|
|
196
|
+
idlFileBuffer.append(("" if generate_all_idl_features else "//") + "const string description=\"" +
|
|
197
|
+
node.description + "\";")
|
|
198
|
+
idlFileBuffer.append("};")
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class StructExporter(object):
|
|
202
|
+
"""
|
|
203
|
+
Helper class used for generating export output for struct data types.
|
|
204
|
+
"""
|
|
205
|
+
|
|
206
|
+
def __init__(self):
|
|
207
|
+
self.str_buf = ""
|
|
208
|
+
self.structs_seen = []
|
|
209
|
+
|
|
210
|
+
def export(self, root) -> str:
|
|
211
|
+
self.str_buf = ""
|
|
212
|
+
self.structs_seen = []
|
|
213
|
+
self.export_data_type_node(root)
|
|
214
|
+
return self.str_buf
|
|
215
|
+
|
|
216
|
+
def export_data_type_node(self, node):
|
|
217
|
+
"""
|
|
218
|
+
This method is used to traverse VSS node and to create corresponding DDS IDL buffer string
|
|
219
|
+
"""
|
|
220
|
+
|
|
221
|
+
prefix = ""
|
|
222
|
+
suffix = ""
|
|
223
|
+
if node.is_branch():
|
|
224
|
+
prefix = f"module {getAllowedName(node.name)}" + " {\n"
|
|
225
|
+
suffix = "};\n"
|
|
226
|
+
elif node.is_struct():
|
|
227
|
+
# check if the properties use structs that have not been seen before
|
|
228
|
+
# if not, add a forward declaration
|
|
229
|
+
fwds = []
|
|
230
|
+
for c in node.children:
|
|
231
|
+
# primtive type
|
|
232
|
+
if c.has_datatype():
|
|
233
|
+
continue
|
|
234
|
+
|
|
235
|
+
datatype_str = c.get_datatype().replace('.', '::').split("[", 1)[0]
|
|
236
|
+
if datatype_str not in self.structs_seen:
|
|
237
|
+
base_type = datatype_str.split("::")[-1]
|
|
238
|
+
fwds.append(base_type)
|
|
239
|
+
|
|
240
|
+
fwds.sort()
|
|
241
|
+
for f in set(fwds):
|
|
242
|
+
prefix += f"struct {f};\n"
|
|
243
|
+
|
|
244
|
+
prefix += f"struct {getAllowedName(node.name)}" + " {\n"
|
|
245
|
+
suffix = "};\n"
|
|
246
|
+
self.structs_seen.append(node.qualified_name("::").split("[", 1)[0])
|
|
247
|
+
else:
|
|
248
|
+
datatype_str = node.get_datatype().replace('.', '::').split("[", 1)[0]
|
|
249
|
+
is_seq = '[' in node.get_datatype()
|
|
250
|
+
if is_seq:
|
|
251
|
+
self.str_buf += f"sequence<{datatype_str}> {getAllowedName(node.name)};\n"
|
|
252
|
+
else:
|
|
253
|
+
self.str_buf += (f"{datatype_str} {getAllowedName(node.name)};\n")
|
|
254
|
+
|
|
255
|
+
self.str_buf += (f"{prefix}")
|
|
256
|
+
|
|
257
|
+
for child in node.children:
|
|
258
|
+
self.export_data_type_node(child)
|
|
259
|
+
self.str_buf += suffix
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def export_idl(file, root, generate_uuids=True, generate_all_idl_features=False):
|
|
263
|
+
"""This method is used to traverse through the root VSS node to build
|
|
264
|
+
-> DDS IDL equivalent string buffer and to serialize it acccordingly into a file
|
|
265
|
+
"""
|
|
266
|
+
export_node(root, generate_uuids, generate_all_idl_features)
|
|
267
|
+
file.write('\n'.join(idlFileBuffer))
|
|
268
|
+
logging.info("IDL file generated at location : " + file.name)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class Vss2DdsIdl(Vss2X):
|
|
272
|
+
|
|
273
|
+
def __init__(self, vspec2vss_config: Vspec2VssConfig):
|
|
274
|
+
vspec2vss_config.no_expand_option_supported = False
|
|
275
|
+
vspec2vss_config.separate_output_type_file_supported = False
|
|
276
|
+
|
|
277
|
+
def add_arguments(self, parser: argparse.ArgumentParser):
|
|
278
|
+
parser.description = "The DDS-IDL exporter"
|
|
279
|
+
parser.add_argument('--all-idl-features', action='store_true',
|
|
280
|
+
help='Generate all features based on DDS IDL 4.2 specification')
|
|
281
|
+
|
|
282
|
+
def generate(self, config: argparse.Namespace, signal_root: VSSNode, vspec2vss_config: Vspec2VssConfig,
|
|
283
|
+
data_type_root: Optional[VSSNode] = None) -> None:
|
|
284
|
+
logging.info("Generating DDS-IDL output...")
|
|
285
|
+
|
|
286
|
+
if data_type_root is not None:
|
|
287
|
+
exporter = StructExporter()
|
|
288
|
+
with open(config.output_file, 'w') as idl_out:
|
|
289
|
+
idl_out.write(exporter.export(data_type_root))
|
|
290
|
+
|
|
291
|
+
with open(config.output_file, 'a' if data_type_root is not None else 'w') as idl_out:
|
|
292
|
+
export_idl(idl_out, signal_root, vspec2vss_config.generate_uuid, config.all_idl_features)
|
|
293
|
+
|
|
294
|
+
def __del__(self):
|
|
295
|
+
idlFileBuffer.clear()
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2021 Contributors to COVESA
|
|
4
|
+
#
|
|
5
|
+
# This program and the accompanying materials are made available under the
|
|
6
|
+
# terms of the Mozilla Public License 2.0 which is available at
|
|
7
|
+
# https://www.mozilla.org/en-US/MPL/2.0/
|
|
8
|
+
#
|
|
9
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
10
|
+
|
|
11
|
+
# Convert vspec tree to franca
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
from typing import Optional
|
|
16
|
+
from vspec.model.vsstree import VSSNode
|
|
17
|
+
from anytree import PreOrderIter # type: ignore[import]
|
|
18
|
+
from vspec.vss2x import Vss2X
|
|
19
|
+
from vspec.vspec2vss_config import Vspec2VssConfig
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# Write the header line
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def print_franca_header(file, version="unknown"):
|
|
26
|
+
file.write(f"""
|
|
27
|
+
// Copyright (C) 2022, COVESA
|
|
28
|
+
//
|
|
29
|
+
// This program is licensed under the terms and conditions of the
|
|
30
|
+
// Mozilla Public License, version 2.0. The full text of the
|
|
31
|
+
// Mozilla Public License is at https://www.mozilla.org/MPL/2.0/
|
|
32
|
+
|
|
33
|
+
const UTF8String VSS_VERSION = "{version}"
|
|
34
|
+
|
|
35
|
+
struct SignalSpec {{
|
|
36
|
+
UInt32 id
|
|
37
|
+
String name
|
|
38
|
+
String type
|
|
39
|
+
String description
|
|
40
|
+
String datatype
|
|
41
|
+
String unit
|
|
42
|
+
Double min
|
|
43
|
+
Double max
|
|
44
|
+
}}
|
|
45
|
+
|
|
46
|
+
const SignalSpec[] signal_spec = [
|
|
47
|
+
""")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# Write the data lines
|
|
51
|
+
def print_franca_content(file, tree, uuid):
|
|
52
|
+
output = ""
|
|
53
|
+
for tree_node in PreOrderIter(tree):
|
|
54
|
+
if tree_node.parent:
|
|
55
|
+
if output:
|
|
56
|
+
output += ",\n{"
|
|
57
|
+
else:
|
|
58
|
+
output += "{"
|
|
59
|
+
output += f"\tname: \"{tree_node.qualified_name('.')}\""
|
|
60
|
+
output += f",\n\ttype: \"{tree_node.type.value}\""
|
|
61
|
+
output += f",\n\tdescription: \"{tree_node.description}\""
|
|
62
|
+
if tree_node.has_datatype():
|
|
63
|
+
output += f",\n\tdatatype: \"{tree_node.get_datatype()}\""
|
|
64
|
+
if uuid:
|
|
65
|
+
output += f",\n\tuuid: \"{tree_node.uuid}\""
|
|
66
|
+
if tree_node.has_unit():
|
|
67
|
+
output += f",\n\tunit: \"{tree_node.get_unit()}\""
|
|
68
|
+
if tree_node.min:
|
|
69
|
+
output += f",\n\tmin: {tree_node.min}"
|
|
70
|
+
if tree_node.max:
|
|
71
|
+
output += f",\n\tmax: {tree_node.max}"
|
|
72
|
+
if tree_node.allowed:
|
|
73
|
+
output += f",\n\tallowed: {tree_node.allowed}"
|
|
74
|
+
|
|
75
|
+
output += "\n}"
|
|
76
|
+
file.write(f"{output}")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class Vss2Franca(Vss2X):
|
|
80
|
+
|
|
81
|
+
def __init__(self, vspec2vss_config: Vspec2VssConfig):
|
|
82
|
+
vspec2vss_config.no_expand_option_supported = False
|
|
83
|
+
vspec2vss_config.type_tree_supported = False
|
|
84
|
+
|
|
85
|
+
def add_arguments(self, parser: argparse.ArgumentParser):
|
|
86
|
+
# Renamed from -v to --franca-vss-version to avoid conflict when using
|
|
87
|
+
# -vt (Otherwise -vt would be interpreted as "-v t")
|
|
88
|
+
parser.add_argument('--franca-vss-version', metavar='franca_vss_version',
|
|
89
|
+
help=" Add version information to franca file.")
|
|
90
|
+
|
|
91
|
+
def generate(self, config: argparse.Namespace, signal_root: VSSNode, vspec2vss_config: Vspec2VssConfig,
|
|
92
|
+
data_type_root: Optional[VSSNode] = None) -> None:
|
|
93
|
+
print("Generating Franca output...")
|
|
94
|
+
outfile = open(config.output_file, 'w')
|
|
95
|
+
print_franca_header(outfile, config.franca_vss_version)
|
|
96
|
+
print_franca_content(outfile, signal_root, vspec2vss_config.generate_uuid)
|
|
97
|
+
outfile.write("\n]")
|
|
98
|
+
outfile.close()
|