ltcodecs 4.2.0__tar.gz → 4.3.0__tar.gz
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.
- ltcodecs-4.3.0/.gitlab-ci.yml +65 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/PKG-INFO +1 -1
- ltcodecs-4.3.0/docs/codec_configs.rst +284 -0
- ltcodecs-4.3.0/docs/index.rst +26 -0
- ltcodecs-4.3.0/docs/quickstart.rst +230 -0
- ltcodecs-4.2.0/docs/index.rst → ltcodecs-4.3.0/docs/reference/codec_aliases.rst +25 -17
- ltcodecs-4.3.0/docs/reference/codecs.rst +109 -0
- ltcodecs-4.3.0/docs/reference/config_schema.rst +152 -0
- ltcodecs-4.2.0/docs/ltcodecs.rst → ltcodecs-4.3.0/docs/reference/python_api.rst +24 -5
- ltcodecs-4.3.0/docs/requirements.txt +3 -0
- ltcodecs-4.3.0/docs/ros_messages.rst +203 -0
- ltcodecs-4.3.0/docs/tests.rst +21 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/__init__.py +5 -0
- ltcodecs-4.3.0/src/ltcodecs/dict_codec.py +184 -0
- ltcodecs-4.3.0/src/ltcodecs/dict_field_codec.py +158 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/exponentialgolomb_integer_codec.py +1 -1
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/fixed_len_array_codec.py +14 -5
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/fixedint_codec.py +19 -10
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/float_codec.py +19 -5
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/ieee_float_codec.py +15 -7
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/linspace_float_codec.py +19 -4
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/optional_field_codec.py +19 -15
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/padding_codec.py +12 -5
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/ros_message_codec.py +55 -7
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/ros_msg_field_codec.py +143 -65
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/string_codecs.py +22 -5
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/variable_len_array_codec.py +21 -9
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/varint_codec.py +21 -5
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs.egg-info/PKG-INFO +1 -1
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs.egg-info/SOURCES.txt +14 -3
- ltcodecs-4.3.0/src/ltcodecs.egg-info/scm_file_list.json +55 -0
- ltcodecs-4.3.0/src/ltcodecs.egg-info/scm_version.json +8 -0
- ltcodecs-4.3.0/tests/dict_codec.yaml +19 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/tests/test_codecs.py +82 -15
- ltcodecs-4.3.0/tests/test_dict_codec.py +104 -0
- ltcodecs-4.2.0/.gitlab-ci.yml +0 -114
- ltcodecs-4.2.0/docs/auto-docs.Dockerfile +0 -28
- ltcodecs-4.2.0/docs/tests.rst +0 -21
- ltcodecs-4.2.0/tests/tests.Dockerfile +0 -6
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/.gitignore +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/.gitlab/merge_request_templates/Default.md +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/CONTRIBUTING.md +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/LICENSE +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/README.md +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/docs/Makefile +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/docs/conf.py +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/pyproject.toml +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/requirements.txt +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/setup.cfg +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/bool_codec.py +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/bytes_codec.py +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/ccl_latlon_bcd_codec.py +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/ccl_latlon_codec.py +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/exceptions.py +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/field_codec.py +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/lzma_codec.py +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/multiple_field_codec.py +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/rostime_codec.py +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs/string_enum_codec.py +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs.egg-info/dependency_links.txt +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs.egg-info/requires.txt +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/src/ltcodecs.egg-info/top_level.txt +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/tests/__init__.py +0 -0
- {ltcodecs-4.2.0 → ltcodecs-4.3.0}/tests/string_msg_codec.yaml +0 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
include:
|
|
2
|
+
- project: acomms/ci_templates
|
|
3
|
+
ref: v2.3.2
|
|
4
|
+
file:
|
|
5
|
+
- /templates/python-docs.yml
|
|
6
|
+
- /templates/python-tests.yml
|
|
7
|
+
|
|
8
|
+
workflow:
|
|
9
|
+
rules:
|
|
10
|
+
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
11
|
+
when: always
|
|
12
|
+
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"'
|
|
13
|
+
when: never
|
|
14
|
+
- if: '$CI_COMMIT_BRANCH || $CI_COMMIT_TAG'
|
|
15
|
+
when: always
|
|
16
|
+
|
|
17
|
+
stages:
|
|
18
|
+
- prepare
|
|
19
|
+
- test
|
|
20
|
+
- deploy
|
|
21
|
+
|
|
22
|
+
variables:
|
|
23
|
+
PYTHON_DOCS_PDF_ARTIFACT: "ltcodecs.pdf"
|
|
24
|
+
PYTHON_DOCS_PDF_SOURCE: "docs/_build/latex/ltcodecs.pdf"
|
|
25
|
+
|
|
26
|
+
ROS_ACOMMS_REF: "devel"
|
|
27
|
+
|
|
28
|
+
PYTHON_PYTEST_ARGS: "-vv -rA --capture=tee-sys"
|
|
29
|
+
PYTHON_PYTEST_COVERAGE_ARGS: "--cov=ltcodecs"
|
|
30
|
+
PYTHON_PYTEST_TARGET: "tests/"
|
|
31
|
+
|
|
32
|
+
native_tests:
|
|
33
|
+
extends: .armw_native_pytest_template
|
|
34
|
+
variables:
|
|
35
|
+
NATIVE_TEST_SETUP_COMMANDS: |
|
|
36
|
+
pip install .
|
|
37
|
+
|
|
38
|
+
trigger-ros_acomms-pipeline:
|
|
39
|
+
stage: test
|
|
40
|
+
trigger:
|
|
41
|
+
project: acomms/ros_acomms
|
|
42
|
+
branch: $ROS_ACOMMS_REF
|
|
43
|
+
strategy: depend
|
|
44
|
+
variables:
|
|
45
|
+
LTCODEC_REF: $CI_COMMIT_SHA
|
|
46
|
+
PYACOMMS_REF: $PYACOMMS_REF
|
|
47
|
+
ARMW_REF: $ARMW_REF
|
|
48
|
+
ROS_SKIP_WORKSPACE_BUILD_IN_PIPELINES: "false"
|
|
49
|
+
ROS_SKIP_WORKSPACE_BUILD_ON_DEV_AUTODOCS: "false"
|
|
50
|
+
rules:
|
|
51
|
+
- if: '$CI_PIPELINE_SOURCE != "pipeline"'
|
|
52
|
+
|
|
53
|
+
pypi:
|
|
54
|
+
image: python:3.12
|
|
55
|
+
stage: deploy
|
|
56
|
+
script:
|
|
57
|
+
- pip install -r requirements.txt
|
|
58
|
+
- pip install build twine
|
|
59
|
+
- python -m build
|
|
60
|
+
- twine upload --username __token__ --password $PYPI_TOKEN dist/*
|
|
61
|
+
artifacts:
|
|
62
|
+
paths:
|
|
63
|
+
- dist/
|
|
64
|
+
only:
|
|
65
|
+
- tags
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
Codec Configurations
|
|
2
|
+
====================
|
|
3
|
+
|
|
4
|
+
Most ``ltcodecs`` applications are configured with a field dictionary. In
|
|
5
|
+
Python this is a nested ``dict``. In files it is usually written as YAML.
|
|
6
|
+
Each top-level key is a field name, and each value is a mapping of parameters
|
|
7
|
+
for the codec that encodes that field.
|
|
8
|
+
|
|
9
|
+
Basic Shape
|
|
10
|
+
-----------
|
|
11
|
+
|
|
12
|
+
Every field needs a ``codec`` value. The value is one of the aliases listed in
|
|
13
|
+
:doc:`reference/codec_aliases`.
|
|
14
|
+
|
|
15
|
+
.. code-block:: yaml
|
|
16
|
+
|
|
17
|
+
field_name:
|
|
18
|
+
codec: string
|
|
19
|
+
max_length: 16
|
|
20
|
+
|
|
21
|
+
The remaining keys are passed to that field codec's constructor. For example,
|
|
22
|
+
``max_length`` belongs to the string codec in the example above.
|
|
23
|
+
|
|
24
|
+
Scalar Fields
|
|
25
|
+
-------------
|
|
26
|
+
|
|
27
|
+
Use scalar codecs for values that encode as a single value in the message.
|
|
28
|
+
|
|
29
|
+
.. code-block:: yaml
|
|
30
|
+
|
|
31
|
+
name:
|
|
32
|
+
codec: string
|
|
33
|
+
max_length: 10
|
|
34
|
+
count:
|
|
35
|
+
codec: integer
|
|
36
|
+
min_value: 0
|
|
37
|
+
max_value: 100
|
|
38
|
+
enabled:
|
|
39
|
+
codec: bool
|
|
40
|
+
temperature:
|
|
41
|
+
codec: float
|
|
42
|
+
min_value: -5.0
|
|
43
|
+
max_value: 35.0
|
|
44
|
+
precision: 1
|
|
45
|
+
depth:
|
|
46
|
+
codec: linspace_float
|
|
47
|
+
min_value: 0.0
|
|
48
|
+
max_value: 100.0
|
|
49
|
+
resolution: 0.5
|
|
50
|
+
|
|
51
|
+
Common scalar aliases include ``string``, ``integer``, ``bool``, ``float``,
|
|
52
|
+
``uint8``, ``uint16``, ``uint32``, ``int8``, ``int16``, ``float32``, and
|
|
53
|
+
``float64``. Use ``float`` when a fixed number of decimal places is the
|
|
54
|
+
natural constraint, and ``linspace_float`` when a physical step size or number
|
|
55
|
+
of values is the natural constraint.
|
|
56
|
+
|
|
57
|
+
Nested Dictionaries
|
|
58
|
+
-------------------
|
|
59
|
+
|
|
60
|
+
Use ``dict`` when a field contains another mapping of named fields.
|
|
61
|
+
|
|
62
|
+
.. code-block:: yaml
|
|
63
|
+
|
|
64
|
+
vehicle:
|
|
65
|
+
codec: dict
|
|
66
|
+
fields:
|
|
67
|
+
id:
|
|
68
|
+
codec: uint8
|
|
69
|
+
name:
|
|
70
|
+
codec: string
|
|
71
|
+
max_length: 12
|
|
72
|
+
|
|
73
|
+
The input value for ``vehicle`` is a nested dictionary:
|
|
74
|
+
|
|
75
|
+
.. code-block:: python
|
|
76
|
+
|
|
77
|
+
{
|
|
78
|
+
"vehicle": {
|
|
79
|
+
"id": 7,
|
|
80
|
+
"name": "remus",
|
|
81
|
+
},
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
Nested ROS Messages
|
|
85
|
+
-------------------
|
|
86
|
+
|
|
87
|
+
Use ``msg`` when a field contains a nested ROS message.
|
|
88
|
+
|
|
89
|
+
.. code-block:: yaml
|
|
90
|
+
|
|
91
|
+
position:
|
|
92
|
+
codec: msg
|
|
93
|
+
ros_type: geometry_msgs/Point
|
|
94
|
+
fields:
|
|
95
|
+
x:
|
|
96
|
+
codec: float32
|
|
97
|
+
y:
|
|
98
|
+
codec: float32
|
|
99
|
+
z:
|
|
100
|
+
codec: float32
|
|
101
|
+
|
|
102
|
+
``ros_type`` may use ROS 1 style names such as ``geometry_msgs/Point`` or ROS
|
|
103
|
+
2 introspection names such as ``geometry_msgs/msg/Point``. ``ltcodecs``
|
|
104
|
+
normalizes ROS 2 names internally.
|
|
105
|
+
|
|
106
|
+
Variable-Length Arrays
|
|
107
|
+
----------------------
|
|
108
|
+
|
|
109
|
+
Use ``variable_len_array`` for a list whose encoded length is included in the
|
|
110
|
+
bit stream.
|
|
111
|
+
|
|
112
|
+
.. code-block:: yaml
|
|
113
|
+
|
|
114
|
+
samples:
|
|
115
|
+
codec: variable_len_array
|
|
116
|
+
max_length: 10
|
|
117
|
+
element_type: uint8
|
|
118
|
+
|
|
119
|
+
``max_length`` is required. Values longer than ``max_length`` are currently
|
|
120
|
+
truncated during encoding.
|
|
121
|
+
|
|
122
|
+
For element codecs that need parameters, put those parameters under
|
|
123
|
+
``element_params``:
|
|
124
|
+
|
|
125
|
+
.. code-block:: yaml
|
|
126
|
+
|
|
127
|
+
labels:
|
|
128
|
+
codec: variable_len_array
|
|
129
|
+
max_length: 4
|
|
130
|
+
element_type: string
|
|
131
|
+
element_params:
|
|
132
|
+
max_length: 12
|
|
133
|
+
|
|
134
|
+
Set ``nullable: true`` when an empty list should encode as a single bit. When
|
|
135
|
+
``nullable`` is false, the array length is always encoded.
|
|
136
|
+
|
|
137
|
+
.. code-block:: yaml
|
|
138
|
+
|
|
139
|
+
optional_samples:
|
|
140
|
+
codec: variable_len_array
|
|
141
|
+
max_length: 10
|
|
142
|
+
nullable: true
|
|
143
|
+
element_type: uint8
|
|
144
|
+
|
|
145
|
+
Fixed-Length Arrays
|
|
146
|
+
-------------------
|
|
147
|
+
|
|
148
|
+
Use ``fixed_len_array`` when the number of elements is known from the config.
|
|
149
|
+
|
|
150
|
+
.. code-block:: yaml
|
|
151
|
+
|
|
152
|
+
rgb:
|
|
153
|
+
codec: fixed_len_array
|
|
154
|
+
length: 3
|
|
155
|
+
element_type: uint8
|
|
156
|
+
|
|
157
|
+
The encoded stream does not include a length field. The decoder always reads
|
|
158
|
+
``length`` elements.
|
|
159
|
+
|
|
160
|
+
Arrays of Messages
|
|
161
|
+
------------------
|
|
162
|
+
|
|
163
|
+
Array elements can be nested dictionaries or ROS messages. Use
|
|
164
|
+
``element_type: msg`` for ROS message elements and pass the message parameters
|
|
165
|
+
with ``element_params``.
|
|
166
|
+
|
|
167
|
+
.. code-block:: yaml
|
|
168
|
+
|
|
169
|
+
points:
|
|
170
|
+
codec: variable_len_array
|
|
171
|
+
max_length: 5
|
|
172
|
+
element_type: msg
|
|
173
|
+
element_params:
|
|
174
|
+
ros_type: geometry_msgs/Point
|
|
175
|
+
fields:
|
|
176
|
+
x:
|
|
177
|
+
codec: float32
|
|
178
|
+
y:
|
|
179
|
+
codec: float32
|
|
180
|
+
z:
|
|
181
|
+
codec: float32
|
|
182
|
+
|
|
183
|
+
Optional Fields
|
|
184
|
+
---------------
|
|
185
|
+
|
|
186
|
+
Use ``optional`` when a boolean field controls whether additional fields are
|
|
187
|
+
present. The controlling field itself encodes as one bit. If it is true, each
|
|
188
|
+
field in ``target_fields`` is encoded immediately after it. If false, the
|
|
189
|
+
target fields use no bits.
|
|
190
|
+
|
|
191
|
+
.. code-block:: yaml
|
|
192
|
+
|
|
193
|
+
has_extra:
|
|
194
|
+
codec: optional
|
|
195
|
+
target_fields:
|
|
196
|
+
extra:
|
|
197
|
+
codec: uint8
|
|
198
|
+
|
|
199
|
+
The input dictionary or ROS message must contain both ``has_extra`` and
|
|
200
|
+
``extra`` when ``has_extra`` is true.
|
|
201
|
+
|
|
202
|
+
Padding
|
|
203
|
+
-------
|
|
204
|
+
|
|
205
|
+
Use ``pad`` or ``padding`` to reserve a fixed number of zero bits.
|
|
206
|
+
|
|
207
|
+
.. code-block:: yaml
|
|
208
|
+
|
|
209
|
+
reserved:
|
|
210
|
+
codec: padding
|
|
211
|
+
num_bits: 8
|
|
212
|
+
|
|
213
|
+
Padding decodes to ``None``.
|
|
214
|
+
|
|
215
|
+
Metadata Fields
|
|
216
|
+
---------------
|
|
217
|
+
|
|
218
|
+
Some codec aliases represent metadata rather than payload bits. These fields
|
|
219
|
+
are copied to or from packet metadata and are not encoded like ordinary fields.
|
|
220
|
+
|
|
221
|
+
This functionality is used by ``ros_acomms``, so the currently implemented metadata fields
|
|
222
|
+
are all related to encoding or decoding acoustic packet data.
|
|
223
|
+
|
|
224
|
+
Available metadata decoder aliases include ``src``, ``dest``,
|
|
225
|
+
``dest_decoder``, ``toa``, and ``snr_in``. The metadata encoder alias
|
|
226
|
+
currently used by top-level codecs is ``dest``.
|
|
227
|
+
|
|
228
|
+
.. code-block:: yaml
|
|
229
|
+
|
|
230
|
+
dest:
|
|
231
|
+
codec: dest
|
|
232
|
+
data:
|
|
233
|
+
codec: string
|
|
234
|
+
max_length: 20
|
|
235
|
+
|
|
236
|
+
When encoding, the top-level codec returns the metadata dictionary as the
|
|
237
|
+
second value from ``encode()``.
|
|
238
|
+
|
|
239
|
+
Checksums
|
|
240
|
+
---------
|
|
241
|
+
|
|
242
|
+
Checksums are configured on the top-level codec object, not inside each field.
|
|
243
|
+
Both :py:class:`ltcodecs.dict_codec.DictCodec` and
|
|
244
|
+
:py:class:`ltcodecs.ros_message_codec.RosMessageCodec` support ``crc8`` and
|
|
245
|
+
``crc32``.
|
|
246
|
+
|
|
247
|
+
.. code-block:: python
|
|
248
|
+
|
|
249
|
+
codec = ltcodecs.DictCodec.from_codec_file(
|
|
250
|
+
"message_codec.yaml",
|
|
251
|
+
checksum="crc32",
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
The checksum is appended after the encoded payload. During decoding, a
|
|
255
|
+
mismatch raises ``ValueError``.
|
|
256
|
+
|
|
257
|
+
Complete Example
|
|
258
|
+
----------------
|
|
259
|
+
|
|
260
|
+
.. code-block:: yaml
|
|
261
|
+
|
|
262
|
+
name:
|
|
263
|
+
codec: string
|
|
264
|
+
max_length: 10
|
|
265
|
+
count:
|
|
266
|
+
codec: integer
|
|
267
|
+
min_value: 0
|
|
268
|
+
max_value: 100
|
|
269
|
+
enabled:
|
|
270
|
+
codec: bool
|
|
271
|
+
nested:
|
|
272
|
+
codec: dict
|
|
273
|
+
fields:
|
|
274
|
+
value:
|
|
275
|
+
codec: uint8
|
|
276
|
+
has_extra:
|
|
277
|
+
codec: optional
|
|
278
|
+
target_fields:
|
|
279
|
+
extra:
|
|
280
|
+
codec: uint8
|
|
281
|
+
|
|
282
|
+
This config can be loaded with
|
|
283
|
+
:py:meth:`ltcodecs.dict_codec.DictCodec.from_codec_file` and used to encode a
|
|
284
|
+
dictionary with the same field names.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
ltcodecs
|
|
2
|
+
========
|
|
3
|
+
|
|
4
|
+
``ltcodecs`` encodes Python dictionaries and ROS messages into compact
|
|
5
|
+
bitstreams using declarative codec configurations.
|
|
6
|
+
|
|
7
|
+
Start with :doc:`quickstart` if you are writing your first codec config. Use
|
|
8
|
+
:doc:`codec_configs` and :doc:`ros_messages` for the full user guide.
|
|
9
|
+
|
|
10
|
+
.. toctree::
|
|
11
|
+
:maxdepth: 2
|
|
12
|
+
:caption: User Guide
|
|
13
|
+
|
|
14
|
+
quickstart
|
|
15
|
+
codec_configs
|
|
16
|
+
ros_messages
|
|
17
|
+
|
|
18
|
+
.. toctree::
|
|
19
|
+
:maxdepth: 2
|
|
20
|
+
:caption: Reference
|
|
21
|
+
|
|
22
|
+
reference/codecs
|
|
23
|
+
reference/codec_aliases
|
|
24
|
+
reference/config_schema
|
|
25
|
+
reference/python_api
|
|
26
|
+
tests
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
Quick Start
|
|
2
|
+
===========
|
|
3
|
+
|
|
4
|
+
``ltcodecs`` encodes structured Python dictionaries and ROS messages into
|
|
5
|
+
compact bit streams. A codec is configured with a field dictionary: each field
|
|
6
|
+
name maps to a codec alias and the parameters for that field codec.
|
|
7
|
+
|
|
8
|
+
Install
|
|
9
|
+
-------
|
|
10
|
+
|
|
11
|
+
Install the package from PyPI:
|
|
12
|
+
|
|
13
|
+
.. code-block:: console
|
|
14
|
+
|
|
15
|
+
pip install ltcodecs
|
|
16
|
+
|
|
17
|
+
For local development, install the checkout in editable mode:
|
|
18
|
+
|
|
19
|
+
.. code-block:: console
|
|
20
|
+
|
|
21
|
+
pip install -e .
|
|
22
|
+
|
|
23
|
+
Encode a Dictionary
|
|
24
|
+
-------------------
|
|
25
|
+
|
|
26
|
+
The quickest way to use ``ltcodecs`` is with
|
|
27
|
+
:py:class:`ltcodecs.dict_codec.DictCodec`. This path does not require ROS.
|
|
28
|
+
|
|
29
|
+
.. code-block:: python
|
|
30
|
+
|
|
31
|
+
from bitstring import ConstBitStream
|
|
32
|
+
import ltcodecs
|
|
33
|
+
|
|
34
|
+
fields = {
|
|
35
|
+
"name": {
|
|
36
|
+
"codec": "string",
|
|
37
|
+
"max_length": 10,
|
|
38
|
+
},
|
|
39
|
+
"count": {
|
|
40
|
+
"codec": "integer",
|
|
41
|
+
"min_value": 0,
|
|
42
|
+
"max_value": 100,
|
|
43
|
+
},
|
|
44
|
+
"enabled": {
|
|
45
|
+
"codec": "bool",
|
|
46
|
+
},
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
message = {
|
|
50
|
+
"name": "test",
|
|
51
|
+
"count": 21,
|
|
52
|
+
"enabled": True,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
codec = ltcodecs.DictCodec(fields)
|
|
56
|
+
bits, metadata = codec.encode(message)
|
|
57
|
+
|
|
58
|
+
decoded = codec.decode(ConstBitStream(bits))
|
|
59
|
+
assert decoded == message
|
|
60
|
+
|
|
61
|
+
The ``bits`` value is a ``bitstring.Bits`` object. The ``metadata`` return
|
|
62
|
+
value is usually ``None`` unless the field configuration includes one of the
|
|
63
|
+
metadata encoder aliases.
|
|
64
|
+
|
|
65
|
+
Encode Metadata
|
|
66
|
+
---------------
|
|
67
|
+
|
|
68
|
+
``encode()`` for the Message/Dictionary codecs returns a tuple of ``(bits, metadata)``.
|
|
69
|
+
The first value is the encoded bit stream.
|
|
70
|
+
The second value is a small metadata dictionary for values
|
|
71
|
+
that should travel outside the compressed payload, such as packet routing
|
|
72
|
+
fields. Most codecs return ``None`` for metadata, and you can ignore it.
|
|
73
|
+
It is possible to define fields that
|
|
74
|
+
use metadata encoders rather than (or in addition to) adding bits to the output stream.
|
|
75
|
+
|
|
76
|
+
Use YAML Configuration
|
|
77
|
+
----------------------
|
|
78
|
+
|
|
79
|
+
Codec configurations are commonly stored as YAML. The same dictionary codec
|
|
80
|
+
above can be written as:
|
|
81
|
+
|
|
82
|
+
.. code-block:: yaml
|
|
83
|
+
|
|
84
|
+
name:
|
|
85
|
+
codec: string
|
|
86
|
+
max_length: 10
|
|
87
|
+
count:
|
|
88
|
+
codec: integer
|
|
89
|
+
min_value: 0
|
|
90
|
+
max_value: 100
|
|
91
|
+
enabled:
|
|
92
|
+
codec: bool
|
|
93
|
+
|
|
94
|
+
Load the YAML file with
|
|
95
|
+
:py:meth:`ltcodecs.dict_codec.DictCodec.from_codec_file`:
|
|
96
|
+
|
|
97
|
+
.. code-block:: python
|
|
98
|
+
|
|
99
|
+
from bitstring import ConstBitStream
|
|
100
|
+
import ltcodecs
|
|
101
|
+
|
|
102
|
+
codec = ltcodecs.DictCodec.from_codec_file("message_codec.yaml")
|
|
103
|
+
|
|
104
|
+
bits, _metadata = codec.encode({
|
|
105
|
+
"name": "test",
|
|
106
|
+
"count": 21,
|
|
107
|
+
"enabled": True,
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
decoded = codec.decode(ConstBitStream(bits))
|
|
111
|
+
|
|
112
|
+
Nested Dictionaries and Optional Fields
|
|
113
|
+
---------------------------------------
|
|
114
|
+
|
|
115
|
+
A field can itself be a dictionary. Use the ``dict`` codec and provide a
|
|
116
|
+
nested ``fields`` mapping:
|
|
117
|
+
|
|
118
|
+
.. code-block:: yaml
|
|
119
|
+
|
|
120
|
+
nested:
|
|
121
|
+
codec: dict
|
|
122
|
+
fields:
|
|
123
|
+
value:
|
|
124
|
+
codec: uint8
|
|
125
|
+
|
|
126
|
+
Optional fields are controlled by a boolean field. If the controlling value is
|
|
127
|
+
true, the target fields are encoded. If false, those fields use no bits.
|
|
128
|
+
|
|
129
|
+
.. code-block:: yaml
|
|
130
|
+
|
|
131
|
+
has_extra:
|
|
132
|
+
codec: optional
|
|
133
|
+
target_fields:
|
|
134
|
+
extra:
|
|
135
|
+
codec: uint8
|
|
136
|
+
|
|
137
|
+
The input dictionary for that configuration would include both the controlling
|
|
138
|
+
field and the target field:
|
|
139
|
+
|
|
140
|
+
.. code-block:: python
|
|
141
|
+
|
|
142
|
+
message = {
|
|
143
|
+
"has_extra": True,
|
|
144
|
+
"extra": 42,
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
Encode a ROS Message
|
|
148
|
+
--------------------
|
|
149
|
+
|
|
150
|
+
Use :py:class:`ltcodecs.ros_message_codec.RosMessageCodec` for ROS messages.
|
|
151
|
+
If no field dictionary is provided, ``ltcodecs`` asks ARMW for the message
|
|
152
|
+
fields and chooses codecs from the ROS field types.
|
|
153
|
+
|
|
154
|
+
.. code-block:: python
|
|
155
|
+
|
|
156
|
+
from bitstring import ConstBitStream
|
|
157
|
+
import armw
|
|
158
|
+
import ltcodecs
|
|
159
|
+
|
|
160
|
+
String = armw.import_message("std_msgs", "String")
|
|
161
|
+
|
|
162
|
+
msg = String()
|
|
163
|
+
msg.data = "hello"
|
|
164
|
+
|
|
165
|
+
codec = ltcodecs.RosMessageCodec("std_msgs/String")
|
|
166
|
+
bits, metadata = codec.encode(msg)
|
|
167
|
+
|
|
168
|
+
decoded = codec.decode(ConstBitStream(bits))
|
|
169
|
+
assert decoded.data == "hello"
|
|
170
|
+
|
|
171
|
+
You can also provide a YAML field configuration for a ROS message:
|
|
172
|
+
|
|
173
|
+
.. code-block:: yaml
|
|
174
|
+
|
|
175
|
+
data:
|
|
176
|
+
codec: string
|
|
177
|
+
max_length: 10
|
|
178
|
+
|
|
179
|
+
.. code-block:: python
|
|
180
|
+
|
|
181
|
+
codec = ltcodecs.RosMessageCodec.from_codec_file(
|
|
182
|
+
"std_msgs/String",
|
|
183
|
+
"string_msg_codec.yaml",
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
ROS 1 and ROS 2 Type Names
|
|
187
|
+
--------------------------
|
|
188
|
+
|
|
189
|
+
ROS message fields may use ROS 1 style type names such as ``pkg/Msg`` and
|
|
190
|
+
``pkg/Msg[]`` or ROS 2 introspection names such as ``pkg/msg/Msg`` and
|
|
191
|
+
``sequence<pkg/msg/Msg>``. ``ltcodecs`` normalizes these forms when it infers
|
|
192
|
+
fields from a ROS message or when an explicit field config contains a ROS type.
|
|
193
|
+
|
|
194
|
+
For arrays, use the array codecs directly when writing explicit configs:
|
|
195
|
+
|
|
196
|
+
.. code-block:: yaml
|
|
197
|
+
|
|
198
|
+
samples:
|
|
199
|
+
codec: variable_len_array
|
|
200
|
+
max_length: 10
|
|
201
|
+
element_type: uint8
|
|
202
|
+
|
|
203
|
+
points:
|
|
204
|
+
codec: fixed_len_array
|
|
205
|
+
length: 3
|
|
206
|
+
element_type: msg
|
|
207
|
+
element_params:
|
|
208
|
+
ros_type: geometry_msgs/Point
|
|
209
|
+
|
|
210
|
+
Checksums
|
|
211
|
+
---------
|
|
212
|
+
|
|
213
|
+
Top-level dictionary and ROS message codecs can append a checksum. Supported
|
|
214
|
+
values are ``crc8`` and ``crc32``.
|
|
215
|
+
|
|
216
|
+
.. code-block:: python
|
|
217
|
+
|
|
218
|
+
codec = ltcodecs.DictCodec(fields, checksum="crc8")
|
|
219
|
+
bits, _metadata = codec.encode(message)
|
|
220
|
+
decoded = codec.decode(ConstBitStream(bits))
|
|
221
|
+
|
|
222
|
+
If the received checksum does not match the encoded content, ``decode`` raises
|
|
223
|
+
``ValueError``.
|
|
224
|
+
|
|
225
|
+
Next Steps
|
|
226
|
+
----------
|
|
227
|
+
|
|
228
|
+
See :doc:`reference/codecs` for the codec reference,
|
|
229
|
+
:doc:`reference/codec_aliases` for the full alias table, and
|
|
230
|
+
:doc:`reference/python_api` for the generated API reference.
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
You can adapt this file completely to your liking, but it should at least
|
|
4
|
-
contain the root `toctree` directive.
|
|
1
|
+
Codec Aliases
|
|
2
|
+
=============
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
There are aliases for each codec that can be used in codec yaml files.
|
|
10
|
-
Note that there are multiple aliases for some codec classes.
|
|
4
|
+
Codec configurations use short aliases instead of Python class names. Some
|
|
5
|
+
codec classes have more than one alias for readability or compatibility with
|
|
6
|
+
existing configs.
|
|
11
7
|
|
|
12
8
|
======================== ====================================================
|
|
13
9
|
Alias Codec Class
|
|
@@ -30,14 +26,17 @@ Alias Codec Class
|
|
|
30
26
|
``float32`` :py:class:`~ltcodecs.ieee_float_codec.IeeeFloat32Codec`
|
|
31
27
|
``float64`` :py:class:`~ltcodecs.ieee_float_codec.IeeeFloat64Codec`
|
|
32
28
|
``bool`` :py:class:`~ltcodecs.bool_codec.BoolCodec`
|
|
29
|
+
``boolean`` :py:class:`~ltcodecs.bool_codec.BoolCodec`
|
|
33
30
|
``string`` :py:class:`~ltcodecs.string_codecs.AsciiStringCodec`
|
|
34
31
|
``ascii`` :py:class:`~ltcodecs.string_codecs.AsciiStringCodec`
|
|
35
32
|
``bytes`` :py:class:`~ltcodecs.bytes_codec.BytesCodec`
|
|
33
|
+
``dict`` :py:class:`~ltcodecs.dict_field_codec.DictFieldCodec`
|
|
34
|
+
``dictionary`` :py:class:`~ltcodecs.dict_field_codec.DictFieldCodec`
|
|
36
35
|
``msg`` :py:class:`~ltcodecs.ros_msg_field_codec.RosMsgFieldCodec`
|
|
37
36
|
``ros_msg`` :py:class:`~ltcodecs.ros_msg_field_codec.RosMsgFieldCodec`
|
|
38
37
|
``variable_len_array`` :py:class:`~ltcodecs.variable_len_array_codec.VariableLenArrayCodec`
|
|
39
38
|
``fixed_len_array`` :py:class:`~ltcodecs.fixed_len_array_codec.FixedLenArrayCodec`
|
|
40
|
-
``ccl_latlon`` :py:class:`~ltcodecs.ccl_latlon_codec.CclLatLonCodec
|
|
39
|
+
``ccl_latlon`` :py:class:`~ltcodecs.ccl_latlon_codec.CclLatLonCodec`
|
|
41
40
|
``ccl_latlon_bcd`` :py:class:`~ltcodecs.ccl_latlon_bcd_codec.CclLatLonBcdCodec`
|
|
42
41
|
``pad`` :py:class:`~ltcodecs.padding_codec.PaddingCodec`
|
|
43
42
|
``padding`` :py:class:`~ltcodecs.padding_codec.PaddingCodec`
|
|
@@ -48,13 +47,22 @@ Alias Codec Class
|
|
|
48
47
|
``optional`` :py:class:`~ltcodecs.optional_field_codec.OptionalFieldCodec`
|
|
49
48
|
======================== ====================================================
|
|
50
49
|
|
|
50
|
+
Metadata Aliases
|
|
51
|
+
----------------
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
:caption: Contents:
|
|
55
|
-
|
|
56
|
-
ltcodecs
|
|
57
|
-
tests
|
|
58
|
-
|
|
53
|
+
Metadata decoder aliases read values from packet metadata during decoding.
|
|
54
|
+
They do not consume bits from the payload.
|
|
59
55
|
|
|
56
|
+
================ ========================
|
|
57
|
+
Alias Metadata attribute
|
|
58
|
+
================ ========================
|
|
59
|
+
``src`` ``packet.src``
|
|
60
|
+
``dest`` ``packet.dest``
|
|
61
|
+
``dest_decoder`` ``packet.dest``
|
|
62
|
+
``toa`` ``cst.toa``
|
|
63
|
+
``snr_in`` ``cst.snr_in``
|
|
64
|
+
================ ========================
|
|
60
65
|
|
|
66
|
+
The metadata encoder alias currently supported by top-level codecs is
|
|
67
|
+
``dest``. During encoding, it copies the configured field into the metadata
|
|
68
|
+
dictionary returned with the encoded bits.
|