| Name | munud JSON |
| Version |
0.3.1
JSON |
| download |
| home_page | None |
| Summary | Building sub-byte payloads, and generating according C code |
| upload_time | 2024-09-27 16:20:31 |
| maintainer | None |
| docs_url | None |
| author | Ulysse Moreau |
| requires_python | <4.0,>=3.9 |
| license | MIT |
| keywords |
|
| VCS |
|
| bugtrack_url |
|
| requirements |
No requirements were recorded.
|
| Travis-CI |
No Travis.
|
| coveralls test coverage |
No coveralls.
|
# Munud
Building payloads with sub-byte unaligned values, and generating according C code.
# Installation
The easiest way to install this library is using pip:
```bash
pip install munud
```
# Motivation
This module is built around the concept of "Unaligned Bytes", which means a sequence
of n bits forming an int which might not be aligned on the bytes themselves.
Take as an example the following bytes :
```py
some_bytes = b"\xfa\x04\xde"
```
We will assume that the first 3 bits corresponds to value A, the next 17 bits to value B, and
the next 4 bits to value C. This will correspond to the following representation in memory:
```txt
+--------+--------+--------+
| Byte 0 | Byte 1 | Byte 2 |
+---+----+--------+---+----+
| A | B | C |
+---+-----------------+----+
```
Thus, a traditionnal python way of retrieving those three values would be as such:
```python
A = some_bytes[0] >> 5
B = (some_bytes[0] & 0x1F) << 12 | some_bytes[1] << 4 | some_bytes[2] >> 4
C = some_bytes[2] & 0x0F
```
And a traditional way of shoving those values in a byte array would be as follows:
```python
some_bytes = [0, 0, 0]
some_bytes[0] |= A << 5
some_bytes[0] |= (B >> 12) & 0x1F
some_bytes[1] = (B >> 4) & 0xFF
some_bytes[2] |= (B << 4) & 0xFF
some_bytes[2] |= C
```
This module provides two main functionalities:
- Provide a python API to do those read/write operations dynamically
- Generate a C code to perform those operations efficiently, given a fixed format
# Usage
## Programmation API
With munud, the same can be achieved using the following:
```python
from munud import UnalignedBytes
ub_A = UnalignedBytes(offset=0, bit_size=3)
ub_B = UnalignedBytes(3, 17)
ub_C = UnalignedBytes(20, 4)
# Writing
some_bytes = [0, 0, 0]
ub_A.shove(byte_buffer=some_bytes, value=3)
ub_B.shove(some_bytes, 1234)
ub_C.shove(some_bytes, 5)
# > b"\x60\x4d\x25"
# Reading
A = ub_A.extract(some_bytes)
B = ub_B.extract(some_bytes)
C = ub_C.extract(some_bytes)
```
### Using a yaml file :
Using the following `test.yml` file:
```yml
- name: A
size: 3
type: uint8_t
- name: B
size: 17
type: uint16_t
- name: C
size: 4
type: uint8_t
```
Use the following to obtain a python dict representing the extracted bytes :
```python
bytes_to_read = b"\x60\x4d\x25"
from_yaml("test.yml", bytes_to_read)
# > {'A': 3, 'B': 1234, 'C': 5}
```
## C generation with the cli
Using the following `test.yml` file:
```yml
- name: A
size: 3
type: uint8_t
- name: B
size: 17
type: uint16_t
- name: C
size: 4
type: uint8_t
```
To show a table summarizing the payload, use :
```bash
munud -f test.yml show
```
```txt
Payload
┏━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ Type ┃ Name ┃ Size (bits) ┃ Byte Span ┃
┡━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ uint8_t │ A │ 3 │ [0 (+0) - 1] │
│ uint16_t │ B │ 17 │ [0 (+3) - 3] │
│ uint8_t │ C │ 4 │ [2 (+4) - 3] │
└──────────┴──────┴─────────────┴──────────────┘
Total payload size: 24 bits
```
To decode an hex payload, use:
```bash
munud -f test.yml decode -p AAAAAAAA
```
```
Payload
┏━━━━━━━━━━┳━━━━━━┳━━━━━━━┓
┃ Type ┃ Name ┃ Value ┃
┡━━━━━━━━━━╇━━━━━━╇━━━━━━━┩
│ uint8_t │ A │ 5 │
│ uint16_t │ B │ 43690 │
│ uint8_t │ C │ 10 │
└──────────┴──────┴───────┘
Total payload size: 24 bits
```
To generate c getters and setters, use:
```bash
munud -f test.yml cgen
```
This will generate the following c code:
```c
#include "assert.h"
#include "stdint.h"
inline static uint8_t get_A(uint8_t *payload)
{
/*
* This function retrives the value A (3 bits).
* The value is found in byte 0.
* The value starts at bit 0.
*/
return payload[0] >> 5;
}
inline static void set_A(uint8_t *payload, uint8_t value)
{
/*
* This function writes the value A (3 bits).
* The value will be written in byte 0.
* The value starts at bit 0.
*/
payload[0] |= value << 5;
}
inline static uint16_t get_B(uint8_t *payload)
{
/*
* This function retrives the value B (17 bits).
* The value spreads between bytes 0 and 2.
* The value starts at bit 3.
*/
return (payload[0] & 0x1F) << 12 | payload[1] << 4 | payload[2] >> 4;
}
inline static void set_B(uint8_t *payload, uint16_t value)
{
/*
* This function writes the value B (17 bits).
* The value will spread between bytes 0 and 2.
* The value starts at bit 3.
*/
payload[0] |= (value >> 12) & 0x1F;
payload[1] = (value >> 4) & 0xFF;
payload[2] |= (value << 4) & 0xFF;
}
inline static uint8_t get_C(uint8_t *payload)
{
/*
* This function retrives the value C (4 bits).
* The value is found in byte 2.
* The value starts at bit 4.
*/
return payload[2] & 0x0F;
}
inline static void set_C(uint8_t *payload, uint8_t value)
{
/*
* This function writes the value C (4 bits).
* The value will be written in byte 20.
* The value starts at bit 4.
*/
payload[2] |= value;
}
struct Payload
{
uint16_t B;
uint8_t A;
uint8_t C;
};
inline static void decode(struct Payload *payload, uint8_t *packed)
{
/*
*
*/
payload->A = get_A(packed);
payload->B = get_B(packed);
payload->C = get_C(packed);
}
inline static void encode(struct Payload *payload, uint8_t *packed)
{
/*
*
*/
set_A(packed, payload->A);
set_B(packed, payload->B);
set_C(packed, payload->C);
}
```
Many options are available for customisation :
```bash
$ munud cgen --help
Usage: munud.cmd cgen [OPTIONS]
Options:
-f, --fmt TEXT A file describing the wanted format.
-o, --output TEXT The output .h file.
--crlf Use \r\n (crlf) as newline instead of \n (crlf).
--use-assert Generate assert check before writing to payload.
--get-only Generate only getters.
--set-only Generate only setters.
--without-struct Do not generate a struct containing the payload.
--packed-struct Add the gcc __attribute__((packed)) attribute to the
struct.
-n, --struct-name TEXT Payload struct name.
--without-safety-mask Removes the 0xff mask when writing ints on bytes.
--payload-type TEXT The type of the payload, usually uint8_t*.
--cpp Generate cpp-style namespace.
--namespace TEXT The name of an optional namespace. If cpp is not
enabled, add it as a prefix.
--help Show this message and exit.
```
# Development
This library uses poetry as a development tool.
You can start development by running :
```bash
poetry install
```
# Testing
You can test this library using :
```bash
poetry run pytest
```
# Tox
You can test multiple python versions using tox :
```bash
poetry run tox
```
Raw data
{
"_id": null,
"home_page": null,
"name": "munud",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.9",
"maintainer_email": null,
"keywords": null,
"author": "Ulysse Moreau",
"author_email": "u.moreau@hexa-h.com",
"download_url": "https://files.pythonhosted.org/packages/a6/45/7ad5d4dda71ab4866f91fce7ff541799a68d281ba83e7ed723e5c82f8baa/munud-0.3.1.tar.gz",
"platform": null,
"description": "# Munud\n\nBuilding payloads with sub-byte unaligned values, and generating according C code.\n\n# Installation\n\nThe easiest way to install this library is using pip:\n\n```bash\npip install munud\n```\n\n# Motivation\n\nThis module is built around the concept of \"Unaligned Bytes\", which means a sequence\nof n bits forming an int which might not be aligned on the bytes themselves.\n\nTake as an example the following bytes : \n\n```py\nsome_bytes = b\"\\xfa\\x04\\xde\"\n```\n\nWe will assume that the first 3 bits corresponds to value A, the next 17 bits to value B, and\nthe next 4 bits to value C. This will correspond to the following representation in memory:\n\n```txt\n +--------+--------+--------+\n | Byte 0 | Byte 1 | Byte 2 |\n +---+----+--------+---+----+\n | A | B | C |\n +---+-----------------+----+\n\n```\n\nThus, a traditionnal python way of retrieving those three values would be as such:\n\n```python\nA = some_bytes[0] >> 5\nB = (some_bytes[0] & 0x1F) << 12 | some_bytes[1] << 4 | some_bytes[2] >> 4\nC = some_bytes[2] & 0x0F\n```\n\nAnd a traditional way of shoving those values in a byte array would be as follows:\n\n```python\nsome_bytes = [0, 0, 0]\n\nsome_bytes[0] |= A << 5\n\nsome_bytes[0] |= (B >> 12) & 0x1F\nsome_bytes[1] = (B >> 4) & 0xFF\nsome_bytes[2] |= (B << 4) & 0xFF\n\nsome_bytes[2] |= C\n```\n\nThis module provides two main functionalities:\n\n- Provide a python API to do those read/write operations dynamically\n- Generate a C code to perform those operations efficiently, given a fixed format\n\n# Usage\n\n## Programmation API\n\nWith munud, the same can be achieved using the following:\n\n```python\n\nfrom munud import UnalignedBytes\n\nub_A = UnalignedBytes(offset=0, bit_size=3)\nub_B = UnalignedBytes(3, 17)\nub_C = UnalignedBytes(20, 4)\n\n# Writing\nsome_bytes = [0, 0, 0]\n\nub_A.shove(byte_buffer=some_bytes, value=3)\nub_B.shove(some_bytes, 1234)\nub_C.shove(some_bytes, 5)\n\n# > b\"\\x60\\x4d\\x25\"\n\n# Reading\nA = ub_A.extract(some_bytes)\nB = ub_B.extract(some_bytes)\nC = ub_C.extract(some_bytes)\n\n```\n\n### Using a yaml file : \n\nUsing the following `test.yml` file:\n\n```yml\n- name: A\n size: 3\n type: uint8_t\n- name: B\n size: 17\n type: uint16_t\n- name: C\n size: 4\n type: uint8_t\n```\n\nUse the following to obtain a python dict representing the extracted bytes :\n\n\n```python\nbytes_to_read = b\"\\x60\\x4d\\x25\"\n\nfrom_yaml(\"test.yml\", bytes_to_read)\n# > {'A': 3, 'B': 1234, 'C': 5}\n\n```\n\n## C generation with the cli\n\nUsing the following `test.yml` file:\n\n```yml\n- name: A\n size: 3\n type: uint8_t\n- name: B\n size: 17\n type: uint16_t\n- name: C\n size: 4\n type: uint8_t\n```\n\nTo show a table summarizing the payload, use :\n\n```bash\nmunud -f test.yml show\n```\n\n```txt\n Payload\n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Type \u2503 Name \u2503 Size (bits) \u2503 Byte Span \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 uint8_t \u2502 A \u2502 3 \u2502 [0 (+0) - 1] \u2502\n\u2502 uint16_t \u2502 B \u2502 17 \u2502 [0 (+3) - 3] \u2502\n\u2502 uint8_t \u2502 C \u2502 4 \u2502 [2 (+4) - 3] \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\nTotal payload size: 24 bits\n```\n\nTo decode an hex payload, use:\n\n```bash\nmunud -f test.yml decode -p AAAAAAAA\n```\n\n```\n Payload\n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Type \u2503 Name \u2503 Value \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 uint8_t \u2502 A \u2502 5 \u2502\n\u2502 uint16_t \u2502 B \u2502 43690 \u2502\n\u2502 uint8_t \u2502 C \u2502 10 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\nTotal payload size: 24 bits\n```\n\nTo generate c getters and setters, use:\n\n```bash\nmunud -f test.yml cgen \n```\n\nThis will generate the following c code:\n\n```c\n#include \"assert.h\"\n#include \"stdint.h\"\n \n\ninline static uint8_t get_A(uint8_t *payload)\n{\n /*\n * This function retrives the value A (3 bits).\n * The value is found in byte 0.\n * The value starts at bit 0.\n */\n\n return payload[0] >> 5;\n}\n\ninline static void set_A(uint8_t *payload, uint8_t value)\n{\n /*\n * This function writes the value A (3 bits).\n * The value will be written in byte 0.\n * The value starts at bit 0.\n */\n\n payload[0] |= value << 5;\n}\n\n\ninline static uint16_t get_B(uint8_t *payload)\n{\n /*\n * This function retrives the value B (17 bits).\n * The value spreads between bytes 0 and 2.\n * The value starts at bit 3.\n */\n\n return (payload[0] & 0x1F) << 12 | payload[1] << 4 | payload[2] >> 4;\n}\n\ninline static void set_B(uint8_t *payload, uint16_t value)\n{\n /*\n * This function writes the value B (17 bits).\n * The value will spread between bytes 0 and 2.\n * The value starts at bit 3.\n */\n\n payload[0] |= (value >> 12) & 0x1F;\n payload[1] = (value >> 4) & 0xFF;\n payload[2] |= (value << 4) & 0xFF;\n}\n\n\ninline static uint8_t get_C(uint8_t *payload)\n{\n /*\n * This function retrives the value C (4 bits).\n * The value is found in byte 2.\n * The value starts at bit 4.\n */\n\n return payload[2] & 0x0F;\n}\n\ninline static void set_C(uint8_t *payload, uint8_t value)\n{\n /*\n * This function writes the value C (4 bits).\n * The value will be written in byte 20.\n * The value starts at bit 4.\n */\n\n payload[2] |= value;\n}\n\n\nstruct Payload\n{\n\n uint16_t B;\n uint8_t A;\n uint8_t C;\n};\n\n\n\ninline static void decode(struct Payload *payload, uint8_t *packed)\n{\n /*\n * \n */\n\n payload->A = get_A(packed);\n payload->B = get_B(packed);\n payload->C = get_C(packed);\n}\n\ninline static void encode(struct Payload *payload, uint8_t *packed)\n{\n /*\n * \n */\n\n set_A(packed, payload->A);\n set_B(packed, payload->B);\n set_C(packed, payload->C);\n}\n```\n\n\nMany options are available for customisation :\n\n```bash\n\n$ munud cgen --help\n\nUsage: munud.cmd cgen [OPTIONS]\n\nOptions:\n -f, --fmt TEXT A file describing the wanted format.\n -o, --output TEXT The output .h file.\n --crlf Use \\r\\n (crlf) as newline instead of \\n (crlf).\n --use-assert Generate assert check before writing to payload.\n --get-only Generate only getters.\n --set-only Generate only setters.\n --without-struct Do not generate a struct containing the payload.\n --packed-struct Add the gcc __attribute__((packed)) attribute to the\n struct.\n -n, --struct-name TEXT Payload struct name.\n --without-safety-mask Removes the 0xff mask when writing ints on bytes.\n --payload-type TEXT The type of the payload, usually uint8_t*.\n --cpp Generate cpp-style namespace.\n --namespace TEXT The name of an optional namespace. If cpp is not\n enabled, add it as a prefix.\n --help Show this message and exit.\n```\n\n# Development\n\nThis library uses poetry as a development tool.\n\nYou can start development by running :\n\n```bash\npoetry install\n```\n\n# Testing\n\nYou can test this library using :\n\n```bash\npoetry run pytest\n```\n\n# Tox\n\nYou can test multiple python versions using tox :\n\n```bash\npoetry run tox\n```\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Building sub-byte payloads, and generating according C code",
"version": "0.3.1",
"project_urls": null,
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "6e61c1cb243a5f15bf7df7e9861cbf99cf804d909a60aaadf355c40c359ea319",
"md5": "004c5d0ead88a3b7d49a9fb71b110ab6",
"sha256": "f1f211532e1780fa2340a483292cc29cb4aca361e5bad76db02f6cbc537df5e5"
},
"downloads": -1,
"filename": "munud-0.3.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "004c5d0ead88a3b7d49a9fb71b110ab6",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.9",
"size": 14539,
"upload_time": "2024-09-27T16:20:29",
"upload_time_iso_8601": "2024-09-27T16:20:29.844517Z",
"url": "https://files.pythonhosted.org/packages/6e/61/c1cb243a5f15bf7df7e9861cbf99cf804d909a60aaadf355c40c359ea319/munud-0.3.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "a6457ad5d4dda71ab4866f91fce7ff541799a68d281ba83e7ed723e5c82f8baa",
"md5": "ba6e3812b2253e5744c6e579442e49d1",
"sha256": "d4f1f59529e31abda1838998cbe528d5ec900e6f594ac819081c78b4f9a59e11"
},
"downloads": -1,
"filename": "munud-0.3.1.tar.gz",
"has_sig": false,
"md5_digest": "ba6e3812b2253e5744c6e579442e49d1",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.9",
"size": 14370,
"upload_time": "2024-09-27T16:20:31",
"upload_time_iso_8601": "2024-09-27T16:20:31.266559Z",
"url": "https://files.pythonhosted.org/packages/a6/45/7ad5d4dda71ab4866f91fce7ff541799a68d281ba83e7ed723e5c82f8baa/munud-0.3.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-09-27 16:20:31",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "munud"
}