Skip to content

Commit

Permalink
Merge pull request #202 from vladmu/master
Browse files Browse the repository at this point in the history
#203 SDL-0234 Proxy Library RPC Generation
  • Loading branch information
Jack-Byrne committed Feb 5, 2020
2 parents c87eb00 + 8bda291 commit bf14662
Show file tree
Hide file tree
Showing 42 changed files with 2,774 additions and 606 deletions.
10 changes: 10 additions & 0 deletions .gitignore
@@ -0,0 +1,10 @@
.idea
*.iml
*venv*
*.pyc
*out
.DS_Store
*htmlcov
*.coverage
*__pycache__
*.pytest_cache
136 changes: 136 additions & 0 deletions InterfaceParser/README.md
@@ -0,0 +1,136 @@
# Requirements

The parser requires Python 3.5 pre-installed in the system. This is the minimal Python 3 version that has not reached the end-of-life (https://devguide.python.org/devcycle/#end-of-life-branches).

The parser requires `xmlschema` library in order to provide the required schema validation. Additionally `pylint` and `coverage` libraries are required for unit tests.

Those libraries are described in `requirements.txt` and should be pre-installed by the command:
```shell script
pip install -r requirements.txt
```

# Parser types
Different parser types implemented in Interface Parser for parsing different types of source XML and generating the code in SDL_core project.

Parser | Source file
------ | ------
sdlrpcv1 | sdl_core/src/components/interfaces/v4_protocol_v1_2_no_extra.xml
sdlrpcv2 | sdl_core/src/components/interfaces/MOBILE_API.xml
jsonrpc | sdl_core/src/components/interfaces/HMI_API.xml
mobile-policy-types | sdl_core/src/components/interfaces/MOBILE_API.xml
hmi-policy-types | sdl_core/src/components/interfaces/HMI_API.xml

# `MOBILE_RPC.xml` structure

## Overview
This document contains the description of the `MOBILE_API.xml` structure in order of preparation specification and transformation rules for Proxy Library RPC Generation. This is not a full XML specification and only elements and attributes required for the code generation are described here. For the full specification see MOBILE_API.xsd.

## `<interface>`
The root element is the `<interface>`. The `<interface>` contains any number of `<enum>`, `<struct>` and `<function>`.

Example:
```xml
<interface name="string" version="string" minVersion="string" date="string">
<!--Zero or more repetitions:-->
<enum/>
<!--Zero or more repetitions:-->
<struct/>
<!--Zero or more repetitions:-->
<function/>
</interface>
```

## `<enum>`
The `<enum>` element contains any number of `<element>` that represents a set of possible values. The `<enum>` has a required `"name"` attribute.

Example:
```xml
<enum deprecated="boolean" internal_scope="string" name="string" platform="string" since="string" until="string">
<!--Zero or more repetitions:-->
<description>string</description>
<!--Zero or more repetitions:-->
<element hexvalue="string" internal_name="string" name="string" rootscreen="boolean" since="string" value="integer">
<!--Zero or more repetitions:-->
<description>string</description>
<!--Zero or more repetitions:-->
<warning>string</warning>
</element>
<!--Optional:-->
<history>
<enum/>
</history>
</enum>
```
SDL has two different enum types: `string` and `integer`. If `"hexvalue"` or `"value"` attribute exists, the enum type is `integer`, otherwise the enum type is `string`.

The `<element>` has a required `"name"` attribute. For `string` enums, the value of `"name"` attribute will be one of the possible values of the particular `<enum>`. For `integer` enums, the value of `"value"` attribute will be one of the possible values, the `"hexvalue"` is just a hexadecimal representation of the `"value"` attribute, any of them could be used but `"hexvalue"` is preferred if exist.

Additionally, `<element>` could have an `"internal_name"` attribute. This helper attribute is not used in communication with SDL Core and describes the `<element>` name for SDL libraries. The actual naming of `<element>` in libraries is per the following rationale: If the `<element>` has an `"internal_name"` attribute, all libraries should name the `<element>` based on this attribute. If `"internal_name"` is not specified, the libraries should name the `<element>` based on the `"name"` attribute. There are possible additional rules, e.g., for `internal_name="SamplingRate_8KHZ"` to cut the leading `<enum>` name, but those rules must be individually specified per each library.

## `<struct>`
The `<struct>` is a complex data type. The `<struct>` contains any number of `<param>`. The `<struct>` has a required `"name"` attribute.

Example:
```xml
<struct deprecated="boolean" name="string" since="string" until="string">
<!--Optional:-->
<history>
<struct/>
</history>
<!--Zero or more repetitions:-->
<description>string</description>
<!--Zero or more repetitions:-->
<param array="boolean" defvalue="integer|decimal|boolean|string" deprecated="boolean" mandatory="boolean" maxlength="integer" maxsize="integer" maxvalue="decimal" minlength="integer" minsize="integer" minvalue="decimal" name="string" since="string" type="string" until="string">
<!--Zero or more repetitions:-->
<description>string</description>
<!--Optional:-->
<history>
<param/>
</history>
</param>
</struct>
```
Each `<param>` requires `"name"`, `"type"` and `"mandatory"` attributes. The `"type"` attribute value should be one of `"Boolean"`, `"Float"`, `"Integer"`, `"String"` or the one of `<enum>`, `<struct>` name specified in the Mobile API.

Additionally, `<param>` could have `"array"` attribute to represent an array of values or objects of the described type. Attributes `"maxsize"` and `"minsize"` provide additional restrictions to an array.

Numeric types can be restricted using `"minvalue"` and `"maxvalue"`. The `"defvalue"` attribute contains default value with different type, depends on `<param>` type, note: this attribute is not allowed for `<struct>` type.

## `<function>`
The `<function>` element represents a specific RPC and message type of the Mobile API. It contains any number of `<param>`. The `<function>` has a required `"name"`, `"messagetype"`, `"functionID"` attributes.

Example:
```xml

<function deprecated="boolean" functionID="string" messagetype="string" name="string" since="string" until="string">
<!--Optional:-->
<history>
<function/>
</history>
<!--Zero or more repetitions:-->
<description>string</description>
<!--Zero or more repetitions:-->
<param array="boolean" defvalue="integer|decimal|boolean|string" deprecated="boolean" mandatory="boolean" maxlength="integer" maxsize="integer" maxvalue="decimal" minlength="integer" minsize="integer" minvalue="decimal" name="string" platform="string" since="string" type="string" until="string">
<!--Zero or more repetitions:-->
<description>string</description>
<!--Optional:-->
<history>
<param/>
</history>
<!--Zero or more repetitions:-->
<todo>string</todo>
<!--Zero or more repetitions:-->
<element name="string">
<!--Optional:-->
<description>string</description>
</element>
</param>
</function>
```
The `"messagetype"` attribute value should be one of `"request"`, `"response"`, or `"notification"`. The `"functionID"` attribute value should match the `"name`" attribute of one `<element>` of the `<enum>` named `"FunctionID"`.

Just like `<param>` elements in `<struct>`, each `<param>` has required `"name"`, `"type"`, and `"mandatory"` attributes. The `"type"` attribute value should be one of `"Boolean"`, `"Float"`, `"Integer"`, `"String"` or the one of `<enum>`, `<struct>` name exists in XML.

Additionally, `<param>` could have `"array"` attribute which means the param represents array of described types. Attributes `"max*"` and `"min*"` provide additional restrictions. The `"defvalue"` attribute contains default value with different type, depends on `<param>` type, note: this attribute is not allowed for `<struct>` type.

The `<param>` with `<enum>` type could additionally contain any number of `<element>` (but not more than the number of `<element>` in the related `<enum>`). The `<element>` has required `"name"` attribute and this should match the one of `<element>`'s `"name"` or `"internal_name"` attribute in the related `<enum>`. This restricts the represented value by the defined list of `<element>` instead of the full list of `<element>` in the related `<enum>`.
Empty file.
18 changes: 18 additions & 0 deletions InterfaceParser/model/array.py
@@ -0,0 +1,18 @@
"""Array type.
"""


class Array:
"""Array type.
:param min_size: minimum array size
:param max_size: maximum array size
:param element_type: type of array element
"""

def __init__(self, min_size=None, max_size=None, element_type=None):
self.min_size = min_size
self.max_size = max_size
self.element_type = element_type
14 changes: 14 additions & 0 deletions InterfaceParser/model/boolean.py
@@ -0,0 +1,14 @@
"""Boolean type.
"""


class Boolean:
"""Boolean type.
:param default_value: default value
"""

def __init__(self, default_value=None):
self.default_value = default_value
40 changes: 40 additions & 0 deletions InterfaceParser/model/enum.py
@@ -0,0 +1,40 @@
"""Enumeration.
"""
from collections import OrderedDict

from model.interface_item_base import InterfaceItemBase


class Enum(InterfaceItemBase):
"""Enumeration.
:param name: item name
:param description: list of string description elements
:param design_description: list of string design description elements
:param issues: list of issues
:param todos: list of string todo elements
:param platform: optional platform (string or None)
:param scope: optional scope: internal, partner or none (none by default, means public)
:param since: string that defines the rpc spec version an element was introduced
:param until: string that defines the rpc spec version an element was removed, deprecated, or changed
:param deprecated: boolean that defines if an element is planned to be removed in a future release
:param removed: boolean that defines if an element was removed from the api
:param history: array of api element signature changes
:param internal_scope: optional internal scope
:param elements: dictionary of enumeration elements (instances of EnumElement class)
"""

def __init__(self, name, description=None, design_description=None,
issues=None, todos=None, platform=None, internal_scope=None,
elements=None, scope=None, since=None, until=None,
deprecated=None, removed=None, history=None):
super(Enum, self).__init__(
name, description=description, design_description=design_description,
issues=issues, todos=todos, platform=platform, scope=scope,
since=since, until=until, deprecated=deprecated, removed=removed, history=history)

self.internal_scope = internal_scope
self.elements = elements if elements is not None else OrderedDict()
51 changes: 51 additions & 0 deletions InterfaceParser/model/enum_element.py
@@ -0,0 +1,51 @@
"""Element of enumeration.
"""

from model.interface_item_base import InterfaceItemBase


class EnumElement(InterfaceItemBase):
"""Element of enumeration.
:param name: item name
:param description: list of string description elements
:param design_description: list of string design description elements
:param issues: list of issues
:param todos: list of string todo elements
:param platform: optional platform (string or None)
:param since: string that defines the rpc spec version an element was introduced
:param until: string that defines the rpc spec version an element was removed, deprecated, or changed
:param deprecated: boolean that defines if an element is planned to be removed in a future release
:param removed: boolean that defines if an element was removed from the api
:param history: array of api element signature changes
:param internal_name: internal name of an element must be used by a
generator if it is provided (not None)
:param value: optional element value
:param hex_value: optional element hex value
"""

def __init__(self, name, description=None, design_description=None,
issues=None, todos=None, platform=None, internal_name=None,
value=None, hex_value=None, since=None, until=None,
deprecated=None, removed=None, history=None):
super(EnumElement, self).__init__(
name, description=description, design_description=design_description,
issues=issues, todos=todos, platform=platform, since=since,
until=until, deprecated=deprecated, removed=removed, history=history)

self.internal_name = internal_name
self.value = value
self.hex_value = hex_value

@property
def primary_name(self):
"""Primary name of the EnumElement.
Return the 'internal_name' property if presented or 'name' property
otherwise.
"""
return self.name if self.internal_name is None else self.internal_name
38 changes: 38 additions & 0 deletions InterfaceParser/model/enum_subset.py
@@ -0,0 +1,38 @@
"""Enumeration subset.
"""

from model.interface_item_base import InterfaceItemBase


class EnumSubset(InterfaceItemBase):
"""Enumeration subset.
:param name: item name
:param description: list of string description elements
:param design_description: list of string design description elements
:param issues: list of issues
:param todos: list of string todo elements
:param platform: optional platform (string or None)
:param since: string that defines the rpc spec version an element was introduced
:param until: string that defines the rpc spec version an element was removed, deprecated, or changed
:param deprecated: boolean that defines if an element is planned to be removed in a future release
:param removed: boolean that defines if an element was removed from the api
:param history: array of api element signature changes
:param enum: enumeration
:param allowed_elements: dictionary of elements of enumeration
which are allowed in this subset
"""

def __init__(self, name, enum, description=None, design_description=None,
issues=None, todos=None, platform=None, allowed_elements=None,
since=None, until=None, deprecated=None, removed=None, history=None):
super(EnumSubset, self).__init__(
name, description=description, design_description=design_description,
issues=issues, todos=todos, platform=platform,
since=since, until=until, deprecated=deprecated, removed=removed, history=history)

self.enum = enum
self.allowed_elements = allowed_elements if allowed_elements is not None else {}
18 changes: 18 additions & 0 deletions InterfaceParser/model/float.py
@@ -0,0 +1,18 @@
"""Floating-point type.
"""


class Float:
"""Floating-point type.
:param min_value: minimum allowed value
:param max_value: maximum allowed value
:param default_value: default value
"""

def __init__(self, min_value=None, max_value=None, default_value=None):
self.min_value = min_value
self.max_value = max_value
self.default_value = default_value
44 changes: 44 additions & 0 deletions InterfaceParser/model/function.py
@@ -0,0 +1,44 @@
"""Function.
"""

from collections import OrderedDict

from model.interface_item_base import InterfaceItemBase


class Function(InterfaceItemBase):
"""Function.
:param name: item name
:param description: list of string description elements
:param design_description: list of string design description elements
:param issues: list of issues
:param todos: list of string todo elements
:param platform: optional platform (string or None)
:param scope: optional scope: internal, partner or none (none by default, means public).
Note exists only in the hmi_api.xml
:param since: string that defines the rpc spec version an element was introduced
:param until: string that defines the rpc spec version an element was removed, deprecated, or changed
:param deprecated: boolean that defines if an element is planned to be removed in a future release
:param removed: boolean that defines if an element was removed from the api
:param history: array of api element signature changes
:param function_id: function identifier (EnumElement from Enum "FunctionID")
:param message_type: message type (EnumElement from Enum "messageType")
:param params: dictionary of function parameters (instances of FunctionParam class)
"""

def __init__(self, name, function_id, message_type, description=None,
design_description=None, issues=None, todos=None,
platform=None, params=None, scope=None, since=None, until=None, deprecated=None, removed=None,
history=None):
super(Function, self).__init__(
name, description=description, design_description=design_description,
issues=issues, todos=todos, platform=platform, scope=scope,
since=since, until=until, deprecated=deprecated, removed=removed, history=history)

self.function_id = function_id
self.message_type = message_type
self.params = params if params is not None else OrderedDict()
16 changes: 16 additions & 0 deletions InterfaceParser/model/integer.py
@@ -0,0 +1,16 @@
"""Integer type.
"""


class Integer:
"""Integer type.
:param min_value: minimum allowed value
:param max_value: maximum allowed value
:param default_value: default value
"""

def __init__(self, min_value=None, max_value=None, default_value=None):
self.min_value = min_value
self.max_value = max_value
self.default_value = default_value

0 comments on commit bf14662

Please sign in to comment.