Skip to content

Latest commit

 

History

History
210 lines (153 loc) · 6.75 KB

File metadata and controls

210 lines (153 loc) · 6.75 KB

Contributing

Contributions are welcome and appreciated — whether it's a bug report, a new feature, a test frame, or a documentation fix. Don't hesitate to open an issue or ask questions.


Table of Contents


Getting oriented

Before diving into the code, build some intuition for what the parser does:

  1. Open the live parser in your browser.
  2. Go to tests/rscada/test-frames/ in this repo and open any .hex file — for example:
    68 3C 3C 68 08 08 72 78 03 49 11 77 04 0E 16 0A 00 00 00 0C 78 78 03 49 11
    04 13 31 D4 00 00 42 6C 00 00 44 13 00 00 00 00 04 6D 0B 0B CD 13 02 27 00
    00 09 FD 0E 02 09 FD 0F 06 0F 00 01 75 13 D3 16
    
  3. Paste it into tmbus and explore the decoded output.
  4. Compare with what this parser produces:
    cargo run -p m-bus-parser-cli -- parse -d "68 3C 3C 68 ..." -t table

The corresponding .xml file in the same folder shows the expected parsed values.

Useful background reading:


Setting up

Prerequisites: Rust toolchain, git.

# Install Rust if you don't have it
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Clone the repo
git clone https://github.com/maebli/m-bus-parser.git
cd m-bus-parser

# Run all tests to confirm everything works
cargo test --all-features

# Build the CLI
cargo build -p m-bus-parser-cli

# Try parsing a frame
cargo run -p m-bus-parser-cli -- parse \
  -d "68 3C 3C 68 08 08 72 78 03 49 11 77 04 0E 16 0A 00 00 00 0C 78 78 03 49 11 04 13 31 D4 00 00 42 6C 00 00 44 13 00 00 00 00 04 6D 0B 0B CD 13 02 27 00 00 09 FD 0E 02 09 FD 0F 06 0F 00 01 75 13 D3 16" \
  -t table

Optional — rebuild the WebAssembly package:

cargo install wasm-pack
wasm-pack build wasm --target web --out-dir ../docs

Project structure

m-bus-parser/
├── src/                        # Main library (serialize_mbus_data, output formats)
│   ├── mbus_data.rs            # All output format functions (table, json, yaml, csv, mermaid)
│   └── manufacturers.rs        # FLAG manufacturer code lookup (std-only)
├── crates/
│   ├── m-bus-core/             # Shared types (ManufacturerCode, FrameError, …)
│   ├── m-bus-application-layer/# Application layer parsing (DIF/VIF, data records)
│   ├── wired-mbus-link-layer/  # Wired frame parsing (long/short/control frames)
│   └── wireless-mbus-link-layer/ # Wireless frame parsing + Format A CRC stripping
├── cli/                        # CLI binary (m-bus-parser-cli)
├── wasm/                       # WebAssembly bindings (wasm-bindgen)
├── python/                     # Python bindings (PyO3)
├── docs/                       # GitHub Pages web app + compiled WASM
├── tests/
│   └── rscada/test-frames/     # Real-world .hex test frames + expected .xml output
└── examples/
    └── cortex-m/               # Embedded no_std example

The src/ crate is the public API. It ties together the inner crates and provides the serialize_mbus_data(data, format, key) function used by the CLI, WASM, and Python bindings.


Making changes

  1. Create a branch from main:

    git checkout -b fix/your-fix
    # or
    git checkout -b feature/your-feature
  2. Make your changes. Some common areas:

    • Adding a missing VIF/DIF code → crates/m-bus-application-layer/
    • Fixing a parsing bug → relevant inner crate
    • Adding a manufacturer → src/manufacturers.rs (add a new match arm)
    • Improving an output format → src/mbus_data.rs
    • Adding a CI field type → crates/m-bus-application-layer/
  3. Add a test if applicable. For a new device frame, add a .hex file to tests/rscada/test-frames/ and a corresponding test.


Testing

# Run all tests
cargo test --all-features

# Run tests for a specific crate
cargo test -p m-bus-application-layer

# Run a specific test by name
cargo test test_mermaid_expected_output

Test frames in tests/rscada/test-frames/ are real-world captures from devices. The .hex file is the raw frame; the .xml file is the expected parsed output.


CI checks

The CI pipeline runs these checks — make sure they all pass before opening a PR:

# Formatting
cargo fmt --check

# Lints (zero warnings policy)
cargo clippy --all-targets --all-features -- -D warnings

# Tests
cargo test --all-features

# no_std build (embedded target)
cargo build --target thumbv7m-none-eabi --no-default-features

To auto-fix formatting and simple clippy suggestions:

cargo fmt
cargo clippy --fix --all-features

Opening a pull request

  1. Push your branch and open a PR against main
  2. Fill in the PR description — what changed and why
  3. Make sure CI is green
  4. A maintainer will review and merge

Commit message convention (loosely followed):

feat: add VIF code 0x3E
fix: handle missing CRC in Format A frames
docs: improve contributing guide

Good first contributions

  • Add a missing manufacturer — check src/manufacturers.rs. If you encounter a 3-letter code that returns None, look it up in the DLMS FLAG ID directory and add it.
  • Add a test frame — capture a real device frame, add it to tests/rscada/test-frames/ with the expected output, and wire it into the test suite.
  • Implement a missing CI type — the list of unimplemented CI fields is in the README. Pick one and implement it in crates/m-bus-application-layer/.
  • Improve error messages — many parse errors are just Unimplemented; a more descriptive message helps users.

Releasing

Releases bump the version in all four crates:

cargo release version patch --execute
cd python  && cargo release version patch --execute && cd ..
cd wasm    && cargo release version patch --execute && cd ..
cd cli     && cargo release version patch --execute && cd ..

Then push the tags and let CI publish to crates.io / npm / PyPI.


Code of conduct

This project follows the Rust Code of Conduct. Be kind and constructive.