Skip to content

Commit

Permalink
docs: Update Message Layout docs
Browse files Browse the repository at this point in the history
  • Loading branch information
huyenngn committed Jan 18, 2024
1 parent 38cd28a commit d866404
Show file tree
Hide file tree
Showing 8 changed files with 703 additions and 403 deletions.
21 changes: 4 additions & 17 deletions capella_ros_tools/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from capella_ros_tools.snapshot import app


@click.group(context_settings={"default_map": {}})
@click.group()
@click.version_option(
version=capella_ros_tools.__version__,
prog_name="capella-ros-tools",
Expand All @@ -25,20 +25,16 @@ def cli():


@cli.command("import")
@click.argument(
"msg_path", type=str, required=True, help="Path to ROS messages."
)
@click.argument("msg_path", type=str, required=True)
@click.argument(
"capella_path",
type=click.Path(path_type=Path),
required=True,
help="Path to Capella model.",
)
@click.argument(
"layer",
type=click.Choice(["oa", "la", "sa", "pa"], case_sensitive=False),
required=True,
help="Layer of Capella data package.",
)
@click.option(
"--exists-action",
Expand Down Expand Up @@ -86,25 +82,16 @@ def import_msg(
required=True,
)
@click.argument("msg_path", type=click.Path(path_type=Path), required=True)
@click.option(
"--exists-action",
"action",
type=click.Choice(
["keep", "overwrite", "abort", "ask"], case_sensitive=False
),
default="ask" if sys.stdin.isatty() else "abort",
help="Default action when an element already exists.",
)
def export_capella(
capella_path: t.Any,
msg_path: Path,
layer: str,
msg_path: Path,
):
"""Export Capella data package to ROS messages."""
if not Path(capella_path).exists():
capella_path = capellambse.filehandler.get_filehandler(capella_path)

converter: t.Any = capella2msg.Converter(capella_path, msg_path, layer)
converter: t.Any = capella2msg.Converter(msg_path, capella_path, layer)
converter.convert()


Expand Down
4 changes: 2 additions & 2 deletions capella_ros_tools/modules/messages/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,12 @@ def from_msg_string(cls, msg_name: str, message_string: str):
# line contains a constant
value = value.lstrip()
if not isinstance(last_element, ConstantDef):
msg.enums.append(EnumDef("", [], current_comments))
msg.enums.append(EnumDef("", [], []))
msg.enums[-1].values.append(
ConstantDef(TypeDef(type_string), name, value, [comment])
)
last_element = msg.enums[-1].values[-1]
msg.enums[-1].annotations += current_comments
else:
# line contains a field
msg.fields.append(
Expand Down Expand Up @@ -254,7 +255,6 @@ def _process_enums(msg):
field.type.name = enum.name
return

for field in msg.fields:
if field.type.name == enum.values[0].type.name:
# enum type is the same as the field type
field.type.name = msg.name + _get_enum_identifier(field.name)
Expand Down
2 changes: 1 addition & 1 deletion capella_ros_tools/scripts/capella2msg.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ class Converter:

def __init__(
self,
capella_path: t.Any,
msg_path: t.Any,
capella_path: t.Any,
layer: str,
) -> None:
self.msg_path = msg_path
Expand Down
2 changes: 1 addition & 1 deletion docs/source/examples/Export capella.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
}
],
"source": [
"converter = capella2msg.Converter(msg_path, capella_path, layer, \"o\", False)"
"converter = capella2msg.Converter(msg_path, capella_path, layer)"
]
},
{
Expand Down
950 changes: 613 additions & 337 deletions docs/source/examples/Import messages.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/source/howtos/howtos.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Export Capella Model (experimental):
------------------------------------
.. code-block:: bash
$ python -m capella_ros_tools export docs/source/examples/data/melody_model_60 la docs/source/examples/data/example_msgs
$ python -m capella_ros_tools export docs/source/examples/data/melody_model_60 la docs/source/examples/data/melody_msgs
Export Capella Model from Git Repository (experimental):
--------------------------------------------------------
Expand Down
97 changes: 66 additions & 31 deletions docs/source/messages/messages.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@ ROS2 Message Layout

The Capella ROS Tools API expects ROS2 messages to be organized in a specific way:

Class definition
=================
Class Definition
================
* A `.msg` file can contain one class definition.
* Comments at the top of the file are appended to the class description.
* **Inline Comments:** Comments on the same line as a property definition are directly appended to that property's description.
* **Indented Comment Lines:** Comments on a line of their own but indented are appended to the description of the last encountered property.
* **Block Comments:** Comments on a line of their own and not indented are prepended to the description of the next properties until an empty line or a new block comment is encountered.
* **Unused Comments:** If a block comment has no properties after it before the next empty line or block comment, it is added to the class description itself.

.. code-block:: python
:linenos:
# MyClass.msg
# The first comment block at the top of the file
Expand All @@ -26,29 +32,40 @@ Class definition
# This block comment is appended to
# class description of MyClass.
# This block comment is appended to the
# property description of my_other_field.
uint8 my_other_field # This inline comment
# is appended to the
# property description of
# my_other_field.
# This block comment is appended to the property descriptions
# of my_other_field and my_third_field.
uint8 my_other_field # This inline comment
# is appended to the
# property description of
# my_other_field.
uint8 my_third_field
Enum definition
===============
* A `.msg` file can contain multiple enum definitions.
* Multiple enum definitions are separated by an empty line.
* Enum names are determined based on the longest common prefix of all enum values in the definition.
* If no common prefix exists, the enum name is derived from the file name (excluding the extension).
* Only one or no enum should have value names without a common prefix.
* Comments at the top of the file and unused comments are ignored.
* **Inline Comments:** Comments on the same line as an enum value definition are directly appended to the that enum value's description.
* **Indented Comment Lines:** Comments on a line of their own but indented are appended to the description of the last encountered enum value.
* **Block Comments:** Comments on a line of their own and not indented are appended to the description of the next/current enum definition until an empty line or a new block comment is encountered.

.. code-block:: python
:linenos:
# MyEnum.msg
# This block comment is appended to the
# enum description of MyEnumMyEnumValue.
uint8 MY_ENUM_VALUE_RED = 0
uint8 MY_ENUM_VALUE_BLUE = 1 # This inline comment is
# appended to the
# enum value description
# of BLUE.
# enum description of MyEnumValue.
uint8 MY_ENUM_VALUE_RED = 0
uint8 MY_ENUM_VALUE_BLUE = 1 # This inline comment is
# appended to the
# enum value description
# of BLUE.
# This block comment is also appended to the
# enum description of MyEnumValue.
uint8 MY_ENUM_VALUE_YELLOW = 2
uint8 MY_ENUM_VALUE_GREEN = 3
# This block comment is appended to the
# enum description of MyEnum.
Expand All @@ -59,10 +76,18 @@ Enum definition
byte ERROR = 2
byte STALE = 3
Enum and class definition
Enum and Class Definition
=========================
* A `.msg` file can contain one class definition and multiple enum definitions.
* Enums without a common value name prefix are named using the file name plus the suffix "Type."
* There can only be one or no enum whose value names do not share a common prefix.
* Comments at the top of the file are appended to the class description.
* **Inline Comments:** Comments on the same line as a property or enum value are directly appended to the description of that element.
* **Indented Comment Lines:** Comments on a line of their own but indented are appended to the description of the last encountered property or enum value.
* **Block Comments:** Comments on a line of their own and not indented are prepended to the descriptions of the next properties or appended to the descriptions of the next/current enum until an empty line or a new block comment is encountered.
* **Unused Comments:** If a block comment has no following properties or enums before the next empty line or block comment, it is added to the class description.

.. code-block:: python
:linenos:
# MyMessage.msg
# The first comment block at the top of the file
Expand All @@ -80,35 +105,46 @@ Enum and class definition
Referencing enums
=================

In the same file
In the Same File
----------------
* In files that define a class along with enums, the class properties can reference enums defined in the same file. This can be achieved in two ways:

* **Name Match:** The property name matches the enum name.
* **Type Match:** The property type matches the enum values type, in which case the updated enum name is derived from the file name plus the property name.

* Name matching takes precedence over type matching.

.. code-block:: python
:linenos:
# MyMessage.msg
# Fields in MyMessage can reference enums in the same file.
# Properties in MyMessage can reference enums in the same file.
# This block comment is appended to the
# enum description of MyMessageType.
# enum description of MyMessageStatus.
byte OK = 0
byte WARN = 1
byte ERROR = 2
byte STALE = 3
# This block comment is appended to the
# enum description of MyMessageColor.
byte COLOR_RED = 0
# enum description of Color.
byte COLOR_RED = 0
byte COLOR_BLUE = 1
byte COLOR_YELLOW = 2
byte COLOR_YELLOW = 2
byte my_field # The property my_field is of type MyMessageType
uint8 color # The property color is of type MyMessageColor
byte status # The property status is of type MyMessageStatus
byte color # The property color is of type Color
In another file
---------------
* If a property definition has a primitive type, it searches for a reference to an enum in the comments and updates the type of the property based on this reference.
* The reference should follow either of the following formats:

* **cf. <File Name>:** The enum name is derived from the file name (excluding the extension).
* **cf. <File Name>, <Common Prefix>_XXX:** The enum name is derived from the longest common prefix of all enum values in the definition.

.. code-block:: python
:linenos:
# MyEnum.msg
# This block comment is appended to the
Expand All @@ -119,13 +155,12 @@ In another file
byte STALE = 3
# This block comment is appended to the
# enum description of MyEnumMyEnumValue.
# enum description of MyEnumValue.
uint8 MY_ENUM_VALUE_1 = 0
uint8 MY_ENUM_VALUE_2 = 1
uint8 MY_ENUM_VALUE_3 = 2
.. code-block:: python
:linenos:
# MyMessage.msg
# Fields in MyMessage can reference enums in MyEnum.
Expand Down
28 changes: 15 additions & 13 deletions docs/source/usage/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,25 @@ Import ROS2 Messages:
$ python -m capella_ros_tools import <ROS_MESSAGES_PATH> <CAPELLA_MODEL_PATH> <CAPELLA_MODEL_LAYER> --port=<PORT> --exists-action=<EXISTS_ACTION> --no-deps
* "<ROS_MESSAGES_PATH>", import ROS2 messages from <ROS_MESSAGES_PATH>
* "<CAPELLA_MODEL_PATH>", export to Capella model <CAPELLA_MODEL_PATH>
* "<CAPELLA_MODEL_LAYER>", use Capella model layer <CAPELLA_MODEL_LAYER>
* "--port=<PORT>", start Capella model server at <PORT> (optional)
* "--exists-action=<EXISTS_ACTION>", action to take if a Capella element already exists (optional)
* "skip", skip elements
* "replace", replace elements
* "abort", abort import
* "ask", ask the user (default)
* "--no-deps", do not import ROS2 dependencies (e.g. std_msgs)
* **<ROS_MESSAGES_PATH>**, import ROS2 messages from <ROS_MESSAGES_PATH>
* **<CAPELLA_MODEL_PATH>**, export to Capella model <CAPELLA_MODEL_PATH>
* **<CAPELLA_MODEL_LAYER>**, use Capella model layer <CAPELLA_MODEL_LAYER>
* **--port=<PORT>**, start Capella model server at <PORT> (optional)
* **--exists-action=<EXISTS_ACTION>**, action to take if a Capella element already exists (optional)

* **skip**, skip elements
* **replace**, replace elements
* **abort**, abort import
* **ask**, ask the user (default)

* **--no-deps**, do not import ROS2 dependencies (e.g. std_msgs)

Export Capella Model (experimental):
------------------------------------
.. code-block:: bash
$ python -m capella_ros_tools export <CAPELLA_MODEL_PATH> <CAPELLA_MODEL_LAYER> <ROS_MESSAGES_PATH>
* "<CAPELLA_MODEL_PATH>", import Capella model from <CAPELLA_MODEL_PATH>
* "<CAPELLA_MODEL_LAYER>", use Capella model layer <CAPELLA_MODEL_LAYER>
* "<ROS_MESSAGES_PATH>", export ROS2 messages to <ROS_MESSAGES_PATH>
* **<CAPELLA_MODEL_PATH>**, import Capella model from <CAPELLA_MODEL_PATH>
* **<CAPELLA_MODEL_LAYER>**, use Capella model layer <CAPELLA_MODEL_LAYER>
* **<ROS_MESSAGES_PATH>**, export ROS2 messages to <ROS_MESSAGES_PATH>

0 comments on commit d866404

Please sign in to comment.