From 9c2b1806a1fab40c289389cc60afd67448a42f35 Mon Sep 17 00:00:00 2001 From: parallels Date: Wed, 22 Apr 2026 18:12:57 -0700 Subject: [PATCH 01/11] Initial INA4230 quad-channel power monitor driver implementation --- .github/workflows/device-driver.yml | 34 + .gitignore | 4 + Cargo.lock | 365 +- Cargo.toml | 40 +- INA4230.toml | 751 +++ README.md | 189 +- src/device.rs | 6600 +++++++++++++++++++++++++++ src/lib.rs | 474 ++ 8 files changed, 8404 insertions(+), 53 deletions(-) create mode 100644 .github/workflows/device-driver.yml create mode 100644 INA4230.toml create mode 100644 src/device.rs create mode 100644 src/lib.rs diff --git a/.github/workflows/device-driver.yml b/.github/workflows/device-driver.yml new file mode 100644 index 0000000..0b349bc --- /dev/null +++ b/.github/workflows/device-driver.yml @@ -0,0 +1,34 @@ +# Verifies that src/device.rs stays in sync with the code generated from ina4230.toml. +permissions: + contents: read +on: + push: + branches: [main] + pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true +name: device-driver-pregen-check +jobs: + device-driver-pregen-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install stable + uses: dtolnay/rust-toolchain@stable + with: { components: rustfmt } + - name: Install device-driver-cli + uses: baptiste0928/cargo-install@v3 + with: + crate: device-driver-cli + - name: Generate device.rs from ina4230.toml + run: device-driver-cli --manifest ina4230.toml --device-name Device -o ci_gen.rs + - name: Format generated file + run: rustfmt --edition 2024 ci_gen.rs + - name: Check generated file matches committed src/device.rs + uses: LouisBrunner/diff-action@v3.0.0 + with: + old: ci_gen.rs + new: src/device.rs + mode: strict + tolerance: same diff --git a/.gitignore b/.gitignore index 26fc367..d3049c1 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,7 @@ target/ # MSVC Windows builds of rustc generate these, which store debugging information *.pdb +/target +Cargo.lock +/target +Cargo.lock diff --git a/Cargo.lock b/Cargo.lock index f1c4f76..49712db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,5 +3,368 @@ version = 4 [[package]] -name = "embedded-rust-template" +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "defmt" +version = "0.3.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad" +dependencies = [ + "defmt 1.0.1", +] + +[[package]] +name = "defmt" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" +dependencies = [ + "bitflags", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" +dependencies = [ + "defmt-parser", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror", +] + +[[package]] +name = "device-driver" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aa3d97b2acf349b9d52c75470e2ccfc7224c49597ec12c2fb0e28826e910495" +dependencies = [ + "defmt 0.3.100", + "embedded-io", + "embedded-io-async", +] + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + +[[package]] +name = "embedded-hal-mock" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a0f04f8886106faf281c47b6a0e4054a369baedaf63591fdb8da9761f3f379" +dependencies = [ + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-hal-nb", + "embedded-time", + "nb 1.1.0", + "void", +] + +[[package]] +name = "embedded-hal-nb" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605" +dependencies = [ + "embedded-hal 1.0.0", + "nb 1.1.0", +] + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" +dependencies = [ + "defmt 0.3.100", +] + +[[package]] +name = "embedded-io-async" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" +dependencies = [ + "embedded-io", +] + +[[package]] +name = "embedded-sensors-hal" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c703756bee31e7aaf55d8fb6dcf7337cfc231cfb4a3ad34b9df509846fd9001" +dependencies = [ + "defmt 1.0.1", + "paste", +] + +[[package]] +name = "embedded-sensors-hal-async" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e51dce2828cbbbca20bd69857628584deccae0fa4e7724f3fceb5d197bdffb0" +dependencies = [ + "defmt 1.0.1", + "embedded-sensors-hal", + "paste", +] + +[[package]] +name = "embedded-time" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a4b4d10ac48d08bfe3db7688c402baadb244721f30a77ce360bd24c3dffe58" +dependencies = [ + "num", +] + +[[package]] +name = "ina4230" version = "0.1.0" +dependencies = [ + "defmt 0.3.100", + "device-driver", + "embedded-hal-async", + "embedded-hal-mock", + "embedded-sensors-hal-async", + "tokio", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "num" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" +dependencies = [ + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio" +version = "1.52.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" +dependencies = [ + "pin-project-lite", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/Cargo.toml b/Cargo.toml index 71c4806..1a6cdc7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,19 +1,43 @@ [package] -name = "embedded-rust-template" +name = "ina4230" version = "0.1.0" -edition = "2021" +repository = "https://github.com/OpenDevicePartnership/ina4230" license = "MIT" -repository = "https://github.com/OpenDevicePartnership/embedded-rust-template" -rust-version = "1.85" +description = "Platform-agnostic Rust driver for the Texas Instruments INA4230 quad-channel power and energy sense monitor." +readme = "README.md" +keywords = ["TI", "power-monitor", "energy", "driver", "embedded-hal-driver"] +categories = ["embedded", "hardware-support", "no-std"] +documentation = "https://docs.rs/ina4230" +include = ["/**/*.rs", "/Cargo.toml", "/README.md", "/LICENSE", "/ina4230.toml"] +edition = "2024" [dependencies] -# dependencies for all targets +device-driver = { version = "1.0.7", default-features = false } +defmt = { version = "0.3", optional = true } +embedded-hal-async = "1.0.0" +embedded-sensors-hal-async = "0.4.0" -[target.'cfg(target_os = "none")'.dependencies] -# dependencies for no-std targets +[dev-dependencies] +embedded-hal-mock = { version = "0.11.1", features = ["embedded-hal-async"] } +tokio = { version = "1", features = ["rt", "macros"] } + +[lib] +doctest = false + +[lints.rust] +unsafe_code = "deny" +missing_docs = "deny" [lints.clippy] -suspicious = "forbid" correctness = "forbid" +suspicious = "forbid" perf = "forbid" style = "forbid" +pedantic = "deny" + +[features] +defmt-03 = [ + "dep:defmt", + "device-driver/defmt-03", + "embedded-sensors-hal-async/defmt", +] diff --git a/INA4230.toml b/INA4230.toml new file mode 100644 index 0000000..5d2afaf --- /dev/null +++ b/INA4230.toml @@ -0,0 +1,751 @@ +[config] +register_address_type = "u8" +default_byte_order = "BE" +name_word_boundaries = ["Hyphen"] +defmt_feature = "defmt-03" +# ============================================================ +# CONFIG1 Register (Address = 0x20, Reset = 0xF127) +# ============================================================ + +[config1] +type = "register" +address = 0x20 +size_bits = 16 +access = "RW" +reset_value = 0xF127 +description = "Configuration register 1" + +[config1.fields.active-channel] +description = "Active channel enable bits. Bit15=CH4, Bit14=CH3, Bit13=CH2, Bit12=CH1" +base = "uint" +start = 12 +end = 16 + +[config1.fields.avg] +description = "Number of ADC conversion results to average" +base = "uint" +start = 9 +end = 12 + +[config1.fields.avg.conversion] +name = "averaging" +description = "Averaging count" +_1 = 0 +_4 = 1 +_16 = 2 +_64 = 3 +_128 = 4 +_256 = 5 +_512 = 6 +_1024 = 7 + +[config1.fields.vbusct] +description = "Bus voltage conversion time" +base = "uint" +start = 6 +end = 9 + +[config1.fields.vbusct.conversion] +name = "bus-conversion-time" +description = "Bus voltage conversion time" +_140-us = 0 +_204-us = 1 +_332-us = 2 +_588-us = 3 +_1100-us = 4 +_2116-us = 5 +_4156-us = 6 +_8244-us = 7 + +[config1.fields.vshct] +description = "Shunt voltage conversion time" +base = "uint" +start = 3 +end = 6 + +[config1.fields.vshct.conversion] +name = "shunt-conversion-time" +description = "Shunt voltage conversion time" +_140-us = 0 +_204-us = 1 +_332-us = 2 +_588-us = 3 +_1100-us = 4 +_2116-us = 5 +_4156-us = 6 +_8244-us = 7 + +[config1.fields.mode] +description = "Operating mode" +base = "uint" +start = 0 +end = 3 + +[config1.fields.mode.conversion] +name = "mode" +description = "Operating mode" +shutdown = 0 +shunt-triggered = 1 +bus-triggered = 2 +shunt-and-bus-triggered = 3 +shutdown-2 = 4 +continuous-shunt = 5 +continuous-bus = 6 +continuous-shunt-and-bus = 7 + +# ============================================================ +# CONFIG2 Register (Address = 0x21, Reset = 0x0000) +# ============================================================ + +[config2] +type = "register" +address = 0x21 +size_bits = 16 +access = "RW" +reset_value = 0x0000 +description = "Configuration register 2" + +[config2.fields.rst] +description = "System reset. Set to 1 to reset all registers to default. Self-clears." +base = "bool" +start = 15 +end = 16 + +[config2.fields.acc-rst] +description = "Energy accumulator reset per channel. Bit11=CH4, Bit10=CH3, Bit9=CH2, Bit8=CH1. Bits self-clear after write." +base = "uint" +start = 8 +end = 12 + +[config2.fields.cnvr-mask] +description = "Conversion ready flag on ALERT pin enable" +base = "bool" +start = 7 +end = 8 + +[config2.fields.enof-mask] +description = "Energy overflow alert enable" +base = "bool" +start = 6 +end = 7 + +[config2.fields.alert-latch] +description = "Alert pin latch enable. When set, alert latches until flags register is read." +base = "bool" +start = 5 +end = 6 + +[config2.fields.alert-pol] +description = "Alert pin polarity" +base = "uint" +start = 4 +end = 5 + +[config2.fields.alert-pol.conversion] +name = "alert-polarity" +active-low = 0 +active-high = 1 + +[config2.fields.range] +description = "Shunt full scale input range per channel. Bit3=CH4, Bit2=CH3, Bit1=CH2, Bit0=CH1. 0=±81.92mV, 1=±20.48mV" +base = "uint" +start = 0 +end = 4 + +# ============================================================ +# CALIBRATION Registers (per channel) +# ============================================================ + +[calibration-ch1] +type = "register" +address = 0x05 +size_bits = 16 +access = "RW" +reset_value = 0x0000 +description = "Calibration register channel 1" + +[calibration-ch1.fields.shunt-cal] +description = "Shunt calibration value for current conversion" +base = "uint" +start = 0 +end = 15 + +[calibration-ch2] +type = "register" +address = 0x0D +size_bits = 16 +access = "RW" +reset_value = 0x0000 +description = "Calibration register channel 2" + +[calibration-ch2.fields.shunt-cal] +description = "Shunt calibration value for current conversion" +base = "uint" +start = 0 +end = 15 + +[calibration-ch3] +type = "register" +address = 0x15 +size_bits = 16 +access = "RW" +reset_value = 0x0000 +description = "Calibration register channel 3" + +[calibration-ch3.fields.shunt-cal] +description = "Shunt calibration value for current conversion" +base = "uint" +start = 0 +end = 15 + +[calibration-ch4] +type = "register" +address = 0x1D +size_bits = 16 +access = "RW" +reset_value = 0x0000 +description = "Calibration register channel 4" + +[calibration-ch4.fields.shunt-cal] +description = "Shunt calibration value for current conversion" +base = "uint" +start = 0 +end = 15 + +# ============================================================ +# ALERT_CONFIG Registers (per alert slot) +# ============================================================ + +[alert-config-1] +type = "register" +address = 0x07 +size_bits = 16 +access = "RW" +reset_value = 0x0000 +description = "Alert configuration register 1" + +[alert-config-1.fields.channel] +description = "Channel assignment for this alert" +base = "uint" +start = 3 +end = 5 + +[alert-config-1.fields.channel.conversion] +name = "alert-channel" +ch1 = 0 +ch2 = 1 +ch3 = 2 +ch4 = 3 + +[alert-config-1.fields.alert-mask] +description = "Active alert function selection" +base = "uint" +start = 0 +end = 3 + +[alert-config-1.fields.alert-mask.conversion] +name = "alert-function" +none = 0 +shunt-over-limit = 1 +shunt-under-limit = 2 +bus-over-limit = 3 +bus-under-limit = 4 +power-over-limit = 5 +reserved-6 = 6 +reserved-7 = 7 + +[alert-config-2] +type = "register" +address = 0x0F +size_bits = 16 +access = "RW" +reset_value = 0x0000 +description = "Alert configuration register 2" + +[alert-config-2.fields.channel] +description = "Channel assignment for this alert" +base = "uint" +start = 3 +end = 5 + + +[alert-config-2.fields.alert-mask] +description = "Active alert function selection" +base = "uint" +start = 0 +end = 3 + + +[alert-config-3] +type = "register" +address = 0x17 +size_bits = 16 +access = "RW" +reset_value = 0x0000 +description = "Alert configuration register 3" + +[alert-config-3.fields.channel] +description = "Channel assignment for this alert" +base = "uint" +start = 3 +end = 5 + + +[alert-config-3.fields.alert-mask] +description = "Active alert function selection" +base = "uint" +start = 0 +end = 3 + + +[alert-config-4] +type = "register" +address = 0x1F +size_bits = 16 +access = "RW" +reset_value = 0x0000 +description = "Alert configuration register 4" + +[alert-config-4.fields.channel] +description = "Channel assignment for this alert" +base = "uint" +start = 3 +end = 5 + + +[alert-config-4.fields.alert-mask] +description = "Active alert function selection" +base = "uint" +start = 0 +end = 3 + + +# ============================================================ +# ALERT_LIMIT Registers (per alert slot) +# ============================================================ + +[alert-limit-1] +type = "register" +address = 0x06 +size_bits = 16 +access = "RW" +reset_value = 0x0000 +description = "Alert limit register 1. Format matches corresponding result register." + +[alert-limit-1.fields.limit] +description = "Alert threshold. Shunt=signed 16-bit, Bus=unsigned 15-bit, Power=unsigned 16-bit" +base = "uint" +start = 0 +end = 16 + +[alert-limit-2] +type = "register" +address = 0x0E +size_bits = 16 +access = "RW" +reset_value = 0x0000 +description = "Alert limit register 2" + +[alert-limit-2.fields.limit] +description = "Alert threshold" +base = "uint" +start = 0 +end = 16 + +[alert-limit-3] +type = "register" +address = 0x16 +size_bits = 16 +access = "RW" +reset_value = 0x0000 +description = "Alert limit register 3" + +[alert-limit-3.fields.limit] +description = "Alert threshold" +base = "uint" +start = 0 +end = 16 + +[alert-limit-4] +type = "register" +address = 0x1E +size_bits = 16 +access = "RW" +reset_value = 0x0000 +description = "Alert limit register 4" + +[alert-limit-4.fields.limit] +description = "Alert threshold" +base = "uint" +start = 0 +end = 16 + +# ============================================================ +# SHUNT_VOLTAGE Registers (per channel, read-only) +# ============================================================ + +[shunt-voltage-ch1] +type = "register" +address = 0x00 +size_bits = 16 +access = "RO" +description = "Shunt voltage channel 1. 2's complement. LSB = 2.5uV (range=0) or 625nV (range=1)" + +[shunt-voltage-ch1.fields.vshunt] +description = "Differential shunt voltage, 2's complement" +base = "uint" +start = 0 +end = 16 + +[shunt-voltage-ch2] +type = "register" +address = 0x08 +size_bits = 16 +access = "RO" +description = "Shunt voltage channel 2" + +[shunt-voltage-ch2.fields.vshunt] +description = "Differential shunt voltage, 2's complement" +base = "uint" +start = 0 +end = 16 + +[shunt-voltage-ch3] +type = "register" +address = 0x10 +size_bits = 16 +access = "RO" +description = "Shunt voltage channel 3" + +[shunt-voltage-ch3.fields.vshunt] +description = "Differential shunt voltage, 2's complement" +base = "uint" +start = 0 +end = 16 + +[shunt-voltage-ch4] +type = "register" +address = 0x18 +size_bits = 16 +access = "RO" +description = "Shunt voltage channel 4" + +[shunt-voltage-ch4.fields.vshunt] +description = "Differential shunt voltage, 2's complement" +base = "uint" +start = 0 +end = 16 + +# ============================================================ +# BUS_VOLTAGE Registers (per channel, read-only) +# ============================================================ + +[bus-voltage-ch1] +type = "register" +address = 0x01 +size_bits = 16 +access = "RO" +description = "Bus voltage channel 1. Always positive. LSB = 1.6mV" + +[bus-voltage-ch1.fields.vbus] +description = "Bus voltage, always positive, 2's complement format" +base = "uint" +start = 0 +end = 16 + +[bus-voltage-ch2] +type = "register" +address = 0x09 +size_bits = 16 +access = "RO" +description = "Bus voltage channel 2" + +[bus-voltage-ch2.fields.vbus] +description = "Bus voltage" +base = "uint" +start = 0 +end = 16 + +[bus-voltage-ch3] +type = "register" +address = 0x11 +size_bits = 16 +access = "RO" +description = "Bus voltage channel 3" + +[bus-voltage-ch3.fields.vbus] +description = "Bus voltage" +base = "uint" +start = 0 +end = 16 + +[bus-voltage-ch4] +type = "register" +address = 0x19 +size_bits = 16 +access = "RO" +description = "Bus voltage channel 4" + +[bus-voltage-ch4.fields.vbus] +description = "Bus voltage" +base = "uint" +start = 0 +end = 16 + +# ============================================================ +# CURRENT Registers (per channel, read-only) +# ============================================================ + +[current-ch1] +type = "register" +address = 0x02 +size_bits = 16 +access = "RO" +description = "Current channel 1. Value [A] = CURRENT_LSB x register_value" + +[current-ch1.fields.current] +description = "Calculated current in amperes, 2's complement" +base = "uint" +start = 0 +end = 16 + +[current-ch2] +type = "register" +address = 0x0A +size_bits = 16 +access = "RO" +description = "Current channel 2" + +[current-ch2.fields.current] +description = "Calculated current in amperes, 2's complement" +base = "uint" +start = 0 +end = 16 + +[current-ch3] +type = "register" +address = 0x12 +size_bits = 16 +access = "RO" +description = "Current channel 3" + +[current-ch3.fields.current] +description = "Calculated current in amperes, 2's complement" +base = "uint" +start = 0 +end = 16 + +[current-ch4] +type = "register" +address = 0x1A +size_bits = 16 +access = "RO" +description = "Current channel 4" + +[current-ch4.fields.current] +description = "Calculated current in amperes, 2's complement" +base = "uint" +start = 0 +end = 16 + +# ============================================================ +# POWER Registers (per channel, read-only) +# ============================================================ + +[power-ch1] +type = "register" +address = 0x03 +size_bits = 16 +access = "RO" +description = "Power channel 1. Value [W] = 32 x CURRENT_LSB x register_value. Unsigned." + +[power-ch1.fields.power] +description = "Calculated power in watts, unsigned" +base = "uint" +start = 0 +end = 16 + +[power-ch2] +type = "register" +address = 0x0B +size_bits = 16 +access = "RO" +description = "Power channel 2" + +[power-ch2.fields.power] +description = "Calculated power in watts, unsigned" +base = "uint" +start = 0 +end = 16 + +[power-ch3] +type = "register" +address = 0x13 +size_bits = 16 +access = "RO" +description = "Power channel 3" + +[power-ch3.fields.power] +description = "Calculated power in watts, unsigned" +base = "uint" +start = 0 +end = 16 + +[power-ch4] +type = "register" +address = 0x1B +size_bits = 16 +access = "RO" +description = "Power channel 4" + +[power-ch4.fields.power] +description = "Calculated power in watts, unsigned" +base = "uint" +start = 0 +end = 16 + +# ============================================================ +# ENERGY Registers (per channel, read-only, 32-bit) +# ============================================================ + +[energy-ch1] +type = "register" +address = 0x04 +size_bits = 32 +access = "RO" +description = "Energy channel 1. Value [J] = 32 x CURRENT_LSB x register_value. Unsigned." + +[energy-ch1.fields.energy] +description = "Accumulated energy in joules, unsigned" +base = "uint" +start = 0 +end = 32 + +[energy-ch2] +type = "register" +address = 0x0C +size_bits = 32 +access = "RO" +description = "Energy channel 2" + +[energy-ch2.fields.energy] +description = "Accumulated energy in joules, unsigned" +base = "uint" +start = 0 +end = 32 + +[energy-ch3] +type = "register" +address = 0x14 +size_bits = 32 +access = "RO" +description = "Energy channel 3" + +[energy-ch3.fields.energy] +description = "Accumulated energy in joules, unsigned" +base = "uint" +start = 0 +end = 32 + +[energy-ch4] +type = "register" +address = 0x1C +size_bits = 32 +access = "RO" +description = "Energy channel 4" + +[energy-ch4.fields.energy] +description = "Accumulated energy in joules, unsigned" +base = "uint" +start = 0 +end = 32 + +# ============================================================ +# FLAGS Register (Address = 0x22, read-only) +# ============================================================ + +[flags] +type = "register" +address = 0x22 +size_bits = 16 +access = "RO" +reset_value = 0x0000 +description = "Flags register" + +[flags.fields.limit4-alert] +description = "Alert limit 4 exceeded" +base = "bool" +start = 15 +end = 16 + +[flags.fields.limit3-alert] +description = "Alert limit 3 exceeded" +base = "bool" +start = 14 +end = 15 + +[flags.fields.limit2-alert] +description = "Alert limit 2 exceeded" +base = "bool" +start = 13 +end = 14 + +[flags.fields.limit1-alert] +description = "Alert limit 1 exceeded" +base = "bool" +start = 12 +end = 13 + +[flags.fields.energyof-ch4] +description = "Energy register overflow channel 4" +base = "bool" +start = 11 +end = 12 + +[flags.fields.energyof-ch3] +description = "Energy register overflow channel 3" +base = "bool" +start = 10 +end = 11 + +[flags.fields.energyof-ch2] +description = "Energy register overflow channel 2" +base = "bool" +start = 9 +end = 10 + +[flags.fields.energyof-ch1] +description = "Energy register overflow channel 1" +base = "bool" +start = 8 +end = 9 + +[flags.fields.cvrf] +description = "Conversion ready flag. Set when all conversions and averaging complete. Cleared by writing CONFIG1 or reading FLAGS." +base = "bool" +start = 7 +end = 8 + +[flags.fields.ovf] +description = "Math overflow flag. Indicates current and power data may be invalid." +base = "bool" +start = 6 +end = 7 + +# ============================================================ +# MANUFACTURER_ID Register (Address = 0x7E, read-only) +# ============================================================ + +[manufacturer-id] +type = "register" +address = 0x7E +size_bits = 16 +access = "RO" +reset_value = 0x5449 +description = "Manufacturer ID. Reads back 0x5449 ('TI' in ASCII)" + +[manufacturer-id.fields.id] +description = "Manufacturer ID" +base = "uint" +start = 0 +end = 16 diff --git a/README.md b/README.md index 60b09c0..e7c4ab0 100644 --- a/README.md +++ b/README.md @@ -1,63 +1,164 @@ -# embedded-rust-template -Template repository for Embedded Rust development +# INA4230 Rust Device Driver -## Customizing This Template +A `#[no_std]` platform-agnostic driver for the [INA4230](https://www.ti.com/lit/ds/symlink/ina4230.pdf) +quad-channel power and energy sense monitor, based on the [`embedded-hal`](https://docs.rs/embedded-hal) traits. -### Changing the Target Architecture +Higher-level measurement APIs are built on the [embedded-sensors](https://github.com/OpenDevicePartnership/embedded-sensors) +async sensor traits (`VoltageSensor`, `CurrentSensor`, `PowerSensor`, `EnergySensor`). -This template is configured for `thumbv8m.main-none-eabihf`, by default, but you can modify it for other targets (i.e. `aarch64-unknown-none`): +## Features -1. **VSCode Settings**: Update the target in `.vscode/settings.json`: - ```json - "rust-analyzer.cargo.target": "your-target-architecture" - ``` +- Full register coverage via pre-generated `src/device.rs` (generated from `INA4230.toml` using `device-driver-cli`) +- Async-first I²C interface (`embedded-hal-async`) +- Four independent measurement channels (bus voltage, shunt voltage, current, power, energy) +- Calibration helpers with correct SHUNT_CAL formula +- ADC range selection (±81.92 mV or ±20.48 mV full scale) +- Optional `defmt-03` logging support +- `no_std` compatible +## Usage -This configuration ensures that: -- Only the specified target architecture is analyzed, not the host platform -- Code is checked against the no_std environment +```toml +[dependencies] +ina4230 = "0.1.0" +embedded-hal-async = "1" +``` -To temporarily analyze code for the host platform instead, you can remove the `rust-analyzer.cargo.target` setting. +```rust,no_run +use ina4230::{AdcRange, Channel, CurrentSensor, Ina4230, INA4230_ADDR, PowerSensor, VoltageSensor}; -2. **GitHub Workflows**: Modify the target in two workflow files: - - `.github/workflows/nostd.yml`: Update the targets in the matrix: - ```yaml - matrix: - target: [your-target-architecture] - ``` - - `.github/workflows/check.yml`: If there are any target-specific checks, update them accordingly. +// i2c implements embedded_hal_async::i2c::I2c +let mut sensor = Ina4230::new(i2c, INA4230_ADDR); -3. **Cargo Configuration**: If needed, you can add target-specific configuration in a `.cargo/config.toml` file. +// Reset, then calibrate before taking measurements +sensor.reset().await?; +sensor.calibrate(Channel::Ch1, CURRENT_LSB_CH1, SHUNT_OHMS_CH1, AdcRange::Range0).await?; -### Converting from Binary to Library +// Wait for conversion +while !sensor.conversion_ready().await? {} -To convert this project from a binary to a library: +// Read channel 1 +let vbus_mv = sensor.bus_voltage(Channel::Ch1).await?; +let ima = sensor.current(Channel::Ch1).await?; +let pmw = sensor.power(Channel::Ch1).await?; +``` -1. **Cargo.toml**: Update your project structure: - ```toml - [lib] - name = "your_library_name" - ``` +## Configuration -2. **Directory Structure**: - - For a library, ensure you have a `src/lib.rs` file instead of `src/main.rs` - - Move your code from `main.rs` to `lib.rs` and adjust as needed +Before taking measurements, two hardware-specific parameters must be set per channel. -3. **No-std Configuration**: If you're creating a no-std library, ensure you have: - ```rust - // In lib.rs - #![cfg_attr(target_os = "none", no_std)] - // Add other attributes as needed - ``` +### Shunt Resistor Value -### Project Dependencies +Set `SHUNT_OHMS_CHx` to the resistance of the shunt resistor fitted on that channel, in ohms: -Update the dependencies in `Cargo.toml` based on your target platform: +```rust,no_run +const SHUNT_OHMS_CH1: f32 = 0.010; // 10 mΩ shunt on channel 1 +``` -```toml -[dependencies] -# Common dependencies for all targets +Use a precision resistor (0.1% tolerance or better) for accurate results. +For very low value shunts, use Kelvin (4-wire) connections to eliminate +lead resistance errors. + +### Current Resolution + +`CURRENT_LSB` determines the resolution of the current measurement. A smaller +value gives finer resolution but a lower full-scale range; a larger value gives +a wider range but coarser resolution. The current register is 16-bit signed, +giving 32767 steps above zero. -[target.'cfg(target_os = "none")'.dependencies] -# Dependencies for no-std targets +Set `MAX_CURRENT_CHx` to the maximum current you expect on that channel — the +driver calculates the optimal `CURRENT_LSB` automatically: + +```rust,no_run +// Example: expecting up to 100 mA on channel 1 +const MAX_CURRENT_CH1: f32 = 0.1; // amps +const CURRENT_LSB_CH1: f32 = MAX_CURRENT_CH1 / 32767.0; // ~3.05 µA/LSB ``` + +The driver uses `CURRENT_LSB` to compute the `SHUNT_CAL` register value +written during `calibrate()`: + +``` +SHUNT_CAL = 0.00512 / (CURRENT_LSB × R_SHUNT) +``` + +And to convert the raw current register reading back to milliamperes: + +``` +Current [mA] = raw × CURRENT_LSB × 1000 +``` + +If `MAX_CURRENT_CHx` is set too low, the current register will saturate and +readings will be clamped. If set too high, resolution will be unnecessarily +coarse. + +### ADC Range + +The INA4230 supports two shunt input voltage ranges, configured via `AdcRange`: + +| `AdcRange` | Full-scale range | LSB | +|--------------------|-----------------|--------| +| `Range0` (default) | ±81.92 mV | 2.5 µV | +| `Range1` | ±20.48 mV | 625 nV | + +`Range0` is the default and suits most applications. Use `Range1` for higher +resolution when measuring small currents through a large shunt resistor. + +When using `Range1`, the `SHUNT_CAL` register value is automatically divided +by 4 and the shunt voltage LSB is adjusted to 625 nV: + +``` +Range0: SHUNT_CAL = 0.00512 / (CURRENT_LSB × R_SHUNT) +Range1: SHUNT_CAL = 0.00512 / (CURRENT_LSB × R_SHUNT) / 4 +``` + +### Calibration + +The calibration register serves two purposes: it provides the device with +the shunt resistor value used to calculate current from the measured +differential voltage, and it sets the resolution of the current and power +registers through the `CURRENT_LSB` and `Power_LSB` values. + +Call `calibrate()` before taking current, power, or energy measurements: + +```rust,no_run +sensor.calibrate(Channel::Ch1, CURRENT_LSB_CH1, SHUNT_OHMS_CH1, AdcRange::Range0).await?; +``` + +The calibration register must be programmed after initial power up, power +cycle events, or device enable to receive valid current, power, and energy +results. Bus voltage and shunt voltage readings do not require calibration. + +## I²C Addresses + +| A1 | A0 | Address | +|-----|-----|---------| +| GND | GND | `0x40` | +| GND | VS | `0x41` | +| VS | GND | `0x44` | +| VS | VS | `0x45` | + +## Regenerating `src/device.rs` + +```sh +cargo install device-driver-cli +device-driver-cli -m INA4230.toml -o generated.rs -d Device +rustfmt --edition 2024 generated.rs +cp generated.rs src/device.rs +``` + +## MSRV + +Rust `1.88` and up. + +## License + +Licensed under the terms of the [MIT license](http://opensource.org/licenses/MIT). + +## Contribution + +Unless you explicitly state otherwise, any contribution submitted for +inclusion in the work by you shall be licensed under the terms of the +MIT license. + +License: MIT diff --git a/src/device.rs b/src/device.rs new file mode 100644 index 0000000..a9fbe60 --- /dev/null +++ b/src/device.rs @@ -0,0 +1,6600 @@ +/// Root block of the Device driver +#[derive(Debug)] +pub struct Device { + pub(crate) interface: I, + #[doc(hidden)] + base_address: u8, +} +impl Device { + /// Create a new instance of the block based on device interface + pub const fn new(interface: I) -> Self { + Self { + interface, + base_address: 0, + } + } + /// A reference to the interface used to communicate with the device + pub(crate) fn interface(&mut self) -> &mut I { + &mut self.interface + } + /// Read all readable register values in this block from the device. + /// The callback is called for each of them. + /// Any registers in child blocks are not included. + /// + /// The callback has three arguments: + /// + /// - The address of the register + /// - The name of the register (with index for repeated registers) + /// - The read value from the register + /// + /// This is useful for e.g. debug printing all values. + /// The given [field_sets::FieldSetValue] has a Debug and Format implementation that forwards to the concrete type + /// the lies within so it can be printed without matching on it. + #[allow(unused_mut)] + #[allow(unused_variables)] + pub fn read_all_registers( + &mut self, + mut callback: impl FnMut(u8, &'static str, field_sets::FieldSetValue), + ) -> Result<(), I::Error> + where + I: ::device_driver::RegisterInterface, + { + let reg = self.config_1().read()?; + callback(32 + 0 * 0, "config_1", reg.into()); + let reg = self.config_2().read()?; + callback(33 + 0 * 0, "config_2", reg.into()); + let reg = self.calibration_ch_1().read()?; + callback(5 + 0 * 0, "calibration_ch_1", reg.into()); + let reg = self.calibration_ch_2().read()?; + callback(13 + 0 * 0, "calibration_ch_2", reg.into()); + let reg = self.calibration_ch_3().read()?; + callback(21 + 0 * 0, "calibration_ch_3", reg.into()); + let reg = self.calibration_ch_4().read()?; + callback(29 + 0 * 0, "calibration_ch_4", reg.into()); + let reg = self.alert_config_1().read()?; + callback(7 + 0 * 0, "alert_config_1", reg.into()); + let reg = self.alert_config_2().read()?; + callback(15 + 0 * 0, "alert_config_2", reg.into()); + let reg = self.alert_config_3().read()?; + callback(23 + 0 * 0, "alert_config_3", reg.into()); + let reg = self.alert_config_4().read()?; + callback(31 + 0 * 0, "alert_config_4", reg.into()); + let reg = self.alert_limit_1().read()?; + callback(6 + 0 * 0, "alert_limit_1", reg.into()); + let reg = self.alert_limit_2().read()?; + callback(14 + 0 * 0, "alert_limit_2", reg.into()); + let reg = self.alert_limit_3().read()?; + callback(22 + 0 * 0, "alert_limit_3", reg.into()); + let reg = self.alert_limit_4().read()?; + callback(30 + 0 * 0, "alert_limit_4", reg.into()); + let reg = self.shunt_voltage_ch_1().read()?; + callback(0 + 0 * 0, "shunt_voltage_ch_1", reg.into()); + let reg = self.shunt_voltage_ch_2().read()?; + callback(8 + 0 * 0, "shunt_voltage_ch_2", reg.into()); + let reg = self.shunt_voltage_ch_3().read()?; + callback(16 + 0 * 0, "shunt_voltage_ch_3", reg.into()); + let reg = self.shunt_voltage_ch_4().read()?; + callback(24 + 0 * 0, "shunt_voltage_ch_4", reg.into()); + let reg = self.bus_voltage_ch_1().read()?; + callback(1 + 0 * 0, "bus_voltage_ch_1", reg.into()); + let reg = self.bus_voltage_ch_2().read()?; + callback(9 + 0 * 0, "bus_voltage_ch_2", reg.into()); + let reg = self.bus_voltage_ch_3().read()?; + callback(17 + 0 * 0, "bus_voltage_ch_3", reg.into()); + let reg = self.bus_voltage_ch_4().read()?; + callback(25 + 0 * 0, "bus_voltage_ch_4", reg.into()); + let reg = self.current_ch_1().read()?; + callback(2 + 0 * 0, "current_ch_1", reg.into()); + let reg = self.current_ch_2().read()?; + callback(10 + 0 * 0, "current_ch_2", reg.into()); + let reg = self.current_ch_3().read()?; + callback(18 + 0 * 0, "current_ch_3", reg.into()); + let reg = self.current_ch_4().read()?; + callback(26 + 0 * 0, "current_ch_4", reg.into()); + let reg = self.power_ch_1().read()?; + callback(3 + 0 * 0, "power_ch_1", reg.into()); + let reg = self.power_ch_2().read()?; + callback(11 + 0 * 0, "power_ch_2", reg.into()); + let reg = self.power_ch_3().read()?; + callback(19 + 0 * 0, "power_ch_3", reg.into()); + let reg = self.power_ch_4().read()?; + callback(27 + 0 * 0, "power_ch_4", reg.into()); + let reg = self.energy_ch_1().read()?; + callback(4 + 0 * 0, "energy_ch_1", reg.into()); + let reg = self.energy_ch_2().read()?; + callback(12 + 0 * 0, "energy_ch_2", reg.into()); + let reg = self.energy_ch_3().read()?; + callback(20 + 0 * 0, "energy_ch_3", reg.into()); + let reg = self.energy_ch_4().read()?; + callback(28 + 0 * 0, "energy_ch_4", reg.into()); + let reg = self.flags().read()?; + callback(34 + 0 * 0, "flags", reg.into()); + let reg = self.manufacturer_id().read()?; + callback(126 + 0 * 0, "manufacturer_id", reg.into()); + Ok(()) + } + /// Read all readable register values in this block from the device. + /// The callback is called for each of them. + /// Any registers in child blocks are not included. + /// + /// The callback has three arguments: + /// + /// - The address of the register + /// - The name of the register (with index for repeated registers) + /// - The read value from the register + /// + /// This is useful for e.g. debug printing all values. + /// The given [field_sets::FieldSetValue] has a Debug and Format implementation that forwards to the concrete type + /// the lies within so it can be printed without matching on it. + #[allow(unused_mut)] + #[allow(unused_variables)] + pub async fn read_all_registers_async( + &mut self, + mut callback: impl FnMut(u8, &'static str, field_sets::FieldSetValue), + ) -> Result<(), I::Error> + where + I: ::device_driver::AsyncRegisterInterface, + { + let reg = self.config_1().read_async().await?; + callback(32 + 0 * 0, "config_1", reg.into()); + let reg = self.config_2().read_async().await?; + callback(33 + 0 * 0, "config_2", reg.into()); + let reg = self.calibration_ch_1().read_async().await?; + callback(5 + 0 * 0, "calibration_ch_1", reg.into()); + let reg = self.calibration_ch_2().read_async().await?; + callback(13 + 0 * 0, "calibration_ch_2", reg.into()); + let reg = self.calibration_ch_3().read_async().await?; + callback(21 + 0 * 0, "calibration_ch_3", reg.into()); + let reg = self.calibration_ch_4().read_async().await?; + callback(29 + 0 * 0, "calibration_ch_4", reg.into()); + let reg = self.alert_config_1().read_async().await?; + callback(7 + 0 * 0, "alert_config_1", reg.into()); + let reg = self.alert_config_2().read_async().await?; + callback(15 + 0 * 0, "alert_config_2", reg.into()); + let reg = self.alert_config_3().read_async().await?; + callback(23 + 0 * 0, "alert_config_3", reg.into()); + let reg = self.alert_config_4().read_async().await?; + callback(31 + 0 * 0, "alert_config_4", reg.into()); + let reg = self.alert_limit_1().read_async().await?; + callback(6 + 0 * 0, "alert_limit_1", reg.into()); + let reg = self.alert_limit_2().read_async().await?; + callback(14 + 0 * 0, "alert_limit_2", reg.into()); + let reg = self.alert_limit_3().read_async().await?; + callback(22 + 0 * 0, "alert_limit_3", reg.into()); + let reg = self.alert_limit_4().read_async().await?; + callback(30 + 0 * 0, "alert_limit_4", reg.into()); + let reg = self.shunt_voltage_ch_1().read_async().await?; + callback(0 + 0 * 0, "shunt_voltage_ch_1", reg.into()); + let reg = self.shunt_voltage_ch_2().read_async().await?; + callback(8 + 0 * 0, "shunt_voltage_ch_2", reg.into()); + let reg = self.shunt_voltage_ch_3().read_async().await?; + callback(16 + 0 * 0, "shunt_voltage_ch_3", reg.into()); + let reg = self.shunt_voltage_ch_4().read_async().await?; + callback(24 + 0 * 0, "shunt_voltage_ch_4", reg.into()); + let reg = self.bus_voltage_ch_1().read_async().await?; + callback(1 + 0 * 0, "bus_voltage_ch_1", reg.into()); + let reg = self.bus_voltage_ch_2().read_async().await?; + callback(9 + 0 * 0, "bus_voltage_ch_2", reg.into()); + let reg = self.bus_voltage_ch_3().read_async().await?; + callback(17 + 0 * 0, "bus_voltage_ch_3", reg.into()); + let reg = self.bus_voltage_ch_4().read_async().await?; + callback(25 + 0 * 0, "bus_voltage_ch_4", reg.into()); + let reg = self.current_ch_1().read_async().await?; + callback(2 + 0 * 0, "current_ch_1", reg.into()); + let reg = self.current_ch_2().read_async().await?; + callback(10 + 0 * 0, "current_ch_2", reg.into()); + let reg = self.current_ch_3().read_async().await?; + callback(18 + 0 * 0, "current_ch_3", reg.into()); + let reg = self.current_ch_4().read_async().await?; + callback(26 + 0 * 0, "current_ch_4", reg.into()); + let reg = self.power_ch_1().read_async().await?; + callback(3 + 0 * 0, "power_ch_1", reg.into()); + let reg = self.power_ch_2().read_async().await?; + callback(11 + 0 * 0, "power_ch_2", reg.into()); + let reg = self.power_ch_3().read_async().await?; + callback(19 + 0 * 0, "power_ch_3", reg.into()); + let reg = self.power_ch_4().read_async().await?; + callback(27 + 0 * 0, "power_ch_4", reg.into()); + let reg = self.energy_ch_1().read_async().await?; + callback(4 + 0 * 0, "energy_ch_1", reg.into()); + let reg = self.energy_ch_2().read_async().await?; + callback(12 + 0 * 0, "energy_ch_2", reg.into()); + let reg = self.energy_ch_3().read_async().await?; + callback(20 + 0 * 0, "energy_ch_3", reg.into()); + let reg = self.energy_ch_4().read_async().await?; + callback(28 + 0 * 0, "energy_ch_4", reg.into()); + let reg = self.flags().read_async().await?; + callback(34 + 0 * 0, "flags", reg.into()); + let reg = self.manufacturer_id().read_async().await?; + callback(126 + 0 * 0, "manufacturer_id", reg.into()); + Ok(()) + } + /// Configuration register 1 + pub fn config_1( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::Config1, ::device_driver::RW> + { + let address = self.base_address + 32; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::Config1, + ::device_driver::RW, + >::new(self.interface(), address as u8, field_sets::Config1::new) + } + /// Configuration register 2 + pub fn config_2( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::Config2, ::device_driver::RW> + { + let address = self.base_address + 33; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::Config2, + ::device_driver::RW, + >::new(self.interface(), address as u8, field_sets::Config2::new) + } + /// Calibration register channel 1 + pub fn calibration_ch_1( + &mut self, + ) -> ::device_driver::RegisterOperation< + '_, + I, + u8, + field_sets::CalibrationCh1, + ::device_driver::RW, + > { + let address = self.base_address + 5; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::CalibrationCh1, + ::device_driver::RW, + >::new( + self.interface(), + address as u8, + field_sets::CalibrationCh1::new, + ) + } + /// Calibration register channel 2 + pub fn calibration_ch_2( + &mut self, + ) -> ::device_driver::RegisterOperation< + '_, + I, + u8, + field_sets::CalibrationCh2, + ::device_driver::RW, + > { + let address = self.base_address + 13; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::CalibrationCh2, + ::device_driver::RW, + >::new( + self.interface(), + address as u8, + field_sets::CalibrationCh2::new, + ) + } + /// Calibration register channel 3 + pub fn calibration_ch_3( + &mut self, + ) -> ::device_driver::RegisterOperation< + '_, + I, + u8, + field_sets::CalibrationCh3, + ::device_driver::RW, + > { + let address = self.base_address + 21; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::CalibrationCh3, + ::device_driver::RW, + >::new( + self.interface(), + address as u8, + field_sets::CalibrationCh3::new, + ) + } + /// Calibration register channel 4 + pub fn calibration_ch_4( + &mut self, + ) -> ::device_driver::RegisterOperation< + '_, + I, + u8, + field_sets::CalibrationCh4, + ::device_driver::RW, + > { + let address = self.base_address + 29; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::CalibrationCh4, + ::device_driver::RW, + >::new( + self.interface(), + address as u8, + field_sets::CalibrationCh4::new, + ) + } + /// Alert configuration register 1 + pub fn alert_config_1( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertConfig1, ::device_driver::RW> + { + let address = self.base_address + 7; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::AlertConfig1, + ::device_driver::RW, + >::new(self.interface(), address as u8, field_sets::AlertConfig1::new) + } + /// Alert configuration register 2 + pub fn alert_config_2( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertConfig2, ::device_driver::RW> + { + let address = self.base_address + 15; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::AlertConfig2, + ::device_driver::RW, + >::new(self.interface(), address as u8, field_sets::AlertConfig2::new) + } + /// Alert configuration register 3 + pub fn alert_config_3( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertConfig3, ::device_driver::RW> + { + let address = self.base_address + 23; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::AlertConfig3, + ::device_driver::RW, + >::new(self.interface(), address as u8, field_sets::AlertConfig3::new) + } + /// Alert configuration register 4 + pub fn alert_config_4( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertConfig4, ::device_driver::RW> + { + let address = self.base_address + 31; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::AlertConfig4, + ::device_driver::RW, + >::new(self.interface(), address as u8, field_sets::AlertConfig4::new) + } + /// Alert limit register 1. Format matches corresponding result register. + pub fn alert_limit_1( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertLimit1, ::device_driver::RW> + { + let address = self.base_address + 6; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::AlertLimit1, + ::device_driver::RW, + >::new(self.interface(), address as u8, field_sets::AlertLimit1::new) + } + /// Alert limit register 2 + pub fn alert_limit_2( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertLimit2, ::device_driver::RW> + { + let address = self.base_address + 14; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::AlertLimit2, + ::device_driver::RW, + >::new(self.interface(), address as u8, field_sets::AlertLimit2::new) + } + /// Alert limit register 3 + pub fn alert_limit_3( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertLimit3, ::device_driver::RW> + { + let address = self.base_address + 22; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::AlertLimit3, + ::device_driver::RW, + >::new(self.interface(), address as u8, field_sets::AlertLimit3::new) + } + /// Alert limit register 4 + pub fn alert_limit_4( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertLimit4, ::device_driver::RW> + { + let address = self.base_address + 30; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::AlertLimit4, + ::device_driver::RW, + >::new(self.interface(), address as u8, field_sets::AlertLimit4::new) + } + /// Shunt voltage channel 1. 2's complement. LSB = 2.5uV (range=0) or 625nV (range=1) + pub fn shunt_voltage_ch_1( + &mut self, + ) -> ::device_driver::RegisterOperation< + '_, + I, + u8, + field_sets::ShuntVoltageCh1, + ::device_driver::RO, + > { + let address = self.base_address + 0; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::ShuntVoltageCh1, + ::device_driver::RO, + >::new( + self.interface(), + address as u8, + field_sets::ShuntVoltageCh1::new, + ) + } + /// Shunt voltage channel 2 + pub fn shunt_voltage_ch_2( + &mut self, + ) -> ::device_driver::RegisterOperation< + '_, + I, + u8, + field_sets::ShuntVoltageCh2, + ::device_driver::RO, + > { + let address = self.base_address + 8; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::ShuntVoltageCh2, + ::device_driver::RO, + >::new( + self.interface(), + address as u8, + field_sets::ShuntVoltageCh2::new, + ) + } + /// Shunt voltage channel 3 + pub fn shunt_voltage_ch_3( + &mut self, + ) -> ::device_driver::RegisterOperation< + '_, + I, + u8, + field_sets::ShuntVoltageCh3, + ::device_driver::RO, + > { + let address = self.base_address + 16; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::ShuntVoltageCh3, + ::device_driver::RO, + >::new( + self.interface(), + address as u8, + field_sets::ShuntVoltageCh3::new, + ) + } + /// Shunt voltage channel 4 + pub fn shunt_voltage_ch_4( + &mut self, + ) -> ::device_driver::RegisterOperation< + '_, + I, + u8, + field_sets::ShuntVoltageCh4, + ::device_driver::RO, + > { + let address = self.base_address + 24; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::ShuntVoltageCh4, + ::device_driver::RO, + >::new( + self.interface(), + address as u8, + field_sets::ShuntVoltageCh4::new, + ) + } + /// Bus voltage channel 1. Always positive. LSB = 1.6mV + pub fn bus_voltage_ch_1( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::BusVoltageCh1, ::device_driver::RO> + { + let address = self.base_address + 1; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::BusVoltageCh1, + ::device_driver::RO, + >::new( + self.interface(), + address as u8, + field_sets::BusVoltageCh1::new, + ) + } + /// Bus voltage channel 2 + pub fn bus_voltage_ch_2( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::BusVoltageCh2, ::device_driver::RO> + { + let address = self.base_address + 9; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::BusVoltageCh2, + ::device_driver::RO, + >::new( + self.interface(), + address as u8, + field_sets::BusVoltageCh2::new, + ) + } + /// Bus voltage channel 3 + pub fn bus_voltage_ch_3( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::BusVoltageCh3, ::device_driver::RO> + { + let address = self.base_address + 17; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::BusVoltageCh3, + ::device_driver::RO, + >::new( + self.interface(), + address as u8, + field_sets::BusVoltageCh3::new, + ) + } + /// Bus voltage channel 4 + pub fn bus_voltage_ch_4( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::BusVoltageCh4, ::device_driver::RO> + { + let address = self.base_address + 25; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::BusVoltageCh4, + ::device_driver::RO, + >::new( + self.interface(), + address as u8, + field_sets::BusVoltageCh4::new, + ) + } + /// Current channel 1. Value [A] = CURRENT_LSB x register_value + pub fn current_ch_1( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::CurrentCh1, ::device_driver::RO> + { + let address = self.base_address + 2; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::CurrentCh1, + ::device_driver::RO, + >::new(self.interface(), address as u8, field_sets::CurrentCh1::new) + } + /// Current channel 2 + pub fn current_ch_2( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::CurrentCh2, ::device_driver::RO> + { + let address = self.base_address + 10; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::CurrentCh2, + ::device_driver::RO, + >::new(self.interface(), address as u8, field_sets::CurrentCh2::new) + } + /// Current channel 3 + pub fn current_ch_3( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::CurrentCh3, ::device_driver::RO> + { + let address = self.base_address + 18; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::CurrentCh3, + ::device_driver::RO, + >::new(self.interface(), address as u8, field_sets::CurrentCh3::new) + } + /// Current channel 4 + pub fn current_ch_4( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::CurrentCh4, ::device_driver::RO> + { + let address = self.base_address + 26; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::CurrentCh4, + ::device_driver::RO, + >::new(self.interface(), address as u8, field_sets::CurrentCh4::new) + } + /// Power channel 1. Value [W] = 32 x CURRENT_LSB x register_value. Unsigned. + pub fn power_ch_1( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::PowerCh1, ::device_driver::RO> + { + let address = self.base_address + 3; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::PowerCh1, + ::device_driver::RO, + >::new(self.interface(), address as u8, field_sets::PowerCh1::new) + } + /// Power channel 2 + pub fn power_ch_2( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::PowerCh2, ::device_driver::RO> + { + let address = self.base_address + 11; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::PowerCh2, + ::device_driver::RO, + >::new(self.interface(), address as u8, field_sets::PowerCh2::new) + } + /// Power channel 3 + pub fn power_ch_3( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::PowerCh3, ::device_driver::RO> + { + let address = self.base_address + 19; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::PowerCh3, + ::device_driver::RO, + >::new(self.interface(), address as u8, field_sets::PowerCh3::new) + } + /// Power channel 4 + pub fn power_ch_4( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::PowerCh4, ::device_driver::RO> + { + let address = self.base_address + 27; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::PowerCh4, + ::device_driver::RO, + >::new(self.interface(), address as u8, field_sets::PowerCh4::new) + } + /// Energy channel 1. Value [J] = 32 x CURRENT_LSB x register_value. Unsigned. + pub fn energy_ch_1( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::EnergyCh1, ::device_driver::RO> + { + let address = self.base_address + 4; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::EnergyCh1, + ::device_driver::RO, + >::new(self.interface(), address as u8, field_sets::EnergyCh1::new) + } + /// Energy channel 2 + pub fn energy_ch_2( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::EnergyCh2, ::device_driver::RO> + { + let address = self.base_address + 12; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::EnergyCh2, + ::device_driver::RO, + >::new(self.interface(), address as u8, field_sets::EnergyCh2::new) + } + /// Energy channel 3 + pub fn energy_ch_3( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::EnergyCh3, ::device_driver::RO> + { + let address = self.base_address + 20; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::EnergyCh3, + ::device_driver::RO, + >::new(self.interface(), address as u8, field_sets::EnergyCh3::new) + } + /// Energy channel 4 + pub fn energy_ch_4( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::EnergyCh4, ::device_driver::RO> + { + let address = self.base_address + 28; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::EnergyCh4, + ::device_driver::RO, + >::new(self.interface(), address as u8, field_sets::EnergyCh4::new) + } + /// Flags register + pub fn flags( + &mut self, + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::Flags, ::device_driver::RO> { + let address = self.base_address + 34; + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::Flags, ::device_driver::RO>::new( + self.interface(), + address as u8, + field_sets::Flags::new, + ) + } + /// Manufacturer ID. Reads back 0x5449 ('TI' in ASCII) + pub fn manufacturer_id( + &mut self, + ) -> ::device_driver::RegisterOperation< + '_, + I, + u8, + field_sets::ManufacturerId, + ::device_driver::RO, + > { + let address = self.base_address + 126; + ::device_driver::RegisterOperation::< + '_, + I, + u8, + field_sets::ManufacturerId, + ::device_driver::RO, + >::new( + self.interface(), + address as u8, + field_sets::ManufacturerId::new, + ) + } +} +/// Module containing the generated fieldsets of the registers and commands +pub mod field_sets { + #[allow(unused_imports)] + use super::*; + /// Configuration register 1 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Config1 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for Config1 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl Config1 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [241, 39] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `active_channel` field of the register. + /// + /// Active channel enable bits. Bit15=CH4, Bit14=CH3, Bit13=CH2, Bit12=CH1 + pub fn active_channel(&self) -> u8 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 12, 16) + }; + raw + } + ///Read the `avg` field of the register. + /// + /// Number of ADC conversion results to average + pub fn avg(&self) -> super::Averaging { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 9, 12) + }; + unsafe { raw.try_into().unwrap_unchecked() } + } + ///Read the `vbusct` field of the register. + /// + /// Bus voltage conversion time + pub fn vbusct(&self) -> super::BusConversionTime { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 6, 9) + }; + unsafe { raw.try_into().unwrap_unchecked() } + } + ///Read the `vshct` field of the register. + /// + /// Shunt voltage conversion time + pub fn vshct(&self) -> super::ShuntConversionTime { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 3, 6) + }; + unsafe { raw.try_into().unwrap_unchecked() } + } + ///Read the `mode` field of the register. + /// + /// Operating mode + pub fn mode(&self) -> super::Mode { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 3) + }; + unsafe { raw.try_into().unwrap_unchecked() } + } + ///Write the `active_channel` field of the register. + /// + /// Active channel enable bits. Bit15=CH4, Bit14=CH3, Bit13=CH2, Bit12=CH1 + pub fn set_active_channel(&mut self, value: u8) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 12, + 16, + &mut self.bits, + ) + }; + } + ///Write the `avg` field of the register. + /// + /// Number of ADC conversion results to average + pub fn set_avg(&mut self, value: super::Averaging) { + let raw = value.into(); + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 9, + 12, + &mut self.bits, + ) + }; + } + ///Write the `vbusct` field of the register. + /// + /// Bus voltage conversion time + pub fn set_vbusct(&mut self, value: super::BusConversionTime) { + let raw = value.into(); + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 6, + 9, + &mut self.bits, + ) + }; + } + ///Write the `vshct` field of the register. + /// + /// Shunt voltage conversion time + pub fn set_vshct(&mut self, value: super::ShuntConversionTime) { + let raw = value.into(); + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 3, + 6, + &mut self.bits, + ) + }; + } + ///Write the `mode` field of the register. + /// + /// Operating mode + pub fn set_mode(&mut self, value: super::Mode) { + let raw = value.into(); + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 3, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for Config1 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: Config1) -> Self { + val.bits + } + } + impl core::fmt::Debug for Config1 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("Config1"); + d.field("active_channel", &self.active_channel()); + d.field("avg", &self.avg()); + d.field("vbusct", &self.vbusct()); + d.field("vshct", &self.vshct()); + d.field("mode", &self.mode()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for Config1 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "Config1 {{ "); + defmt::write!(f, "active_channel: {=u8}, ", &self.active_channel()); + defmt::write!(f, "avg: {}, ", &self.avg()); + defmt::write!(f, "vbusct: {}, ", &self.vbusct()); + defmt::write!(f, "vshct: {}, ", &self.vshct()); + defmt::write!(f, "mode: {}, ", &self.mode()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for Config1 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for Config1 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for Config1 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for Config1 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for Config1 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for Config1 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for Config1 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Configuration register 2 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Config2 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for Config2 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl Config2 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `rst` field of the register. + /// + /// System reset. Set to 1 to reset all registers to default. Self-clears. + pub fn rst(&self) -> bool { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 15, 16) + }; + raw > 0 + } + ///Read the `acc_rst` field of the register. + /// + /// Energy accumulator reset per channel. Bit11=CH4, Bit10=CH3, Bit9=CH2, Bit8=CH1. Bits self-clear after write. + pub fn acc_rst(&self) -> u8 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 8, 12) + }; + raw + } + ///Read the `cnvr_mask` field of the register. + /// + /// Conversion ready flag on ALERT pin enable + pub fn cnvr_mask(&self) -> bool { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 7, 8) + }; + raw > 0 + } + ///Read the `enof_mask` field of the register. + /// + /// Energy overflow alert enable + pub fn enof_mask(&self) -> bool { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 6, 7) + }; + raw > 0 + } + ///Read the `alert_latch` field of the register. + /// + /// Alert pin latch enable. When set, alert latches until flags register is read. + pub fn alert_latch(&self) -> bool { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 5, 6) + }; + raw > 0 + } + ///Read the `alert_pol` field of the register. + /// + /// Alert pin polarity + pub fn alert_pol(&self) -> super::AlertPolarity { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 4, 5) + }; + unsafe { raw.try_into().unwrap_unchecked() } + } + ///Read the `range` field of the register. + /// + /// Shunt full scale input range per channel. Bit3=CH4, Bit2=CH3, Bit1=CH2, Bit0=CH1. 0=±81.92mV, 1=±20.48mV + pub fn range(&self) -> u8 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 4) + }; + raw + } + ///Write the `rst` field of the register. + /// + /// System reset. Set to 1 to reset all registers to default. Self-clears. + pub fn set_rst(&mut self, value: bool) { + let raw = value as _; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 15, + 16, + &mut self.bits, + ) + }; + } + ///Write the `acc_rst` field of the register. + /// + /// Energy accumulator reset per channel. Bit11=CH4, Bit10=CH3, Bit9=CH2, Bit8=CH1. Bits self-clear after write. + pub fn set_acc_rst(&mut self, value: u8) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 8, + 12, + &mut self.bits, + ) + }; + } + ///Write the `cnvr_mask` field of the register. + /// + /// Conversion ready flag on ALERT pin enable + pub fn set_cnvr_mask(&mut self, value: bool) { + let raw = value as _; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 7, + 8, + &mut self.bits, + ) + }; + } + ///Write the `enof_mask` field of the register. + /// + /// Energy overflow alert enable + pub fn set_enof_mask(&mut self, value: bool) { + let raw = value as _; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 6, + 7, + &mut self.bits, + ) + }; + } + ///Write the `alert_latch` field of the register. + /// + /// Alert pin latch enable. When set, alert latches until flags register is read. + pub fn set_alert_latch(&mut self, value: bool) { + let raw = value as _; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 5, + 6, + &mut self.bits, + ) + }; + } + ///Write the `alert_pol` field of the register. + /// + /// Alert pin polarity + pub fn set_alert_pol(&mut self, value: super::AlertPolarity) { + let raw = value.into(); + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 4, + 5, + &mut self.bits, + ) + }; + } + ///Write the `range` field of the register. + /// + /// Shunt full scale input range per channel. Bit3=CH4, Bit2=CH3, Bit1=CH2, Bit0=CH1. 0=±81.92mV, 1=±20.48mV + pub fn set_range(&mut self, value: u8) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 4, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for Config2 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: Config2) -> Self { + val.bits + } + } + impl core::fmt::Debug for Config2 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("Config2"); + d.field("rst", &self.rst()); + d.field("acc_rst", &self.acc_rst()); + d.field("cnvr_mask", &self.cnvr_mask()); + d.field("enof_mask", &self.enof_mask()); + d.field("alert_latch", &self.alert_latch()); + d.field("alert_pol", &self.alert_pol()); + d.field("range", &self.range()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for Config2 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "Config2 {{ "); + defmt::write!(f, "rst: {=bool}, ", &self.rst()); + defmt::write!(f, "acc_rst: {=u8}, ", &self.acc_rst()); + defmt::write!(f, "cnvr_mask: {=bool}, ", &self.cnvr_mask()); + defmt::write!(f, "enof_mask: {=bool}, ", &self.enof_mask()); + defmt::write!(f, "alert_latch: {=bool}, ", &self.alert_latch()); + defmt::write!(f, "alert_pol: {}, ", &self.alert_pol()); + defmt::write!(f, "range: {=u8}, ", &self.range()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for Config2 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for Config2 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for Config2 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for Config2 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for Config2 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for Config2 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for Config2 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Calibration register channel 1 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct CalibrationCh1 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for CalibrationCh1 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl CalibrationCh1 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `shunt_cal` field of the register. + /// + /// Shunt calibration value for current conversion + pub fn shunt_cal(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 15) + }; + raw + } + ///Write the `shunt_cal` field of the register. + /// + /// Shunt calibration value for current conversion + pub fn set_shunt_cal(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 15, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for CalibrationCh1 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: CalibrationCh1) -> Self { + val.bits + } + } + impl core::fmt::Debug for CalibrationCh1 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("CalibrationCh1"); + d.field("shunt_cal", &self.shunt_cal()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for CalibrationCh1 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "CalibrationCh1 {{ "); + defmt::write!(f, "shunt_cal: {=u16}, ", &self.shunt_cal()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for CalibrationCh1 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for CalibrationCh1 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for CalibrationCh1 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for CalibrationCh1 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for CalibrationCh1 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for CalibrationCh1 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for CalibrationCh1 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Calibration register channel 2 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct CalibrationCh2 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for CalibrationCh2 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl CalibrationCh2 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `shunt_cal` field of the register. + /// + /// Shunt calibration value for current conversion + pub fn shunt_cal(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 15) + }; + raw + } + ///Write the `shunt_cal` field of the register. + /// + /// Shunt calibration value for current conversion + pub fn set_shunt_cal(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 15, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for CalibrationCh2 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: CalibrationCh2) -> Self { + val.bits + } + } + impl core::fmt::Debug for CalibrationCh2 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("CalibrationCh2"); + d.field("shunt_cal", &self.shunt_cal()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for CalibrationCh2 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "CalibrationCh2 {{ "); + defmt::write!(f, "shunt_cal: {=u16}, ", &self.shunt_cal()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for CalibrationCh2 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for CalibrationCh2 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for CalibrationCh2 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for CalibrationCh2 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for CalibrationCh2 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for CalibrationCh2 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for CalibrationCh2 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Calibration register channel 3 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct CalibrationCh3 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for CalibrationCh3 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl CalibrationCh3 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `shunt_cal` field of the register. + /// + /// Shunt calibration value for current conversion + pub fn shunt_cal(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 15) + }; + raw + } + ///Write the `shunt_cal` field of the register. + /// + /// Shunt calibration value for current conversion + pub fn set_shunt_cal(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 15, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for CalibrationCh3 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: CalibrationCh3) -> Self { + val.bits + } + } + impl core::fmt::Debug for CalibrationCh3 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("CalibrationCh3"); + d.field("shunt_cal", &self.shunt_cal()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for CalibrationCh3 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "CalibrationCh3 {{ "); + defmt::write!(f, "shunt_cal: {=u16}, ", &self.shunt_cal()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for CalibrationCh3 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for CalibrationCh3 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for CalibrationCh3 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for CalibrationCh3 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for CalibrationCh3 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for CalibrationCh3 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for CalibrationCh3 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Calibration register channel 4 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct CalibrationCh4 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for CalibrationCh4 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl CalibrationCh4 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `shunt_cal` field of the register. + /// + /// Shunt calibration value for current conversion + pub fn shunt_cal(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 15) + }; + raw + } + ///Write the `shunt_cal` field of the register. + /// + /// Shunt calibration value for current conversion + pub fn set_shunt_cal(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 15, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for CalibrationCh4 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: CalibrationCh4) -> Self { + val.bits + } + } + impl core::fmt::Debug for CalibrationCh4 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("CalibrationCh4"); + d.field("shunt_cal", &self.shunt_cal()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for CalibrationCh4 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "CalibrationCh4 {{ "); + defmt::write!(f, "shunt_cal: {=u16}, ", &self.shunt_cal()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for CalibrationCh4 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for CalibrationCh4 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for CalibrationCh4 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for CalibrationCh4 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for CalibrationCh4 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for CalibrationCh4 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for CalibrationCh4 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Alert configuration register 1 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct AlertConfig1 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for AlertConfig1 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl AlertConfig1 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `channel` field of the register. + /// + /// Channel assignment for this alert + pub fn channel(&self) -> super::AlertChannel { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 3, 5) + }; + unsafe { raw.try_into().unwrap_unchecked() } + } + ///Read the `alert_mask` field of the register. + /// + /// Active alert function selection + pub fn alert_mask(&self) -> super::AlertFunction { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 3) + }; + unsafe { raw.try_into().unwrap_unchecked() } + } + ///Write the `channel` field of the register. + /// + /// Channel assignment for this alert + pub fn set_channel(&mut self, value: super::AlertChannel) { + let raw = value.into(); + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 3, + 5, + &mut self.bits, + ) + }; + } + ///Write the `alert_mask` field of the register. + /// + /// Active alert function selection + pub fn set_alert_mask(&mut self, value: super::AlertFunction) { + let raw = value.into(); + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 3, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for AlertConfig1 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: AlertConfig1) -> Self { + val.bits + } + } + impl core::fmt::Debug for AlertConfig1 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("AlertConfig1"); + d.field("channel", &self.channel()); + d.field("alert_mask", &self.alert_mask()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for AlertConfig1 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "AlertConfig1 {{ "); + defmt::write!(f, "channel: {}, ", &self.channel()); + defmt::write!(f, "alert_mask: {}, ", &self.alert_mask()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for AlertConfig1 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for AlertConfig1 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for AlertConfig1 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for AlertConfig1 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for AlertConfig1 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for AlertConfig1 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for AlertConfig1 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Alert configuration register 2 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct AlertConfig2 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for AlertConfig2 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl AlertConfig2 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `channel` field of the register. + /// + /// Channel assignment for this alert + pub fn channel(&self) -> u8 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 3, 5) + }; + raw + } + ///Read the `alert_mask` field of the register. + /// + /// Active alert function selection + pub fn alert_mask(&self) -> u8 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 3) + }; + raw + } + ///Write the `channel` field of the register. + /// + /// Channel assignment for this alert + pub fn set_channel(&mut self, value: u8) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 3, + 5, + &mut self.bits, + ) + }; + } + ///Write the `alert_mask` field of the register. + /// + /// Active alert function selection + pub fn set_alert_mask(&mut self, value: u8) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 3, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for AlertConfig2 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: AlertConfig2) -> Self { + val.bits + } + } + impl core::fmt::Debug for AlertConfig2 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("AlertConfig2"); + d.field("channel", &self.channel()); + d.field("alert_mask", &self.alert_mask()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for AlertConfig2 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "AlertConfig2 {{ "); + defmt::write!(f, "channel: {=u8}, ", &self.channel()); + defmt::write!(f, "alert_mask: {=u8}, ", &self.alert_mask()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for AlertConfig2 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for AlertConfig2 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for AlertConfig2 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for AlertConfig2 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for AlertConfig2 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for AlertConfig2 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for AlertConfig2 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Alert configuration register 3 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct AlertConfig3 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for AlertConfig3 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl AlertConfig3 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `channel` field of the register. + /// + /// Channel assignment for this alert + pub fn channel(&self) -> u8 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 3, 5) + }; + raw + } + ///Read the `alert_mask` field of the register. + /// + /// Active alert function selection + pub fn alert_mask(&self) -> u8 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 3) + }; + raw + } + ///Write the `channel` field of the register. + /// + /// Channel assignment for this alert + pub fn set_channel(&mut self, value: u8) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 3, + 5, + &mut self.bits, + ) + }; + } + ///Write the `alert_mask` field of the register. + /// + /// Active alert function selection + pub fn set_alert_mask(&mut self, value: u8) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 3, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for AlertConfig3 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: AlertConfig3) -> Self { + val.bits + } + } + impl core::fmt::Debug for AlertConfig3 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("AlertConfig3"); + d.field("channel", &self.channel()); + d.field("alert_mask", &self.alert_mask()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for AlertConfig3 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "AlertConfig3 {{ "); + defmt::write!(f, "channel: {=u8}, ", &self.channel()); + defmt::write!(f, "alert_mask: {=u8}, ", &self.alert_mask()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for AlertConfig3 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for AlertConfig3 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for AlertConfig3 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for AlertConfig3 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for AlertConfig3 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for AlertConfig3 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for AlertConfig3 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Alert configuration register 4 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct AlertConfig4 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for AlertConfig4 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl AlertConfig4 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `channel` field of the register. + /// + /// Channel assignment for this alert + pub fn channel(&self) -> u8 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 3, 5) + }; + raw + } + ///Read the `alert_mask` field of the register. + /// + /// Active alert function selection + pub fn alert_mask(&self) -> u8 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 3) + }; + raw + } + ///Write the `channel` field of the register. + /// + /// Channel assignment for this alert + pub fn set_channel(&mut self, value: u8) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 3, + 5, + &mut self.bits, + ) + }; + } + ///Write the `alert_mask` field of the register. + /// + /// Active alert function selection + pub fn set_alert_mask(&mut self, value: u8) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 3, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for AlertConfig4 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: AlertConfig4) -> Self { + val.bits + } + } + impl core::fmt::Debug for AlertConfig4 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("AlertConfig4"); + d.field("channel", &self.channel()); + d.field("alert_mask", &self.alert_mask()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for AlertConfig4 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "AlertConfig4 {{ "); + defmt::write!(f, "channel: {=u8}, ", &self.channel()); + defmt::write!(f, "alert_mask: {=u8}, ", &self.alert_mask()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for AlertConfig4 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for AlertConfig4 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for AlertConfig4 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for AlertConfig4 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for AlertConfig4 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for AlertConfig4 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for AlertConfig4 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Alert limit register 1. Format matches corresponding result register. + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct AlertLimit1 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for AlertLimit1 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl AlertLimit1 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `limit` field of the register. + /// + /// Alert threshold. Shunt=signed 16-bit, Bus=unsigned 15-bit, Power=unsigned 16-bit + pub fn limit(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `limit` field of the register. + /// + /// Alert threshold. Shunt=signed 16-bit, Bus=unsigned 15-bit, Power=unsigned 16-bit + pub fn set_limit(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for AlertLimit1 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: AlertLimit1) -> Self { + val.bits + } + } + impl core::fmt::Debug for AlertLimit1 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("AlertLimit1"); + d.field("limit", &self.limit()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for AlertLimit1 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "AlertLimit1 {{ "); + defmt::write!(f, "limit: {=u16}, ", &self.limit()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for AlertLimit1 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for AlertLimit1 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for AlertLimit1 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for AlertLimit1 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for AlertLimit1 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for AlertLimit1 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for AlertLimit1 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Alert limit register 2 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct AlertLimit2 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for AlertLimit2 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl AlertLimit2 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `limit` field of the register. + /// + /// Alert threshold + pub fn limit(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `limit` field of the register. + /// + /// Alert threshold + pub fn set_limit(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for AlertLimit2 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: AlertLimit2) -> Self { + val.bits + } + } + impl core::fmt::Debug for AlertLimit2 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("AlertLimit2"); + d.field("limit", &self.limit()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for AlertLimit2 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "AlertLimit2 {{ "); + defmt::write!(f, "limit: {=u16}, ", &self.limit()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for AlertLimit2 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for AlertLimit2 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for AlertLimit2 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for AlertLimit2 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for AlertLimit2 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for AlertLimit2 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for AlertLimit2 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Alert limit register 3 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct AlertLimit3 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for AlertLimit3 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl AlertLimit3 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `limit` field of the register. + /// + /// Alert threshold + pub fn limit(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `limit` field of the register. + /// + /// Alert threshold + pub fn set_limit(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for AlertLimit3 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: AlertLimit3) -> Self { + val.bits + } + } + impl core::fmt::Debug for AlertLimit3 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("AlertLimit3"); + d.field("limit", &self.limit()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for AlertLimit3 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "AlertLimit3 {{ "); + defmt::write!(f, "limit: {=u16}, ", &self.limit()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for AlertLimit3 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for AlertLimit3 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for AlertLimit3 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for AlertLimit3 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for AlertLimit3 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for AlertLimit3 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for AlertLimit3 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Alert limit register 4 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct AlertLimit4 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for AlertLimit4 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl AlertLimit4 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `limit` field of the register. + /// + /// Alert threshold + pub fn limit(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `limit` field of the register. + /// + /// Alert threshold + pub fn set_limit(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for AlertLimit4 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: AlertLimit4) -> Self { + val.bits + } + } + impl core::fmt::Debug for AlertLimit4 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("AlertLimit4"); + d.field("limit", &self.limit()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for AlertLimit4 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "AlertLimit4 {{ "); + defmt::write!(f, "limit: {=u16}, ", &self.limit()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for AlertLimit4 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for AlertLimit4 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for AlertLimit4 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for AlertLimit4 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for AlertLimit4 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for AlertLimit4 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for AlertLimit4 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Shunt voltage channel 1. 2's complement. LSB = 2.5uV (range=0) or 625nV (range=1) + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct ShuntVoltageCh1 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for ShuntVoltageCh1 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl ShuntVoltageCh1 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `vshunt` field of the register. + /// + /// Differential shunt voltage, 2's complement + pub fn vshunt(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `vshunt` field of the register. + /// + /// Differential shunt voltage, 2's complement + pub fn set_vshunt(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for ShuntVoltageCh1 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: ShuntVoltageCh1) -> Self { + val.bits + } + } + impl core::fmt::Debug for ShuntVoltageCh1 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("ShuntVoltageCh1"); + d.field("vshunt", &self.vshunt()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for ShuntVoltageCh1 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "ShuntVoltageCh1 {{ "); + defmt::write!(f, "vshunt: {=u16}, ", &self.vshunt()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for ShuntVoltageCh1 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for ShuntVoltageCh1 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for ShuntVoltageCh1 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for ShuntVoltageCh1 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for ShuntVoltageCh1 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for ShuntVoltageCh1 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for ShuntVoltageCh1 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Shunt voltage channel 2 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct ShuntVoltageCh2 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for ShuntVoltageCh2 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl ShuntVoltageCh2 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `vshunt` field of the register. + /// + /// Differential shunt voltage, 2's complement + pub fn vshunt(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `vshunt` field of the register. + /// + /// Differential shunt voltage, 2's complement + pub fn set_vshunt(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for ShuntVoltageCh2 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: ShuntVoltageCh2) -> Self { + val.bits + } + } + impl core::fmt::Debug for ShuntVoltageCh2 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("ShuntVoltageCh2"); + d.field("vshunt", &self.vshunt()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for ShuntVoltageCh2 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "ShuntVoltageCh2 {{ "); + defmt::write!(f, "vshunt: {=u16}, ", &self.vshunt()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for ShuntVoltageCh2 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for ShuntVoltageCh2 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for ShuntVoltageCh2 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for ShuntVoltageCh2 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for ShuntVoltageCh2 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for ShuntVoltageCh2 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for ShuntVoltageCh2 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Shunt voltage channel 3 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct ShuntVoltageCh3 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for ShuntVoltageCh3 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl ShuntVoltageCh3 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `vshunt` field of the register. + /// + /// Differential shunt voltage, 2's complement + pub fn vshunt(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `vshunt` field of the register. + /// + /// Differential shunt voltage, 2's complement + pub fn set_vshunt(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for ShuntVoltageCh3 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: ShuntVoltageCh3) -> Self { + val.bits + } + } + impl core::fmt::Debug for ShuntVoltageCh3 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("ShuntVoltageCh3"); + d.field("vshunt", &self.vshunt()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for ShuntVoltageCh3 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "ShuntVoltageCh3 {{ "); + defmt::write!(f, "vshunt: {=u16}, ", &self.vshunt()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for ShuntVoltageCh3 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for ShuntVoltageCh3 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for ShuntVoltageCh3 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for ShuntVoltageCh3 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for ShuntVoltageCh3 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for ShuntVoltageCh3 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for ShuntVoltageCh3 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Shunt voltage channel 4 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct ShuntVoltageCh4 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for ShuntVoltageCh4 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl ShuntVoltageCh4 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `vshunt` field of the register. + /// + /// Differential shunt voltage, 2's complement + pub fn vshunt(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `vshunt` field of the register. + /// + /// Differential shunt voltage, 2's complement + pub fn set_vshunt(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for ShuntVoltageCh4 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: ShuntVoltageCh4) -> Self { + val.bits + } + } + impl core::fmt::Debug for ShuntVoltageCh4 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("ShuntVoltageCh4"); + d.field("vshunt", &self.vshunt()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for ShuntVoltageCh4 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "ShuntVoltageCh4 {{ "); + defmt::write!(f, "vshunt: {=u16}, ", &self.vshunt()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for ShuntVoltageCh4 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for ShuntVoltageCh4 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for ShuntVoltageCh4 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for ShuntVoltageCh4 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for ShuntVoltageCh4 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for ShuntVoltageCh4 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for ShuntVoltageCh4 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Bus voltage channel 1. Always positive. LSB = 1.6mV + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct BusVoltageCh1 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for BusVoltageCh1 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl BusVoltageCh1 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `vbus` field of the register. + /// + /// Bus voltage, always positive, 2's complement format + pub fn vbus(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `vbus` field of the register. + /// + /// Bus voltage, always positive, 2's complement format + pub fn set_vbus(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for BusVoltageCh1 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: BusVoltageCh1) -> Self { + val.bits + } + } + impl core::fmt::Debug for BusVoltageCh1 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("BusVoltageCh1"); + d.field("vbus", &self.vbus()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for BusVoltageCh1 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "BusVoltageCh1 {{ "); + defmt::write!(f, "vbus: {=u16}, ", &self.vbus()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for BusVoltageCh1 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for BusVoltageCh1 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for BusVoltageCh1 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for BusVoltageCh1 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for BusVoltageCh1 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for BusVoltageCh1 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for BusVoltageCh1 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Bus voltage channel 2 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct BusVoltageCh2 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for BusVoltageCh2 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl BusVoltageCh2 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `vbus` field of the register. + /// + /// Bus voltage + pub fn vbus(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `vbus` field of the register. + /// + /// Bus voltage + pub fn set_vbus(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for BusVoltageCh2 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: BusVoltageCh2) -> Self { + val.bits + } + } + impl core::fmt::Debug for BusVoltageCh2 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("BusVoltageCh2"); + d.field("vbus", &self.vbus()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for BusVoltageCh2 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "BusVoltageCh2 {{ "); + defmt::write!(f, "vbus: {=u16}, ", &self.vbus()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for BusVoltageCh2 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for BusVoltageCh2 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for BusVoltageCh2 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for BusVoltageCh2 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for BusVoltageCh2 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for BusVoltageCh2 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for BusVoltageCh2 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Bus voltage channel 3 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct BusVoltageCh3 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for BusVoltageCh3 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl BusVoltageCh3 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `vbus` field of the register. + /// + /// Bus voltage + pub fn vbus(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `vbus` field of the register. + /// + /// Bus voltage + pub fn set_vbus(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for BusVoltageCh3 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: BusVoltageCh3) -> Self { + val.bits + } + } + impl core::fmt::Debug for BusVoltageCh3 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("BusVoltageCh3"); + d.field("vbus", &self.vbus()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for BusVoltageCh3 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "BusVoltageCh3 {{ "); + defmt::write!(f, "vbus: {=u16}, ", &self.vbus()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for BusVoltageCh3 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for BusVoltageCh3 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for BusVoltageCh3 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for BusVoltageCh3 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for BusVoltageCh3 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for BusVoltageCh3 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for BusVoltageCh3 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Bus voltage channel 4 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct BusVoltageCh4 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for BusVoltageCh4 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl BusVoltageCh4 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `vbus` field of the register. + /// + /// Bus voltage + pub fn vbus(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `vbus` field of the register. + /// + /// Bus voltage + pub fn set_vbus(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for BusVoltageCh4 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: BusVoltageCh4) -> Self { + val.bits + } + } + impl core::fmt::Debug for BusVoltageCh4 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("BusVoltageCh4"); + d.field("vbus", &self.vbus()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for BusVoltageCh4 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "BusVoltageCh4 {{ "); + defmt::write!(f, "vbus: {=u16}, ", &self.vbus()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for BusVoltageCh4 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for BusVoltageCh4 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for BusVoltageCh4 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for BusVoltageCh4 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for BusVoltageCh4 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for BusVoltageCh4 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for BusVoltageCh4 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Current channel 1. Value [A] = CURRENT_LSB x register_value + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct CurrentCh1 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for CurrentCh1 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl CurrentCh1 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `current` field of the register. + /// + /// Calculated current in amperes, 2's complement + pub fn current(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `current` field of the register. + /// + /// Calculated current in amperes, 2's complement + pub fn set_current(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for CurrentCh1 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: CurrentCh1) -> Self { + val.bits + } + } + impl core::fmt::Debug for CurrentCh1 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("CurrentCh1"); + d.field("current", &self.current()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for CurrentCh1 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "CurrentCh1 {{ "); + defmt::write!(f, "current: {=u16}, ", &self.current()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for CurrentCh1 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for CurrentCh1 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for CurrentCh1 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for CurrentCh1 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for CurrentCh1 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for CurrentCh1 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for CurrentCh1 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Current channel 2 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct CurrentCh2 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for CurrentCh2 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl CurrentCh2 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `current` field of the register. + /// + /// Calculated current in amperes, 2's complement + pub fn current(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `current` field of the register. + /// + /// Calculated current in amperes, 2's complement + pub fn set_current(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for CurrentCh2 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: CurrentCh2) -> Self { + val.bits + } + } + impl core::fmt::Debug for CurrentCh2 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("CurrentCh2"); + d.field("current", &self.current()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for CurrentCh2 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "CurrentCh2 {{ "); + defmt::write!(f, "current: {=u16}, ", &self.current()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for CurrentCh2 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for CurrentCh2 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for CurrentCh2 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for CurrentCh2 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for CurrentCh2 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for CurrentCh2 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for CurrentCh2 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Current channel 3 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct CurrentCh3 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for CurrentCh3 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl CurrentCh3 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `current` field of the register. + /// + /// Calculated current in amperes, 2's complement + pub fn current(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `current` field of the register. + /// + /// Calculated current in amperes, 2's complement + pub fn set_current(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for CurrentCh3 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: CurrentCh3) -> Self { + val.bits + } + } + impl core::fmt::Debug for CurrentCh3 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("CurrentCh3"); + d.field("current", &self.current()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for CurrentCh3 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "CurrentCh3 {{ "); + defmt::write!(f, "current: {=u16}, ", &self.current()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for CurrentCh3 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for CurrentCh3 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for CurrentCh3 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for CurrentCh3 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for CurrentCh3 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for CurrentCh3 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for CurrentCh3 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Current channel 4 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct CurrentCh4 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for CurrentCh4 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl CurrentCh4 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `current` field of the register. + /// + /// Calculated current in amperes, 2's complement + pub fn current(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `current` field of the register. + /// + /// Calculated current in amperes, 2's complement + pub fn set_current(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for CurrentCh4 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: CurrentCh4) -> Self { + val.bits + } + } + impl core::fmt::Debug for CurrentCh4 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("CurrentCh4"); + d.field("current", &self.current()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for CurrentCh4 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "CurrentCh4 {{ "); + defmt::write!(f, "current: {=u16}, ", &self.current()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for CurrentCh4 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for CurrentCh4 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for CurrentCh4 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for CurrentCh4 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for CurrentCh4 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for CurrentCh4 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for CurrentCh4 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Power channel 1. Value [W] = 32 x CURRENT_LSB x register_value. Unsigned. + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct PowerCh1 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for PowerCh1 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl PowerCh1 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `power` field of the register. + /// + /// Calculated power in watts, unsigned + pub fn power(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `power` field of the register. + /// + /// Calculated power in watts, unsigned + pub fn set_power(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for PowerCh1 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: PowerCh1) -> Self { + val.bits + } + } + impl core::fmt::Debug for PowerCh1 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("PowerCh1"); + d.field("power", &self.power()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for PowerCh1 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "PowerCh1 {{ "); + defmt::write!(f, "power: {=u16}, ", &self.power()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for PowerCh1 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for PowerCh1 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for PowerCh1 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for PowerCh1 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for PowerCh1 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for PowerCh1 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for PowerCh1 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Power channel 2 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct PowerCh2 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for PowerCh2 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl PowerCh2 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `power` field of the register. + /// + /// Calculated power in watts, unsigned + pub fn power(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `power` field of the register. + /// + /// Calculated power in watts, unsigned + pub fn set_power(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for PowerCh2 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: PowerCh2) -> Self { + val.bits + } + } + impl core::fmt::Debug for PowerCh2 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("PowerCh2"); + d.field("power", &self.power()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for PowerCh2 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "PowerCh2 {{ "); + defmt::write!(f, "power: {=u16}, ", &self.power()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for PowerCh2 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for PowerCh2 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for PowerCh2 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for PowerCh2 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for PowerCh2 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for PowerCh2 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for PowerCh2 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Power channel 3 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct PowerCh3 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for PowerCh3 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl PowerCh3 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `power` field of the register. + /// + /// Calculated power in watts, unsigned + pub fn power(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `power` field of the register. + /// + /// Calculated power in watts, unsigned + pub fn set_power(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for PowerCh3 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: PowerCh3) -> Self { + val.bits + } + } + impl core::fmt::Debug for PowerCh3 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("PowerCh3"); + d.field("power", &self.power()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for PowerCh3 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "PowerCh3 {{ "); + defmt::write!(f, "power: {=u16}, ", &self.power()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for PowerCh3 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for PowerCh3 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for PowerCh3 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for PowerCh3 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for PowerCh3 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for PowerCh3 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for PowerCh3 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Power channel 4 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct PowerCh4 { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for PowerCh4 { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl PowerCh4 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `power` field of the register. + /// + /// Calculated power in watts, unsigned + pub fn power(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `power` field of the register. + /// + /// Calculated power in watts, unsigned + pub fn set_power(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for PowerCh4 { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: PowerCh4) -> Self { + val.bits + } + } + impl core::fmt::Debug for PowerCh4 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("PowerCh4"); + d.field("power", &self.power()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for PowerCh4 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "PowerCh4 {{ "); + defmt::write!(f, "power: {=u16}, ", &self.power()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for PowerCh4 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for PowerCh4 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for PowerCh4 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for PowerCh4 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for PowerCh4 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for PowerCh4 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for PowerCh4 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Energy channel 1. Value [J] = 32 x CURRENT_LSB x register_value. Unsigned. + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct EnergyCh1 { + /// The internal bits + bits: [u8; 4], + } + impl ::device_driver::FieldSet for EnergyCh1 { + const SIZE_BITS: u32 = 32; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl EnergyCh1 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0, 0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 4] } + } + ///Read the `energy` field of the register. + /// + /// Accumulated energy in joules, unsigned + pub fn energy(&self) -> u32 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 32) + }; + raw + } + ///Write the `energy` field of the register. + /// + /// Accumulated energy in joules, unsigned + pub fn set_energy(&mut self, value: u32) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 32, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 4]> for EnergyCh1 { + fn from(bits: [u8; 4]) -> Self { + Self { bits } + } + } + impl From for [u8; 4] { + fn from(val: EnergyCh1) -> Self { + val.bits + } + } + impl core::fmt::Debug for EnergyCh1 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("EnergyCh1"); + d.field("energy", &self.energy()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for EnergyCh1 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "EnergyCh1 {{ "); + defmt::write!(f, "energy: {=u32}, ", &self.energy()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for EnergyCh1 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for EnergyCh1 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for EnergyCh1 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for EnergyCh1 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for EnergyCh1 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for EnergyCh1 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for EnergyCh1 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Energy channel 2 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct EnergyCh2 { + /// The internal bits + bits: [u8; 4], + } + impl ::device_driver::FieldSet for EnergyCh2 { + const SIZE_BITS: u32 = 32; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl EnergyCh2 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0, 0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 4] } + } + ///Read the `energy` field of the register. + /// + /// Accumulated energy in joules, unsigned + pub fn energy(&self) -> u32 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 32) + }; + raw + } + ///Write the `energy` field of the register. + /// + /// Accumulated energy in joules, unsigned + pub fn set_energy(&mut self, value: u32) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 32, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 4]> for EnergyCh2 { + fn from(bits: [u8; 4]) -> Self { + Self { bits } + } + } + impl From for [u8; 4] { + fn from(val: EnergyCh2) -> Self { + val.bits + } + } + impl core::fmt::Debug for EnergyCh2 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("EnergyCh2"); + d.field("energy", &self.energy()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for EnergyCh2 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "EnergyCh2 {{ "); + defmt::write!(f, "energy: {=u32}, ", &self.energy()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for EnergyCh2 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for EnergyCh2 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for EnergyCh2 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for EnergyCh2 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for EnergyCh2 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for EnergyCh2 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for EnergyCh2 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Energy channel 3 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct EnergyCh3 { + /// The internal bits + bits: [u8; 4], + } + impl ::device_driver::FieldSet for EnergyCh3 { + const SIZE_BITS: u32 = 32; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl EnergyCh3 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0, 0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 4] } + } + ///Read the `energy` field of the register. + /// + /// Accumulated energy in joules, unsigned + pub fn energy(&self) -> u32 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 32) + }; + raw + } + ///Write the `energy` field of the register. + /// + /// Accumulated energy in joules, unsigned + pub fn set_energy(&mut self, value: u32) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 32, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 4]> for EnergyCh3 { + fn from(bits: [u8; 4]) -> Self { + Self { bits } + } + } + impl From for [u8; 4] { + fn from(val: EnergyCh3) -> Self { + val.bits + } + } + impl core::fmt::Debug for EnergyCh3 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("EnergyCh3"); + d.field("energy", &self.energy()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for EnergyCh3 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "EnergyCh3 {{ "); + defmt::write!(f, "energy: {=u32}, ", &self.energy()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for EnergyCh3 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for EnergyCh3 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for EnergyCh3 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for EnergyCh3 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for EnergyCh3 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for EnergyCh3 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for EnergyCh3 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Energy channel 4 + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct EnergyCh4 { + /// The internal bits + bits: [u8; 4], + } + impl ::device_driver::FieldSet for EnergyCh4 { + const SIZE_BITS: u32 = 32; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl EnergyCh4 { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0, 0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 4] } + } + ///Read the `energy` field of the register. + /// + /// Accumulated energy in joules, unsigned + pub fn energy(&self) -> u32 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 32) + }; + raw + } + ///Write the `energy` field of the register. + /// + /// Accumulated energy in joules, unsigned + pub fn set_energy(&mut self, value: u32) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 32, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 4]> for EnergyCh4 { + fn from(bits: [u8; 4]) -> Self { + Self { bits } + } + } + impl From for [u8; 4] { + fn from(val: EnergyCh4) -> Self { + val.bits + } + } + impl core::fmt::Debug for EnergyCh4 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("EnergyCh4"); + d.field("energy", &self.energy()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for EnergyCh4 { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "EnergyCh4 {{ "); + defmt::write!(f, "energy: {=u32}, ", &self.energy()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for EnergyCh4 { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for EnergyCh4 { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for EnergyCh4 { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for EnergyCh4 { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for EnergyCh4 { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for EnergyCh4 { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for EnergyCh4 { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Flags register + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct Flags { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for Flags { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl Flags { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [0, 0] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `limit4_alert` field of the register. + /// + /// Alert limit 4 exceeded + pub fn limit4_alert(&self) -> bool { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 15, 16) + }; + raw > 0 + } + ///Read the `limit3_alert` field of the register. + /// + /// Alert limit 3 exceeded + pub fn limit3_alert(&self) -> bool { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 14, 15) + }; + raw > 0 + } + ///Read the `limit2_alert` field of the register. + /// + /// Alert limit 2 exceeded + pub fn limit2_alert(&self) -> bool { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 13, 14) + }; + raw > 0 + } + ///Read the `limit1_alert` field of the register. + /// + /// Alert limit 1 exceeded + pub fn limit1_alert(&self) -> bool { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 12, 13) + }; + raw > 0 + } + ///Read the `energyof_ch4` field of the register. + /// + /// Energy register overflow channel 4 + pub fn energyof_ch4(&self) -> bool { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 11, 12) + }; + raw > 0 + } + ///Read the `energyof_ch3` field of the register. + /// + /// Energy register overflow channel 3 + pub fn energyof_ch3(&self) -> bool { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 10, 11) + }; + raw > 0 + } + ///Read the `energyof_ch2` field of the register. + /// + /// Energy register overflow channel 2 + pub fn energyof_ch2(&self) -> bool { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 9, 10) + }; + raw > 0 + } + ///Read the `energyof_ch1` field of the register. + /// + /// Energy register overflow channel 1 + pub fn energyof_ch1(&self) -> bool { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 8, 9) + }; + raw > 0 + } + ///Read the `cvrf` field of the register. + /// + /// Conversion ready flag. Set when all conversions and averaging complete. Cleared by writing CONFIG1 or reading FLAGS. + pub fn cvrf(&self) -> bool { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 7, 8) + }; + raw > 0 + } + ///Read the `ovf` field of the register. + /// + /// Math overflow flag. Indicates current and power data may be invalid. + pub fn ovf(&self) -> bool { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 6, 7) + }; + raw > 0 + } + ///Write the `limit4_alert` field of the register. + /// + /// Alert limit 4 exceeded + pub fn set_limit4_alert(&mut self, value: bool) { + let raw = value as _; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 15, + 16, + &mut self.bits, + ) + }; + } + ///Write the `limit3_alert` field of the register. + /// + /// Alert limit 3 exceeded + pub fn set_limit3_alert(&mut self, value: bool) { + let raw = value as _; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 14, + 15, + &mut self.bits, + ) + }; + } + ///Write the `limit2_alert` field of the register. + /// + /// Alert limit 2 exceeded + pub fn set_limit2_alert(&mut self, value: bool) { + let raw = value as _; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 13, + 14, + &mut self.bits, + ) + }; + } + ///Write the `limit1_alert` field of the register. + /// + /// Alert limit 1 exceeded + pub fn set_limit1_alert(&mut self, value: bool) { + let raw = value as _; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 12, + 13, + &mut self.bits, + ) + }; + } + ///Write the `energyof_ch4` field of the register. + /// + /// Energy register overflow channel 4 + pub fn set_energyof_ch4(&mut self, value: bool) { + let raw = value as _; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 11, + 12, + &mut self.bits, + ) + }; + } + ///Write the `energyof_ch3` field of the register. + /// + /// Energy register overflow channel 3 + pub fn set_energyof_ch3(&mut self, value: bool) { + let raw = value as _; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 10, + 11, + &mut self.bits, + ) + }; + } + ///Write the `energyof_ch2` field of the register. + /// + /// Energy register overflow channel 2 + pub fn set_energyof_ch2(&mut self, value: bool) { + let raw = value as _; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 9, + 10, + &mut self.bits, + ) + }; + } + ///Write the `energyof_ch1` field of the register. + /// + /// Energy register overflow channel 1 + pub fn set_energyof_ch1(&mut self, value: bool) { + let raw = value as _; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 8, + 9, + &mut self.bits, + ) + }; + } + ///Write the `cvrf` field of the register. + /// + /// Conversion ready flag. Set when all conversions and averaging complete. Cleared by writing CONFIG1 or reading FLAGS. + pub fn set_cvrf(&mut self, value: bool) { + let raw = value as _; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 7, + 8, + &mut self.bits, + ) + }; + } + ///Write the `ovf` field of the register. + /// + /// Math overflow flag. Indicates current and power data may be invalid. + pub fn set_ovf(&mut self, value: bool) { + let raw = value as _; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 6, + 7, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for Flags { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: Flags) -> Self { + val.bits + } + } + impl core::fmt::Debug for Flags { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("Flags"); + d.field("limit4_alert", &self.limit4_alert()); + d.field("limit3_alert", &self.limit3_alert()); + d.field("limit2_alert", &self.limit2_alert()); + d.field("limit1_alert", &self.limit1_alert()); + d.field("energyof_ch4", &self.energyof_ch4()); + d.field("energyof_ch3", &self.energyof_ch3()); + d.field("energyof_ch2", &self.energyof_ch2()); + d.field("energyof_ch1", &self.energyof_ch1()); + d.field("cvrf", &self.cvrf()); + d.field("ovf", &self.ovf()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for Flags { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "Flags {{ "); + defmt::write!(f, "limit4_alert: {=bool}, ", &self.limit4_alert()); + defmt::write!(f, "limit3_alert: {=bool}, ", &self.limit3_alert()); + defmt::write!(f, "limit2_alert: {=bool}, ", &self.limit2_alert()); + defmt::write!(f, "limit1_alert: {=bool}, ", &self.limit1_alert()); + defmt::write!(f, "energyof_ch4: {=bool}, ", &self.energyof_ch4()); + defmt::write!(f, "energyof_ch3: {=bool}, ", &self.energyof_ch3()); + defmt::write!(f, "energyof_ch2: {=bool}, ", &self.energyof_ch2()); + defmt::write!(f, "energyof_ch1: {=bool}, ", &self.energyof_ch1()); + defmt::write!(f, "cvrf: {=bool}, ", &self.cvrf()); + defmt::write!(f, "ovf: {=bool}, ", &self.ovf()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for Flags { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for Flags { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for Flags { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for Flags { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for Flags { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for Flags { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for Flags { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Manufacturer ID. Reads back 0x5449 ('TI' in ASCII) + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct ManufacturerId { + /// The internal bits + bits: [u8; 2], + } + impl ::device_driver::FieldSet for ManufacturerId { + const SIZE_BITS: u32 = 16; + fn new_with_zero() -> Self { + Self::new_zero() + } + fn get_inner_buffer(&self) -> &[u8] { + &self.bits + } + fn get_inner_buffer_mut(&mut self) -> &mut [u8] { + &mut self.bits + } + } + impl ManufacturerId { + /// Create a new instance, loaded with the reset value (if any) + pub const fn new() -> Self { + Self { bits: [84, 73] } + } + /// Create a new instance, loaded with all zeroes + pub const fn new_zero() -> Self { + Self { bits: [0; 2] } + } + ///Read the `id` field of the register. + /// + /// Manufacturer ID + pub fn id(&self) -> u16 { + let raw = unsafe { + ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) + }; + raw + } + ///Write the `id` field of the register. + /// + /// Manufacturer ID + pub fn set_id(&mut self, value: u16) { + let raw = value; + unsafe { + ::device_driver::ops::store_lsb0::( + raw, + 0, + 16, + &mut self.bits, + ) + }; + } + } + impl From<[u8; 2]> for ManufacturerId { + fn from(bits: [u8; 2]) -> Self { + Self { bits } + } + } + impl From for [u8; 2] { + fn from(val: ManufacturerId) -> Self { + val.bits + } + } + impl core::fmt::Debug for ManufacturerId { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let mut d = f.debug_struct("ManufacturerId"); + d.field("id", &self.id()); + d.finish() + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for ManufacturerId { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "ManufacturerId {{ "); + defmt::write!(f, "id: {=u16}, ", &self.id()); + defmt::write!(f, "}}"); + } + } + impl core::ops::BitAnd for ManufacturerId { + type Output = Self; + fn bitand(mut self, rhs: Self) -> Self::Output { + self &= rhs; + self + } + } + impl core::ops::BitAndAssign for ManufacturerId { + fn bitand_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l &= *r; + } + } + } + impl core::ops::BitOr for ManufacturerId { + type Output = Self; + fn bitor(mut self, rhs: Self) -> Self::Output { + self |= rhs; + self + } + } + impl core::ops::BitOrAssign for ManufacturerId { + fn bitor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l |= *r; + } + } + } + impl core::ops::BitXor for ManufacturerId { + type Output = Self; + fn bitxor(mut self, rhs: Self) -> Self::Output { + self ^= rhs; + self + } + } + impl core::ops::BitXorAssign for ManufacturerId { + fn bitxor_assign(&mut self, rhs: Self) { + for (l, r) in self.bits.iter_mut().zip(&rhs.bits) { + *l ^= *r; + } + } + } + impl core::ops::Not for ManufacturerId { + type Output = Self; + fn not(mut self) -> Self::Output { + for val in self.bits.iter_mut() { + *val = !*val; + } + self + } + } + /// Enum containing all possible field set types + pub enum FieldSetValue { + /// Configuration register 1 + Config1(Config1), + /// Configuration register 2 + Config2(Config2), + /// Calibration register channel 1 + CalibrationCh1(CalibrationCh1), + /// Calibration register channel 2 + CalibrationCh2(CalibrationCh2), + /// Calibration register channel 3 + CalibrationCh3(CalibrationCh3), + /// Calibration register channel 4 + CalibrationCh4(CalibrationCh4), + /// Alert configuration register 1 + AlertConfig1(AlertConfig1), + /// Alert configuration register 2 + AlertConfig2(AlertConfig2), + /// Alert configuration register 3 + AlertConfig3(AlertConfig3), + /// Alert configuration register 4 + AlertConfig4(AlertConfig4), + /// Alert limit register 1. Format matches corresponding result register. + AlertLimit1(AlertLimit1), + /// Alert limit register 2 + AlertLimit2(AlertLimit2), + /// Alert limit register 3 + AlertLimit3(AlertLimit3), + /// Alert limit register 4 + AlertLimit4(AlertLimit4), + /// Shunt voltage channel 1. 2's complement. LSB = 2.5uV (range=0) or 625nV (range=1) + ShuntVoltageCh1(ShuntVoltageCh1), + /// Shunt voltage channel 2 + ShuntVoltageCh2(ShuntVoltageCh2), + /// Shunt voltage channel 3 + ShuntVoltageCh3(ShuntVoltageCh3), + /// Shunt voltage channel 4 + ShuntVoltageCh4(ShuntVoltageCh4), + /// Bus voltage channel 1. Always positive. LSB = 1.6mV + BusVoltageCh1(BusVoltageCh1), + /// Bus voltage channel 2 + BusVoltageCh2(BusVoltageCh2), + /// Bus voltage channel 3 + BusVoltageCh3(BusVoltageCh3), + /// Bus voltage channel 4 + BusVoltageCh4(BusVoltageCh4), + /// Current channel 1. Value [A] = CURRENT_LSB x register_value + CurrentCh1(CurrentCh1), + /// Current channel 2 + CurrentCh2(CurrentCh2), + /// Current channel 3 + CurrentCh3(CurrentCh3), + /// Current channel 4 + CurrentCh4(CurrentCh4), + /// Power channel 1. Value [W] = 32 x CURRENT_LSB x register_value. Unsigned. + PowerCh1(PowerCh1), + /// Power channel 2 + PowerCh2(PowerCh2), + /// Power channel 3 + PowerCh3(PowerCh3), + /// Power channel 4 + PowerCh4(PowerCh4), + /// Energy channel 1. Value [J] = 32 x CURRENT_LSB x register_value. Unsigned. + EnergyCh1(EnergyCh1), + /// Energy channel 2 + EnergyCh2(EnergyCh2), + /// Energy channel 3 + EnergyCh3(EnergyCh3), + /// Energy channel 4 + EnergyCh4(EnergyCh4), + /// Flags register + Flags(Flags), + /// Manufacturer ID. Reads back 0x5449 ('TI' in ASCII) + ManufacturerId(ManufacturerId), + } + impl core::fmt::Debug for FieldSetValue { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Config1(val) => core::fmt::Debug::fmt(val, f), + Self::Config2(val) => core::fmt::Debug::fmt(val, f), + Self::CalibrationCh1(val) => core::fmt::Debug::fmt(val, f), + Self::CalibrationCh2(val) => core::fmt::Debug::fmt(val, f), + Self::CalibrationCh3(val) => core::fmt::Debug::fmt(val, f), + Self::CalibrationCh4(val) => core::fmt::Debug::fmt(val, f), + Self::AlertConfig1(val) => core::fmt::Debug::fmt(val, f), + Self::AlertConfig2(val) => core::fmt::Debug::fmt(val, f), + Self::AlertConfig3(val) => core::fmt::Debug::fmt(val, f), + Self::AlertConfig4(val) => core::fmt::Debug::fmt(val, f), + Self::AlertLimit1(val) => core::fmt::Debug::fmt(val, f), + Self::AlertLimit2(val) => core::fmt::Debug::fmt(val, f), + Self::AlertLimit3(val) => core::fmt::Debug::fmt(val, f), + Self::AlertLimit4(val) => core::fmt::Debug::fmt(val, f), + Self::ShuntVoltageCh1(val) => core::fmt::Debug::fmt(val, f), + Self::ShuntVoltageCh2(val) => core::fmt::Debug::fmt(val, f), + Self::ShuntVoltageCh3(val) => core::fmt::Debug::fmt(val, f), + Self::ShuntVoltageCh4(val) => core::fmt::Debug::fmt(val, f), + Self::BusVoltageCh1(val) => core::fmt::Debug::fmt(val, f), + Self::BusVoltageCh2(val) => core::fmt::Debug::fmt(val, f), + Self::BusVoltageCh3(val) => core::fmt::Debug::fmt(val, f), + Self::BusVoltageCh4(val) => core::fmt::Debug::fmt(val, f), + Self::CurrentCh1(val) => core::fmt::Debug::fmt(val, f), + Self::CurrentCh2(val) => core::fmt::Debug::fmt(val, f), + Self::CurrentCh3(val) => core::fmt::Debug::fmt(val, f), + Self::CurrentCh4(val) => core::fmt::Debug::fmt(val, f), + Self::PowerCh1(val) => core::fmt::Debug::fmt(val, f), + Self::PowerCh2(val) => core::fmt::Debug::fmt(val, f), + Self::PowerCh3(val) => core::fmt::Debug::fmt(val, f), + Self::PowerCh4(val) => core::fmt::Debug::fmt(val, f), + Self::EnergyCh1(val) => core::fmt::Debug::fmt(val, f), + Self::EnergyCh2(val) => core::fmt::Debug::fmt(val, f), + Self::EnergyCh3(val) => core::fmt::Debug::fmt(val, f), + Self::EnergyCh4(val) => core::fmt::Debug::fmt(val, f), + Self::Flags(val) => core::fmt::Debug::fmt(val, f), + Self::ManufacturerId(val) => core::fmt::Debug::fmt(val, f), + #[allow(unreachable_patterns)] + _ => unreachable!(), + } + } + } + #[cfg(feature = "defmt-03")] + impl defmt::Format for FieldSetValue { + fn format(&self, f: defmt::Formatter) { + match self { + Self::Config1(val) => defmt::Format::format(val, f), + Self::Config2(val) => defmt::Format::format(val, f), + Self::CalibrationCh1(val) => defmt::Format::format(val, f), + Self::CalibrationCh2(val) => defmt::Format::format(val, f), + Self::CalibrationCh3(val) => defmt::Format::format(val, f), + Self::CalibrationCh4(val) => defmt::Format::format(val, f), + Self::AlertConfig1(val) => defmt::Format::format(val, f), + Self::AlertConfig2(val) => defmt::Format::format(val, f), + Self::AlertConfig3(val) => defmt::Format::format(val, f), + Self::AlertConfig4(val) => defmt::Format::format(val, f), + Self::AlertLimit1(val) => defmt::Format::format(val, f), + Self::AlertLimit2(val) => defmt::Format::format(val, f), + Self::AlertLimit3(val) => defmt::Format::format(val, f), + Self::AlertLimit4(val) => defmt::Format::format(val, f), + Self::ShuntVoltageCh1(val) => defmt::Format::format(val, f), + Self::ShuntVoltageCh2(val) => defmt::Format::format(val, f), + Self::ShuntVoltageCh3(val) => defmt::Format::format(val, f), + Self::ShuntVoltageCh4(val) => defmt::Format::format(val, f), + Self::BusVoltageCh1(val) => defmt::Format::format(val, f), + Self::BusVoltageCh2(val) => defmt::Format::format(val, f), + Self::BusVoltageCh3(val) => defmt::Format::format(val, f), + Self::BusVoltageCh4(val) => defmt::Format::format(val, f), + Self::CurrentCh1(val) => defmt::Format::format(val, f), + Self::CurrentCh2(val) => defmt::Format::format(val, f), + Self::CurrentCh3(val) => defmt::Format::format(val, f), + Self::CurrentCh4(val) => defmt::Format::format(val, f), + Self::PowerCh1(val) => defmt::Format::format(val, f), + Self::PowerCh2(val) => defmt::Format::format(val, f), + Self::PowerCh3(val) => defmt::Format::format(val, f), + Self::PowerCh4(val) => defmt::Format::format(val, f), + Self::EnergyCh1(val) => defmt::Format::format(val, f), + Self::EnergyCh2(val) => defmt::Format::format(val, f), + Self::EnergyCh3(val) => defmt::Format::format(val, f), + Self::EnergyCh4(val) => defmt::Format::format(val, f), + Self::Flags(val) => defmt::Format::format(val, f), + Self::ManufacturerId(val) => defmt::Format::format(val, f), + } + } + } + impl From for FieldSetValue { + fn from(val: Config1) -> Self { + Self::Config1(val) + } + } + impl From for FieldSetValue { + fn from(val: Config2) -> Self { + Self::Config2(val) + } + } + impl From for FieldSetValue { + fn from(val: CalibrationCh1) -> Self { + Self::CalibrationCh1(val) + } + } + impl From for FieldSetValue { + fn from(val: CalibrationCh2) -> Self { + Self::CalibrationCh2(val) + } + } + impl From for FieldSetValue { + fn from(val: CalibrationCh3) -> Self { + Self::CalibrationCh3(val) + } + } + impl From for FieldSetValue { + fn from(val: CalibrationCh4) -> Self { + Self::CalibrationCh4(val) + } + } + impl From for FieldSetValue { + fn from(val: AlertConfig1) -> Self { + Self::AlertConfig1(val) + } + } + impl From for FieldSetValue { + fn from(val: AlertConfig2) -> Self { + Self::AlertConfig2(val) + } + } + impl From for FieldSetValue { + fn from(val: AlertConfig3) -> Self { + Self::AlertConfig3(val) + } + } + impl From for FieldSetValue { + fn from(val: AlertConfig4) -> Self { + Self::AlertConfig4(val) + } + } + impl From for FieldSetValue { + fn from(val: AlertLimit1) -> Self { + Self::AlertLimit1(val) + } + } + impl From for FieldSetValue { + fn from(val: AlertLimit2) -> Self { + Self::AlertLimit2(val) + } + } + impl From for FieldSetValue { + fn from(val: AlertLimit3) -> Self { + Self::AlertLimit3(val) + } + } + impl From for FieldSetValue { + fn from(val: AlertLimit4) -> Self { + Self::AlertLimit4(val) + } + } + impl From for FieldSetValue { + fn from(val: ShuntVoltageCh1) -> Self { + Self::ShuntVoltageCh1(val) + } + } + impl From for FieldSetValue { + fn from(val: ShuntVoltageCh2) -> Self { + Self::ShuntVoltageCh2(val) + } + } + impl From for FieldSetValue { + fn from(val: ShuntVoltageCh3) -> Self { + Self::ShuntVoltageCh3(val) + } + } + impl From for FieldSetValue { + fn from(val: ShuntVoltageCh4) -> Self { + Self::ShuntVoltageCh4(val) + } + } + impl From for FieldSetValue { + fn from(val: BusVoltageCh1) -> Self { + Self::BusVoltageCh1(val) + } + } + impl From for FieldSetValue { + fn from(val: BusVoltageCh2) -> Self { + Self::BusVoltageCh2(val) + } + } + impl From for FieldSetValue { + fn from(val: BusVoltageCh3) -> Self { + Self::BusVoltageCh3(val) + } + } + impl From for FieldSetValue { + fn from(val: BusVoltageCh4) -> Self { + Self::BusVoltageCh4(val) + } + } + impl From for FieldSetValue { + fn from(val: CurrentCh1) -> Self { + Self::CurrentCh1(val) + } + } + impl From for FieldSetValue { + fn from(val: CurrentCh2) -> Self { + Self::CurrentCh2(val) + } + } + impl From for FieldSetValue { + fn from(val: CurrentCh3) -> Self { + Self::CurrentCh3(val) + } + } + impl From for FieldSetValue { + fn from(val: CurrentCh4) -> Self { + Self::CurrentCh4(val) + } + } + impl From for FieldSetValue { + fn from(val: PowerCh1) -> Self { + Self::PowerCh1(val) + } + } + impl From for FieldSetValue { + fn from(val: PowerCh2) -> Self { + Self::PowerCh2(val) + } + } + impl From for FieldSetValue { + fn from(val: PowerCh3) -> Self { + Self::PowerCh3(val) + } + } + impl From for FieldSetValue { + fn from(val: PowerCh4) -> Self { + Self::PowerCh4(val) + } + } + impl From for FieldSetValue { + fn from(val: EnergyCh1) -> Self { + Self::EnergyCh1(val) + } + } + impl From for FieldSetValue { + fn from(val: EnergyCh2) -> Self { + Self::EnergyCh2(val) + } + } + impl From for FieldSetValue { + fn from(val: EnergyCh3) -> Self { + Self::EnergyCh3(val) + } + } + impl From for FieldSetValue { + fn from(val: EnergyCh4) -> Self { + Self::EnergyCh4(val) + } + } + impl From for FieldSetValue { + fn from(val: Flags) -> Self { + Self::Flags(val) + } + } + impl From for FieldSetValue { + fn from(val: ManufacturerId) -> Self { + Self::ManufacturerId(val) + } + } +} +/// Averaging count +#[repr(u8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +pub enum Averaging { + _1 = 0, + _4 = 1, + _16 = 2, + _64 = 3, + _128 = 4, + _256 = 5, + _512 = 6, + _1024 = 7, +} +impl core::convert::TryFrom for Averaging { + type Error = ::device_driver::ConversionError; + fn try_from(val: u8) -> Result { + match val { + 0 => Ok(Self::_1), + 1 => Ok(Self::_4), + 2 => Ok(Self::_16), + 3 => Ok(Self::_64), + 4 => Ok(Self::_128), + 5 => Ok(Self::_256), + 6 => Ok(Self::_512), + 7 => Ok(Self::_1024), + val => Err(::device_driver::ConversionError { + source: val, + target: "Averaging", + }), + } + } +} +impl From for u8 { + fn from(val: Averaging) -> Self { + match val { + Averaging::_1 => 0, + Averaging::_4 => 1, + Averaging::_16 => 2, + Averaging::_64 => 3, + Averaging::_128 => 4, + Averaging::_256 => 5, + Averaging::_512 => 6, + Averaging::_1024 => 7, + } + } +} +/// Bus voltage conversion time +#[repr(u8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +pub enum BusConversionTime { + _140Us = 0, + _204Us = 1, + _332Us = 2, + _588Us = 3, + _1100Us = 4, + _2116Us = 5, + _4156Us = 6, + _8244Us = 7, +} +impl core::convert::TryFrom for BusConversionTime { + type Error = ::device_driver::ConversionError; + fn try_from(val: u8) -> Result { + match val { + 0 => Ok(Self::_140Us), + 1 => Ok(Self::_204Us), + 2 => Ok(Self::_332Us), + 3 => Ok(Self::_588Us), + 4 => Ok(Self::_1100Us), + 5 => Ok(Self::_2116Us), + 6 => Ok(Self::_4156Us), + 7 => Ok(Self::_8244Us), + val => Err(::device_driver::ConversionError { + source: val, + target: "BusConversionTime", + }), + } + } +} +impl From for u8 { + fn from(val: BusConversionTime) -> Self { + match val { + BusConversionTime::_140Us => 0, + BusConversionTime::_204Us => 1, + BusConversionTime::_332Us => 2, + BusConversionTime::_588Us => 3, + BusConversionTime::_1100Us => 4, + BusConversionTime::_2116Us => 5, + BusConversionTime::_4156Us => 6, + BusConversionTime::_8244Us => 7, + } + } +} +/// Shunt voltage conversion time +#[repr(u8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +pub enum ShuntConversionTime { + _140Us = 0, + _204Us = 1, + _332Us = 2, + _588Us = 3, + _1100Us = 4, + _2116Us = 5, + _4156Us = 6, + _8244Us = 7, +} +impl core::convert::TryFrom for ShuntConversionTime { + type Error = ::device_driver::ConversionError; + fn try_from(val: u8) -> Result { + match val { + 0 => Ok(Self::_140Us), + 1 => Ok(Self::_204Us), + 2 => Ok(Self::_332Us), + 3 => Ok(Self::_588Us), + 4 => Ok(Self::_1100Us), + 5 => Ok(Self::_2116Us), + 6 => Ok(Self::_4156Us), + 7 => Ok(Self::_8244Us), + val => Err(::device_driver::ConversionError { + source: val, + target: "ShuntConversionTime", + }), + } + } +} +impl From for u8 { + fn from(val: ShuntConversionTime) -> Self { + match val { + ShuntConversionTime::_140Us => 0, + ShuntConversionTime::_204Us => 1, + ShuntConversionTime::_332Us => 2, + ShuntConversionTime::_588Us => 3, + ShuntConversionTime::_1100Us => 4, + ShuntConversionTime::_2116Us => 5, + ShuntConversionTime::_4156Us => 6, + ShuntConversionTime::_8244Us => 7, + } + } +} +/// Operating mode +#[repr(u8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +pub enum Mode { + Shutdown = 0, + ShuntTriggered = 1, + BusTriggered = 2, + ShuntAndBusTriggered = 3, + Shutdown2 = 4, + ContinuousShunt = 5, + ContinuousBus = 6, + ContinuousShuntAndBus = 7, +} +impl core::convert::TryFrom for Mode { + type Error = ::device_driver::ConversionError; + fn try_from(val: u8) -> Result { + match val { + 0 => Ok(Self::Shutdown), + 1 => Ok(Self::ShuntTriggered), + 2 => Ok(Self::BusTriggered), + 3 => Ok(Self::ShuntAndBusTriggered), + 4 => Ok(Self::Shutdown2), + 5 => Ok(Self::ContinuousShunt), + 6 => Ok(Self::ContinuousBus), + 7 => Ok(Self::ContinuousShuntAndBus), + val => Err(::device_driver::ConversionError { + source: val, + target: "Mode", + }), + } + } +} +impl From for u8 { + fn from(val: Mode) -> Self { + match val { + Mode::Shutdown => 0, + Mode::ShuntTriggered => 1, + Mode::BusTriggered => 2, + Mode::ShuntAndBusTriggered => 3, + Mode::Shutdown2 => 4, + Mode::ContinuousShunt => 5, + Mode::ContinuousBus => 6, + Mode::ContinuousShuntAndBus => 7, + } + } +} +#[repr(u8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +pub enum AlertPolarity { + ActiveLow = 0, + ActiveHigh = 1, +} +impl core::convert::TryFrom for AlertPolarity { + type Error = ::device_driver::ConversionError; + fn try_from(val: u8) -> Result { + match val { + 0 => Ok(Self::ActiveLow), + 1 => Ok(Self::ActiveHigh), + val => Err(::device_driver::ConversionError { + source: val, + target: "AlertPolarity", + }), + } + } +} +impl From for u8 { + fn from(val: AlertPolarity) -> Self { + match val { + AlertPolarity::ActiveLow => 0, + AlertPolarity::ActiveHigh => 1, + } + } +} +#[repr(u8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +pub enum AlertChannel { + Ch1 = 0, + Ch2 = 1, + Ch3 = 2, + Ch4 = 3, +} +impl core::convert::TryFrom for AlertChannel { + type Error = ::device_driver::ConversionError; + fn try_from(val: u8) -> Result { + match val { + 0 => Ok(Self::Ch1), + 1 => Ok(Self::Ch2), + 2 => Ok(Self::Ch3), + 3 => Ok(Self::Ch4), + val => Err(::device_driver::ConversionError { + source: val, + target: "AlertChannel", + }), + } + } +} +impl From for u8 { + fn from(val: AlertChannel) -> Self { + match val { + AlertChannel::Ch1 => 0, + AlertChannel::Ch2 => 1, + AlertChannel::Ch3 => 2, + AlertChannel::Ch4 => 3, + } + } +} +#[repr(u8)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +pub enum AlertFunction { + None = 0, + ShuntOverLimit = 1, + ShuntUnderLimit = 2, + BusOverLimit = 3, + BusUnderLimit = 4, + PowerOverLimit = 5, + Reserved6 = 6, + Reserved7 = 7, +} +impl core::convert::TryFrom for AlertFunction { + type Error = ::device_driver::ConversionError; + fn try_from(val: u8) -> Result { + match val { + 0 => Ok(Self::None), + 1 => Ok(Self::ShuntOverLimit), + 2 => Ok(Self::ShuntUnderLimit), + 3 => Ok(Self::BusOverLimit), + 4 => Ok(Self::BusUnderLimit), + 5 => Ok(Self::PowerOverLimit), + 6 => Ok(Self::Reserved6), + 7 => Ok(Self::Reserved7), + val => Err(::device_driver::ConversionError { + source: val, + target: "AlertFunction", + }), + } + } +} +impl From for u8 { + fn from(val: AlertFunction) -> Self { + match val { + AlertFunction::None => 0, + AlertFunction::ShuntOverLimit => 1, + AlertFunction::ShuntUnderLimit => 2, + AlertFunction::BusOverLimit => 3, + AlertFunction::BusUnderLimit => 4, + AlertFunction::PowerOverLimit => 5, + AlertFunction::Reserved6 => 6, + AlertFunction::Reserved7 => 7, + } + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..580cc67 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,474 @@ +//! Platform-agnostic Rust driver for the Texas Instruments INA4230 quad-channel +//! power and energy sense monitor, based on the [`embedded-hal`] traits. +//! +//! [`embedded-hal`]: https://docs.rs/embedded-hal +//! +//! For further details of the device architecture and operation, please refer +//! to the official [`Datasheet`]. +//! +//! [`Datasheet`]: https://www.ti.com/lit/ds/symlink/ina4230.pdf + +#![doc = include_str!("../README.md")] +#![cfg_attr(not(test), no_std)] +#![allow(async_fn_in_trait)] + +use embedded_sensors_hal_async::sensor; + +#[allow(clippy::all)] +#[allow(clippy::pedantic)] +#[allow(unsafe_code)] +#[allow(missing_docs)] +mod device; + +pub use crate::device::*; + +// ── I²C address ─────────────────────────────────────────────────────────────── + +/// Default 7-bit I²C address for the INA4230 (A0=GND, A1=GND → 0x40). +pub const INA4230_ADDR: u8 = 0x40; + +/// Maximum register data size in bytes (energy registers are 32-bit = 4 bytes). +const LARGEST_REG_SIZE_BYTES: usize = 4; + +// ── Error type ──────────────────────────────────────────────────────────────── + +/// INA4230 driver error. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +pub enum Ina4230Error { + /// An error occurred on the I²C bus. + Bus(I2cError), +} + +impl sensor::Error for Ina4230Error { + fn kind(&self) -> sensor::ErrorKind { + match self { + Self::Bus(_) => sensor::ErrorKind::Peripheral, + } + } +} + +// ── DeviceInterface ─────────────────────────────────────────────────────────── + +/// Async I²C interface adapter for the INA4230. +pub struct DeviceInterface { + /// The underlying async I²C bus. + pub i2c: I2c, + /// 7-bit I²C address of this device instance (see [`INA4230_ADDR`]). + pub address: u8, +} + +impl device_driver::AsyncRegisterInterface + for DeviceInterface +{ + type Error = Ina4230Error; + type AddressType = u8; + + async fn write_register( + &mut self, + address: Self::AddressType, + _size_bits: u32, + data: &[u8], + ) -> Result<(), Self::Error> { + debug_assert!(data.len() <= LARGEST_REG_SIZE_BYTES, "Register data too large"); + let mut buf = [0u8; 1 + LARGEST_REG_SIZE_BYTES]; + buf[0] = address; + buf[1..=data.len()].copy_from_slice(data); + self.i2c + .write(self.address, &buf[..=data.len()]) + .await + .map_err(Ina4230Error::Bus) + } + + async fn read_register( + &mut self, + address: Self::AddressType, + _size_bits: u32, + data: &mut [u8], + ) -> Result<(), Self::Error> { + self.i2c + .write_read(self.address, &[address], data) + .await + .map_err(Ina4230Error::Bus) + } +} + +// ── Channel ─────────────────────────────────────────────────────────────────── + +/// One of the four measurement channels on the INA4230. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +pub enum Channel { + /// Channel 1 + Ch1, + /// Channel 2 + Ch2, + /// Channel 3 + Ch3, + /// Channel 4 + Ch4, +} + +/// ADC full-scale input range for shunt voltage measurement. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +pub enum AdcRange { + /// ±81.92 mV full scale, LSB = 2.5 µV (default) + Range0, + /// ±20.48 mV full scale, LSB = 625 nV. SHUNT_CAL divided by 4. + Range1, +} + +// ── Physical-unit type aliases ──────────────────────────────────────────────── + +/// Voltage in millivolts. +pub type MilliVolts = f32; +/// Current in milliamperes. +pub type MilliAmps = f32; +/// Power in milliwatts. +pub type MilliWatts = f32; +/// Energy in millijoules. +pub type MilliJoules = f32; + +// ── Sensor traits ───────────────────────────────────────────────────────────── + +/// Async voltage sensor — reads bus or shunt voltage per channel. +pub trait VoltageSensor: sensor::ErrorType { + /// Read the bus voltage for the given channel, in millivolts (LSB = 1.6 mV). + async fn bus_voltage(&mut self, channel: Channel) -> Result; + /// Read the shunt voltage for the given channel, in millivolts (LSB = 2.5 µV). + async fn shunt_voltage(&mut self, channel: Channel) -> Result; +} + +impl VoltageSensor for &mut T { + async fn bus_voltage(&mut self, channel: Channel) -> Result { + T::bus_voltage(self, channel).await + } + async fn shunt_voltage(&mut self, channel: Channel) -> Result { + T::shunt_voltage(self, channel).await + } +} + +/// Async current sensor — reads calculated current per channel. +pub trait CurrentSensor: sensor::ErrorType { + /// Read the calculated current for the given channel, in milliamperes. + /// Requires [`Ina4230::calibrate`] to have been called first. + async fn current(&mut self, channel: Channel) -> Result; +} + +impl CurrentSensor for &mut T { + async fn current(&mut self, channel: Channel) -> Result { + T::current(self, channel).await + } +} + +/// Async power sensor — reads calculated power per channel. +pub trait PowerSensor: sensor::ErrorType { + /// Read the calculated power for the given channel, in milliwatts. + /// Requires [`Ina4230::calibrate`] to have been called first. + async fn power(&mut self, channel: Channel) -> Result; +} + +impl PowerSensor for &mut T { + async fn power(&mut self, channel: Channel) -> Result { + T::power(self, channel).await + } +} + +/// Async energy sensor — reads accumulated energy per channel. +pub trait EnergySensor: sensor::ErrorType { + /// Read the accumulated energy for the given channel, in millijoules. + /// Requires [`Ina4230::calibrate`] to have been called first. + async fn energy(&mut self, channel: Channel) -> Result; +} + +impl EnergySensor for &mut T { + async fn energy(&mut self, channel: Channel) -> Result { + T::energy(self, channel).await + } +} + +// ── Ina4230 driver struct ───────────────────────────────────────────────────── + +/// High-level driver for the INA4230 quad-channel power and energy monitor. +pub struct Ina4230 { + /// The generated low-level register accessor. + pub device: Device>, + /// Stored CURRENT_LSB in A/LSB, set by `calibrate*`. Used for unit conversion. + current_lsb_a: f32, + /// ADC input range, set during calibration. Used for shunt voltage LSB selection. + adc_range: AdcRange, +} + +impl Ina4230 { + /// Create a new driver instance. + /// + /// Pass [`INA4230_ADDR`] for the default address (A0=GND, A1=GND → 0x40). + pub fn new(i2c: I2c, address: u8) -> Self { + Self { + device: Device::new(DeviceInterface { i2c, address }), + current_lsb_a: 0.0, + adc_range: AdcRange::Range0, + } + } + + /// Release the underlying I²C bus. + pub fn release(self) -> I2c { + self.device.interface.i2c + } + + // ── Device management ───────────────────────────────────────────────── + + /// Issue a full device reset (`CONFIG2.RST = 1`). All registers return to + /// power-on defaults. The bit self-clears. + pub async fn reset(&mut self) -> Result<(), Ina4230Error> { + self.device.config_2().write_async(|w| w.set_rst(true)).await + } + + /// Read the manufacturer ID register. Returns `0x5449` ("TI") on a healthy device. + pub async fn manufacturer_id(&mut self) -> Result> { + Ok(self.device.manufacturer_id().read_async().await?.id()) + } + + /// Poll the Conversion Ready Flag (`FLAGS.CVRF`). Returns `true` when all + /// enabled channels have completed conversion and averaging. Reading FLAGS clears CVRF. + pub async fn conversion_ready(&mut self) -> Result> { + Ok(self.device.flags().read_async().await?.cvrf()) + } + + /// Read the full flags register in one call. + pub async fn flags(&mut self) -> Result> { + self.device.flags().read_async().await + } + + // ── Calibration ─────────────────────────────────────────────────────── + + /// Write the calibration register for a single channel. + /// + /// - `current_lsb_a`: desired current resolution in A/LSB (e.g. `100e-6` for 100 µA/LSB) + /// - `shunt_ohms`: shunt resistor value in Ω (e.g. `0.010` for 10 mΩ) + /// - `adc_range`: ADC full-scale input range (use [`AdcRange::Range0`] for default ±81.92 mV) + /// + /// Formula (ADCRANGE = 0): `SHUNT_CAL = 0.00512 / (CURRENT_LSB × R_SHUNT)` + /// Formula (ADCRANGE = 1): `SHUNT_CAL = 0.00512 / (CURRENT_LSB × R_SHUNT) / 4` + pub async fn calibrate( + &mut self, + channel: Channel, + current_lsb_a: f32, + shunt_ohms: f32, + adc_range: AdcRange, + ) -> Result<(), Ina4230Error> { + self.current_lsb_a = current_lsb_a; + self.adc_range = adc_range; + let cal = Self::shunt_cal_value(current_lsb_a, shunt_ohms, adc_range); + match channel { + Channel::Ch1 => { + self.device.calibration_ch_1().write_async(|w| w.set_shunt_cal(cal)).await + } + Channel::Ch2 => { + self.device.calibration_ch_2().write_async(|w| w.set_shunt_cal(cal)).await + } + Channel::Ch3 => { + self.device.calibration_ch_3().write_async(|w| w.set_shunt_cal(cal)).await + } + Channel::Ch4 => { + self.device.calibration_ch_4().write_async(|w| w.set_shunt_cal(cal)).await + } + } + } + + /// Write the calibration register for all four channels with identical parameters. + pub async fn calibrate_all( + &mut self, + current_lsb_a: f32, + shunt_ohms: f32, + adc_range: AdcRange, + ) -> Result<(), Ina4230Error> { + for ch in [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] { + self.calibrate(ch, current_lsb_a, shunt_ohms, adc_range).await?; + } + Ok(()) + } + + // ── Internal unit-conversion helpers ────────────────────────────────── + + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + fn shunt_cal_value(current_lsb_a: f32, shunt_ohms: f32, adc_range: AdcRange) -> u16 { + // INA4230 datasheet §8.1.2: SHUNT_CAL = 0.00512 / (CURRENT_LSB × R_SHUNT) + let val = 0.00512_f32 / (current_lsb_a * shunt_ohms); + let val = match adc_range { + AdcRange::Range0 => val, + AdcRange::Range1 => val / 4.0, + }; + (val as u32).min(u32::from(u16::MAX)) as u16 + } + + fn bus_mv(raw: u16) -> MilliVolts { + f32::from(raw) * 1.6 + } + + #[allow(clippy::cast_possible_wrap)] + fn shunt_mv(&self, raw: u16) -> MilliVolts { + let signed = raw as i16; + let lsb_mv = match self.adc_range { + AdcRange::Range0 => 0.0025, // 2.5 µV + AdcRange::Range1 => 0.000625, // 625 nV + }; + f32::from(signed) * lsb_mv + } + + #[allow(clippy::cast_possible_wrap)] + fn current_ma(&self, raw: u16) -> MilliAmps { + let signed = raw as i16; + f32::from(signed) * self.current_lsb_a * 1000.0 + } + + fn power_mw(&self, raw: u16) -> MilliWatts { + f32::from(raw) * 32.0 * self.current_lsb_a * 1000.0 + } + + fn energy_mj(&self, raw: u32) -> MilliJoules { + raw as f32 * 32.0 * self.current_lsb_a * 1000.0 + } +} + +// ── Trait implementations ───────────────────────────────────────────────────── + +impl sensor::ErrorType for Ina4230 { + type Error = Ina4230Error; +} + +impl VoltageSensor for Ina4230 { + async fn bus_voltage(&mut self, channel: Channel) -> Result { + let raw = match channel { + Channel::Ch1 => self.device.bus_voltage_ch_1().read_async().await?.vbus(), + Channel::Ch2 => self.device.bus_voltage_ch_2().read_async().await?.vbus(), + Channel::Ch3 => self.device.bus_voltage_ch_3().read_async().await?.vbus(), + Channel::Ch4 => self.device.bus_voltage_ch_4().read_async().await?.vbus(), + }; + Ok(Self::bus_mv(raw)) + } + + async fn shunt_voltage(&mut self, channel: Channel) -> Result { + let raw = match channel { + Channel::Ch1 => self.device.shunt_voltage_ch_1().read_async().await?.vshunt(), + Channel::Ch2 => self.device.shunt_voltage_ch_2().read_async().await?.vshunt(), + Channel::Ch3 => self.device.shunt_voltage_ch_3().read_async().await?.vshunt(), + Channel::Ch4 => self.device.shunt_voltage_ch_4().read_async().await?.vshunt(), + }; + Ok(self.shunt_mv(raw)) + } +} + +impl CurrentSensor for Ina4230 { + async fn current(&mut self, channel: Channel) -> Result { + let raw = match channel { + Channel::Ch1 => self.device.current_ch_1().read_async().await?.current(), + Channel::Ch2 => self.device.current_ch_2().read_async().await?.current(), + Channel::Ch3 => self.device.current_ch_3().read_async().await?.current(), + Channel::Ch4 => self.device.current_ch_4().read_async().await?.current(), + }; + Ok(self.current_ma(raw)) + } +} + +impl PowerSensor for Ina4230 { + async fn power(&mut self, channel: Channel) -> Result { + let raw = match channel { + Channel::Ch1 => self.device.power_ch_1().read_async().await?.power(), + Channel::Ch2 => self.device.power_ch_2().read_async().await?.power(), + Channel::Ch3 => self.device.power_ch_3().read_async().await?.power(), + Channel::Ch4 => self.device.power_ch_4().read_async().await?.power(), + }; + Ok(self.power_mw(raw)) + } +} + +impl EnergySensor for Ina4230 { + async fn energy(&mut self, channel: Channel) -> Result { + let raw = match channel { + Channel::Ch1 => self.device.energy_ch_1().read_async().await?.energy(), + Channel::Ch2 => self.device.energy_ch_2().read_async().await?.energy(), + Channel::Ch3 => self.device.energy_ch_3().read_async().await?.energy(), + Channel::Ch4 => self.device.energy_ch_4().read_async().await?.energy(), + }; + Ok(self.energy_mj(raw)) + } +} + +// ── Tests ───────────────────────────────────────────────────────────────────── + +#[cfg(test)] +mod tests { + use embedded_hal_mock::eh1::i2c::{Mock, Transaction}; + + use super::*; + + #[tokio::test] + async fn read_manufacturer_id() { + // ManufacturerId: address 0x7E, 2 bytes BE, resets to 0x5449 (TI in ASCII) + let expectations = vec![Transaction::write_read( + INA4230_ADDR, + vec![0x7E], + vec![0x54, 0x49], + )]; + let i2c = Mock::new(&expectations); + let mut dev = Device::new(DeviceInterface { i2c, address: INA4230_ADDR }); + let id = dev.manufacturer_id().read_async().await.unwrap(); + assert_eq!(id.id(), 0x5449); + dev.interface.i2c.done(); + } + + #[tokio::test] + async fn write_calibration_ch1() { + // calibration_ch_1: address 0x05, 2 bytes BE + // shunt_cal for 100µA/LSB, 10mΩ: 0.00512 / (100e-6 * 0.010) = 5120 + let cal: u16 = 5120; + let [hi, lo] = cal.to_be_bytes(); + let expectations = vec![Transaction::write(INA4230_ADDR, vec![0x05, hi, lo])]; + let i2c = Mock::new(&expectations); + let mut dev = Device::new(DeviceInterface { i2c, address: INA4230_ADDR }); + dev.calibration_ch_1() + .write_async(|w| w.set_shunt_cal(cal)) + .await + .unwrap(); + dev.interface.i2c.done(); + } + + #[tokio::test] + async fn bus_voltage_ch1_trait() { + // bus_voltage_ch_1: address 0x01, 2 bytes BE + // raw = 5000 → 5000 * 1.6 mV = 8000.0 mV + let raw: u16 = 5000; + let [hi, lo] = raw.to_be_bytes(); + let expectations = vec![Transaction::write_read( + INA4230_ADDR, + vec![0x01], + vec![hi, lo], + )]; + let i2c = Mock::new(&expectations); + let mut sensor = Ina4230::new(i2c, INA4230_ADDR); + let mv = sensor.bus_voltage(Channel::Ch1).await.unwrap(); + assert!((mv - 8000.0).abs() < 0.1, "expected 8000.0 mV, got {mv}"); + sensor.device.interface.i2c.done(); + } + + #[tokio::test] + async fn current_ch1_trait() { + // current_ch_1: address 0x02, 2 bytes BE + // raw = 1000, CURRENT_LSB = 100µA/LSB → 1000 * 100e-6 * 1000 = 100.0 mA + let raw: u16 = 1000; + let [hi, lo] = raw.to_be_bytes(); + let expectations = vec![Transaction::write_read( + INA4230_ADDR, + vec![0x02], + vec![hi, lo], + )]; + let i2c = Mock::new(&expectations); + let mut sensor = Ina4230::new(i2c, INA4230_ADDR); + sensor.current_lsb_a = 100e-6; + let ma = sensor.current(Channel::Ch1).await.unwrap(); + assert!((ma - 100.0).abs() < 0.01, "expected 100.0 mA, got {ma}"); + sensor.device.interface.i2c.done(); + } +} From 97a5307d11e5cec63a8842c2e081bbd9a5ff03a0 Mon Sep 17 00:00:00 2001 From: parallels Date: Wed, 22 Apr 2026 23:35:06 -0700 Subject: [PATCH 02/11] Address PR review comments - Fix filename casing: ina4230.toml -> INA4230.toml in workflows and Cargo.toml - Add rust-version = 1.88 to Cargo.toml - Clamp SHUNT_CAL to 15-bit max (0x7FFF) - Per-channel calibration storage ([Option; 4], [AdcRange; 4]) - Write CONFIG2.RANGE in calibrate() for hardware ADC range selection - Return NotCalibrated error when current/power/energy read before calibrate() - Replace INA4230_ADDR constant with A0/A1 enums and i2c_address() function - Add MathOverflow and EnergyOverflow error variants with check_flags() method - Make device field private - Add set_channel_active() method - Update calibrate_all() to take per-channel params [(f32, f32, AdcRange); 4] - Remove src/main.rs template leftover - Update README with new API, error handling, and channel management sections - Expand test suite to 9 tests --- .github/workflows/device-driver.yml | 2 +- Cargo.toml | 3 +- README.md | 76 +++++- src/lib.rs | 396 +++++++++++++++++++++++----- src/main.rs | 18 -- 5 files changed, 396 insertions(+), 99 deletions(-) delete mode 100644 src/main.rs diff --git a/.github/workflows/device-driver.yml b/.github/workflows/device-driver.yml index 0b349bc..153ae5c 100644 --- a/.github/workflows/device-driver.yml +++ b/.github/workflows/device-driver.yml @@ -21,7 +21,7 @@ jobs: uses: baptiste0928/cargo-install@v3 with: crate: device-driver-cli - - name: Generate device.rs from ina4230.toml + - name: Generate device.rs from INA4230.toml run: device-driver-cli --manifest ina4230.toml --device-name Device -o ci_gen.rs - name: Format generated file run: rustfmt --edition 2024 ci_gen.rs diff --git a/Cargo.toml b/Cargo.toml index 1a6cdc7..c844163 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,8 +8,9 @@ readme = "README.md" keywords = ["TI", "power-monitor", "energy", "driver", "embedded-hal-driver"] categories = ["embedded", "hardware-support", "no-std"] documentation = "https://docs.rs/ina4230" -include = ["/**/*.rs", "/Cargo.toml", "/README.md", "/LICENSE", "/ina4230.toml"] +include = ["/**/*.rs", "/Cargo.toml", "/README.md", "/LICENSE", "/INA4230.toml"] edition = "2024" +rust-version = "1.88" [dependencies] device-driver = { version = "1.0.7", default-features = false } diff --git a/README.md b/README.md index e7c4ab0..13431d1 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,10 @@ async sensor traits (`VoltageSensor`, `CurrentSensor`, `PowerSensor`, `EnergySen - Full register coverage via pre-generated `src/device.rs` (generated from `INA4230.toml` using `device-driver-cli`) - Async-first I²C interface (`embedded-hal-async`) - Four independent measurement channels (bus voltage, shunt voltage, current, power, energy) -- Calibration helpers with correct SHUNT_CAL formula -- ADC range selection (±81.92 mV or ±20.48 mV full scale) +- Per-channel calibration with independent shunt resistor, current range, and ADC range +- ADC range selection (±81.92 mV or ±20.48 mV full scale) written to hardware on calibration +- Channel enable/disable support +- INA4230-specific error variants (`NotCalibrated`, `MathOverflow`, `EnergyOverflow`) - Optional `defmt-03` logging support - `no_std` compatible @@ -25,12 +27,13 @@ embedded-hal-async = "1" ``` ```rust,no_run -use ina4230::{AdcRange, Channel, CurrentSensor, Ina4230, INA4230_ADDR, PowerSensor, VoltageSensor}; +use ina4230::{A0, A1, AdcRange, Channel, Ina4230}; // i2c implements embedded_hal_async::i2c::I2c -let mut sensor = Ina4230::new(i2c, INA4230_ADDR); +// A0 and A1 select the I²C address via pin strapping on the device +let mut sensor = Ina4230::new(i2c, A0::Gnd, A1::Gnd); -// Reset, then calibrate before taking measurements +// Reset, then calibrate each channel before taking measurements sensor.reset().await?; sensor.calibrate(Channel::Ch1, CURRENT_LSB_CH1, SHUNT_OHMS_CH1, AdcRange::Range0).await?; @@ -105,7 +108,8 @@ The INA4230 supports two shunt input voltage ranges, configured via `AdcRange`: resolution when measuring small currents through a large shunt resistor. When using `Range1`, the `SHUNT_CAL` register value is automatically divided -by 4 and the shunt voltage LSB is adjusted to 625 nV: +by 4, the shunt voltage LSB is adjusted to 625 nV, and `CONFIG2.RANGE` is +updated in hardware: ``` Range0: SHUNT_CAL = 0.00512 / (CURRENT_LSB × R_SHUNT) @@ -119,18 +123,76 @@ the shunt resistor value used to calculate current from the measured differential voltage, and it sets the resolution of the current and power registers through the `CURRENT_LSB` and `Power_LSB` values. -Call `calibrate()` before taking current, power, or energy measurements: +Call `calibrate()` before taking current, power, or energy measurements. +Each channel is calibrated independently: ```rust,no_run sensor.calibrate(Channel::Ch1, CURRENT_LSB_CH1, SHUNT_OHMS_CH1, AdcRange::Range0).await?; +sensor.calibrate(Channel::Ch2, CURRENT_LSB_CH2, SHUNT_OHMS_CH2, AdcRange::Range0).await?; +sensor.calibrate(Channel::Ch3, CURRENT_LSB_CH3, SHUNT_OHMS_CH3, AdcRange::Range1).await?; +sensor.calibrate(Channel::Ch4, CURRENT_LSB_CH4, SHUNT_OHMS_CH4, AdcRange::Range0).await?; +``` + +Or use `calibrate_all()` to configure all four channels in one call: + +```rust,no_run +sensor.calibrate_all([ + (CURRENT_LSB_CH1, SHUNT_OHMS_CH1, AdcRange::Range0), + (CURRENT_LSB_CH2, SHUNT_OHMS_CH2, AdcRange::Range0), + (CURRENT_LSB_CH3, SHUNT_OHMS_CH3, AdcRange::Range1), + (CURRENT_LSB_CH4, SHUNT_OHMS_CH4, AdcRange::Range0), +]).await?; ``` The calibration register must be programmed after initial power up, power cycle events, or device enable to receive valid current, power, and energy results. Bus voltage and shunt voltage readings do not require calibration. +### Channel Management + +All four channels are active by default after power up. Unused channels can +be disabled to reduce conversion time: + +```rust,no_run +sensor.set_channel_active(Channel::Ch3, false).await?; +sensor.set_channel_active(Channel::Ch4, false).await?; +``` + +## Error Handling + +The driver returns `Ina4230Error` which covers both I²C bus errors and +device-level conditions: + +```rust,no_run +match sensor.current(Channel::Ch1).await { + Ok(ma) => info!("Current: {} mA", ma), + Err(Ina4230Error::NotCalibrated) => error!("Call calibrate() first"), + Err(Ina4230Error::MathOverflow) => error!("Current exceeds full-scale range"), + Err(Ina4230Error::EnergyOverflow(ch)) => error!("Energy overflow on {:?}", ch), + Err(Ina4230Error::Bus(e)) => error!("I²C error: {:?}", e), +} +``` + +Use `check_flags()` to explicitly poll for overflow conditions: + +```rust,no_run +if let Err(e) = sensor.check_flags().await { + warn!("INA4230 flag: {:?}", e); +} +``` + ## I²C Addresses +The I²C address is selected by the A0 and A1 pin strapping on the device. +Pass `A0` and `A1` values to `Ina4230::new()`: + +```rust,no_run +let sensor = Ina4230::new(i2c, A0::Gnd, A1::Gnd); // address 0x40 +let sensor = Ina4230::new(i2c, A0::Vs, A1::Gnd); // address 0x41 +let sensor = Ina4230::new(i2c, A0::Gnd, A1::Vs); // address 0x44 +let sensor = Ina4230::new(i2c, A0::Vs, A1::Vs); // address 0x45 +``` + | A1 | A0 | Address | |-----|-----|---------| | GND | GND | `0x40` | diff --git a/src/lib.rs b/src/lib.rs index 580cc67..8868812 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,11 +22,6 @@ mod device; pub use crate::device::*; -// ── I²C address ─────────────────────────────────────────────────────────────── - -/// Default 7-bit I²C address for the INA4230 (A0=GND, A1=GND → 0x40). -pub const INA4230_ADDR: u8 = 0x40; - /// Maximum register data size in bytes (energy registers are 32-bit = 4 bytes). const LARGEST_REG_SIZE_BYTES: usize = 4; @@ -38,12 +33,23 @@ const LARGEST_REG_SIZE_BYTES: usize = 4; pub enum Ina4230Error { /// An error occurred on the I²C bus. Bus(I2cError), + /// A measurement was requested before calibration was configured. + NotCalibrated, + /// Math overflow — current and power data may be invalid. + /// Occurs when the current exceeds the configured full-scale range. + MathOverflow, + /// Energy register overflow on the specified channel. + /// Occurs when the accumulated energy exceeds the 40-bit register maximum. + EnergyOverflow(Channel), } impl sensor::Error for Ina4230Error { fn kind(&self) -> sensor::ErrorKind { match self { Self::Bus(_) => sensor::ErrorKind::Peripheral, + Self::NotCalibrated => sensor::ErrorKind::NotReady, + Self::MathOverflow => sensor::ErrorKind::Saturated, + Self::EnergyOverflow(_) => sensor::ErrorKind::Saturated, } } } @@ -54,13 +60,11 @@ impl sensor::Error for Ina4230Error { pub struct DeviceInterface { /// The underlying async I²C bus. pub i2c: I2c, - /// 7-bit I²C address of this device instance (see [`INA4230_ADDR`]). + /// 7-bit I²C address of this device instance. pub address: u8, } -impl device_driver::AsyncRegisterInterface - for DeviceInterface -{ +impl device_driver::AsyncRegisterInterface for DeviceInterface { type Error = Ina4230Error; type AddressType = u8; @@ -93,27 +97,65 @@ impl device_driver::AsyncRegisterInterface } } +// ── Address pins ────────────────────────────────────────────────────────────── + +/// A0 pin logic level for I²C address selection. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +pub enum A0 { + /// A0 tied to GND (default). + #[default] + Gnd, + /// A0 tied to VS. + Vs, +} + +/// A1 pin logic level for I²C address selection. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +pub enum A1 { + /// A1 tied to GND (default). + #[default] + Gnd, + /// A1 tied to VS. + Vs, +} + +/// Compute the 7-bit I²C address from A0 and A1 pin strapping. +pub fn i2c_address(a0: A0, a1: A1) -> u8 { + match (a0, a1) { + (A0::Gnd, A1::Gnd) => 0x40, + (A0::Vs, A1::Gnd) => 0x41, + (A0::Gnd, A1::Vs) => 0x44, + (A0::Vs, A1::Vs) => 0x45, + } +} + // ── Channel ─────────────────────────────────────────────────────────────────── /// One of the four measurement channels on the INA4230. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +#[repr(usize)] pub enum Channel { /// Channel 1 - Ch1, + Ch1 = 0, /// Channel 2 - Ch2, + Ch2 = 1, /// Channel 3 - Ch3, + Ch3 = 2, /// Channel 4 - Ch4, + Ch4 = 3, } +// ── ADC Range ───────────────────────────────────────────────────────────────── + /// ADC full-scale input range for shunt voltage measurement. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub enum AdcRange { /// ±81.92 mV full scale, LSB = 2.5 µV (default) + #[default] Range0, /// ±20.48 mV full scale, LSB = 625 nV. SHUNT_CAL divided by 4. Range1, @@ -136,7 +178,7 @@ pub type MilliJoules = f32; pub trait VoltageSensor: sensor::ErrorType { /// Read the bus voltage for the given channel, in millivolts (LSB = 1.6 mV). async fn bus_voltage(&mut self, channel: Channel) -> Result; - /// Read the shunt voltage for the given channel, in millivolts (LSB = 2.5 µV). + /// Read the shunt voltage for the given channel, in millivolts. async fn shunt_voltage(&mut self, channel: Channel) -> Result; } @@ -193,22 +235,25 @@ impl EnergySensor for &mut T { /// High-level driver for the INA4230 quad-channel power and energy monitor. pub struct Ina4230 { /// The generated low-level register accessor. - pub device: Device>, - /// Stored CURRENT_LSB in A/LSB, set by `calibrate*`. Used for unit conversion. - current_lsb_a: f32, - /// ADC input range, set during calibration. Used for shunt voltage LSB selection. - adc_range: AdcRange, + device: Device>, + /// CURRENT_LSB per channel in A/LSB. None means not yet calibrated. + current_lsb_a: [Option; 4], + /// ADC input range per channel. + adc_range: [AdcRange; 4], } impl Ina4230 { /// Create a new driver instance. /// - /// Pass [`INA4230_ADDR`] for the default address (A0=GND, A1=GND → 0x40). - pub fn new(i2c: I2c, address: u8) -> Self { + /// `a0` and `a1` select the I²C address via the pin strapping on the device. + pub fn new(i2c: I2c, a0: A0, a1: A1) -> Self { Self { - device: Device::new(DeviceInterface { i2c, address }), - current_lsb_a: 0.0, - adc_range: AdcRange::Range0, + device: Device::new(DeviceInterface { + i2c, + address: i2c_address(a0, a1), + }), + current_lsb_a: [None; 4], + adc_range: [AdcRange::Range0; 4], } } @@ -231,7 +276,7 @@ impl Ina4230 { } /// Poll the Conversion Ready Flag (`FLAGS.CVRF`). Returns `true` when all - /// enabled channels have completed conversion and averaging. Reading FLAGS clears CVRF. + /// enabled channels have completed conversion and averaging. pub async fn conversion_ready(&mut self) -> Result> { Ok(self.device.flags().read_async().await?.cvrf()) } @@ -241,6 +286,46 @@ impl Ina4230 { self.device.flags().read_async().await } + /// Enable or disable a channel in `CONFIG1.ACTIVE_CHANNEL`. ← add here + pub async fn set_channel_active(&mut self, channel: Channel, active: bool) -> Result<(), Ina4230Error> { + let bit = 1u8 << (channel as usize); + self.device + .config_1() + .modify_async(|w| { + let mut active_channels = w.active_channel(); + if active { + active_channels |= bit; // set bit to enable channel + } else { + active_channels &= !bit; // clear bit to disable channel + } + w.set_active_channel(active_channels); + }) + .await + } + /// Check the FLAGS register for overflow conditions. + /// + /// Returns [`Ina4230Error::MathOverflow`] if current or power data may be + /// invalid, or [`Ina4230Error::EnergyOverflow`] if the energy accumulator + /// has overflowed on any channel. Reading FLAGS clears all flags. + pub async fn check_flags(&mut self) -> Result<(), Ina4230Error> { + let flags = self.device.flags().read_async().await?; + if flags.ovf() { + return Err(Ina4230Error::MathOverflow); + } + if flags.energyof_ch1() { + return Err(Ina4230Error::EnergyOverflow(Channel::Ch1)); + } + if flags.energyof_ch2() { + return Err(Ina4230Error::EnergyOverflow(Channel::Ch2)); + } + if flags.energyof_ch3() { + return Err(Ina4230Error::EnergyOverflow(Channel::Ch3)); + } + if flags.energyof_ch4() { + return Err(Ina4230Error::EnergyOverflow(Channel::Ch4)); + } + Ok(()) + } // ── Calibration ─────────────────────────────────────────────────────── /// Write the calibration register for a single channel. @@ -258,34 +343,65 @@ impl Ina4230 { shunt_ohms: f32, adc_range: AdcRange, ) -> Result<(), Ina4230Error> { - self.current_lsb_a = current_lsb_a; - self.adc_range = adc_range; + let idx = channel as usize; + self.current_lsb_a[idx] = Some(current_lsb_a); + self.adc_range[idx] = adc_range; + + // Update CONFIG2.RANGE bit for this channel + // Bit0=CH1, Bit1=CH2, Bit2=CH3, Bit3=CH4 + let bit = 1u8 << idx; + self.device + .config_2() + .modify_async(|w| { + let mut range = w.range(); + match adc_range { + AdcRange::Range0 => range &= !bit, // clear bit → ±81.92 mV + AdcRange::Range1 => range |= bit, // set bit → ±20.48 mV + } + w.set_range(range); + }) + .await?; + + // Write the calibration register let cal = Self::shunt_cal_value(current_lsb_a, shunt_ohms, adc_range); match channel { Channel::Ch1 => { - self.device.calibration_ch_1().write_async(|w| w.set_shunt_cal(cal)).await + self.device + .calibration_ch_1() + .write_async(|w| w.set_shunt_cal(cal)) + .await } Channel::Ch2 => { - self.device.calibration_ch_2().write_async(|w| w.set_shunt_cal(cal)).await + self.device + .calibration_ch_2() + .write_async(|w| w.set_shunt_cal(cal)) + .await } Channel::Ch3 => { - self.device.calibration_ch_3().write_async(|w| w.set_shunt_cal(cal)).await + self.device + .calibration_ch_3() + .write_async(|w| w.set_shunt_cal(cal)) + .await } Channel::Ch4 => { - self.device.calibration_ch_4().write_async(|w| w.set_shunt_cal(cal)).await + self.device + .calibration_ch_4() + .write_async(|w| w.set_shunt_cal(cal)) + .await } } } - /// Write the calibration register for all four channels with identical parameters. - pub async fn calibrate_all( - &mut self, - current_lsb_a: f32, - shunt_ohms: f32, - adc_range: AdcRange, - ) -> Result<(), Ina4230Error> { - for ch in [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] { - self.calibrate(ch, current_lsb_a, shunt_ohms, adc_range).await?; + /// Write the calibration register for all four channels. + /// + /// Each channel can have independent parameters. `params` is ordered + /// `[Ch1, Ch2, Ch3, Ch4]` as `(current_lsb_a, shunt_ohms, adc_range)`. + pub async fn calibrate_all(&mut self, params: [(f32, f32, AdcRange); 4]) -> Result<(), Ina4230Error> { + for (ch, (current_lsb_a, shunt_ohms, adc_range)) in [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] + .iter() + .zip(params.iter()) + { + self.calibrate(*ch, *current_lsb_a, *shunt_ohms, *adc_range).await?; } Ok(()) } @@ -294,13 +410,14 @@ impl Ina4230 { #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] fn shunt_cal_value(current_lsb_a: f32, shunt_ohms: f32, adc_range: AdcRange) -> u16 { + const SHUNT_CAL_MAX: u32 = 0x7FFF; // INA4230 datasheet §8.1.2: SHUNT_CAL = 0.00512 / (CURRENT_LSB × R_SHUNT) let val = 0.00512_f32 / (current_lsb_a * shunt_ohms); let val = match adc_range { AdcRange::Range0 => val, AdcRange::Range1 => val / 4.0, }; - (val as u32).min(u32::from(u16::MAX)) as u16 + (val as u32).min(SHUNT_CAL_MAX) as u16 } fn bus_mv(raw: u16) -> MilliVolts { @@ -308,27 +425,30 @@ impl Ina4230 { } #[allow(clippy::cast_possible_wrap)] - fn shunt_mv(&self, raw: u16) -> MilliVolts { + fn shunt_mv(&self, channel: Channel, raw: u16) -> MilliVolts { let signed = raw as i16; - let lsb_mv = match self.adc_range { - AdcRange::Range0 => 0.0025, // 2.5 µV - AdcRange::Range1 => 0.000625, // 625 nV + let lsb_mv = match self.adc_range[channel as usize] { + AdcRange::Range0 => 0.0025, // 2.5 µV + AdcRange::Range1 => 0.000625, // 625 nV }; f32::from(signed) * lsb_mv } #[allow(clippy::cast_possible_wrap)] - fn current_ma(&self, raw: u16) -> MilliAmps { + fn current_ma(&self, channel: Channel, raw: u16) -> Result> { + let lsb = self.current_lsb_a[channel as usize].ok_or(Ina4230Error::NotCalibrated)?; let signed = raw as i16; - f32::from(signed) * self.current_lsb_a * 1000.0 + Ok(f32::from(signed) * lsb * 1000.0) } - fn power_mw(&self, raw: u16) -> MilliWatts { - f32::from(raw) * 32.0 * self.current_lsb_a * 1000.0 + fn power_mw(&self, channel: Channel, raw: u16) -> Result> { + let lsb = self.current_lsb_a[channel as usize].ok_or(Ina4230Error::NotCalibrated)?; + Ok(f32::from(raw) * 32.0 * lsb * 1000.0) } - fn energy_mj(&self, raw: u32) -> MilliJoules { - raw as f32 * 32.0 * self.current_lsb_a * 1000.0 + fn energy_mj(&self, channel: Channel, raw: u32) -> Result> { + let lsb = self.current_lsb_a[channel as usize].ok_or(Ina4230Error::NotCalibrated)?; + Ok(raw as f32 * 32.0 * lsb * 1000.0) } } @@ -356,7 +476,7 @@ impl VoltageSensor for Ina4230 { Channel::Ch3 => self.device.shunt_voltage_ch_3().read_async().await?.vshunt(), Channel::Ch4 => self.device.shunt_voltage_ch_4().read_async().await?.vshunt(), }; - Ok(self.shunt_mv(raw)) + Ok(self.shunt_mv(channel, raw)) } } @@ -368,7 +488,7 @@ impl CurrentSensor for Ina4230 { Channel::Ch3 => self.device.current_ch_3().read_async().await?.current(), Channel::Ch4 => self.device.current_ch_4().read_async().await?.current(), }; - Ok(self.current_ma(raw)) + self.current_ma(channel, raw) } } @@ -380,7 +500,7 @@ impl PowerSensor for Ina4230 { Channel::Ch3 => self.device.power_ch_3().read_async().await?.power(), Channel::Ch4 => self.device.power_ch_4().read_async().await?.power(), }; - Ok(self.power_mw(raw)) + self.power_mw(channel, raw) } } @@ -392,7 +512,7 @@ impl EnergySensor for Ina4230 { Channel::Ch3 => self.device.energy_ch_3().read_async().await?.energy(), Channel::Ch4 => self.device.energy_ch_4().read_async().await?.energy(), }; - Ok(self.energy_mj(raw)) + self.energy_mj(channel, raw) } } @@ -406,14 +526,17 @@ mod tests { #[tokio::test] async fn read_manufacturer_id() { - // ManufacturerId: address 0x7E, 2 bytes BE, resets to 0x5449 (TI in ASCII) + // ManufacturerId: address 0x7E, 2 bytes BE, resets to 0x5449 ("TI" in ASCII) let expectations = vec![Transaction::write_read( - INA4230_ADDR, + i2c_address(A0::Gnd, A1::Gnd), vec![0x7E], vec![0x54, 0x49], )]; let i2c = Mock::new(&expectations); - let mut dev = Device::new(DeviceInterface { i2c, address: INA4230_ADDR }); + let mut dev = Device::new(DeviceInterface { + i2c, + address: i2c_address(A0::Gnd, A1::Gnd), + }); let id = dev.manufacturer_id().read_async().await.unwrap(); assert_eq!(id.id(), 0x5449); dev.interface.i2c.done(); @@ -425,9 +548,12 @@ mod tests { // shunt_cal for 100µA/LSB, 10mΩ: 0.00512 / (100e-6 * 0.010) = 5120 let cal: u16 = 5120; let [hi, lo] = cal.to_be_bytes(); - let expectations = vec![Transaction::write(INA4230_ADDR, vec![0x05, hi, lo])]; + let expectations = vec![Transaction::write(i2c_address(A0::Gnd, A1::Gnd), vec![0x05, hi, lo])]; let i2c = Mock::new(&expectations); - let mut dev = Device::new(DeviceInterface { i2c, address: INA4230_ADDR }); + let mut dev = Device::new(DeviceInterface { + i2c, + address: i2c_address(A0::Gnd, A1::Gnd), + }); dev.calibration_ch_1() .write_async(|w| w.set_shunt_cal(cal)) .await @@ -442,33 +568,159 @@ mod tests { let raw: u16 = 5000; let [hi, lo] = raw.to_be_bytes(); let expectations = vec![Transaction::write_read( - INA4230_ADDR, + i2c_address(A0::Gnd, A1::Gnd), vec![0x01], vec![hi, lo], )]; let i2c = Mock::new(&expectations); - let mut sensor = Ina4230::new(i2c, INA4230_ADDR); + let mut sensor = Ina4230::new(i2c, A0::Gnd, A1::Gnd); let mv = sensor.bus_voltage(Channel::Ch1).await.unwrap(); assert!((mv - 8000.0).abs() < 0.1, "expected 8000.0 mV, got {mv}"); - sensor.device.interface.i2c.done(); + sensor.release().done(); } #[tokio::test] async fn current_ch1_trait() { - // current_ch_1: address 0x02, 2 bytes BE - // raw = 1000, CURRENT_LSB = 100µA/LSB → 1000 * 100e-6 * 1000 = 100.0 mA + let cal: u16 = 5120; + let [cal_hi, cal_lo] = cal.to_be_bytes(); + let raw: u16 = 1000; + let [hi, lo] = raw.to_be_bytes(); + let addr = i2c_address(A0::Gnd, A1::Gnd); + let expectations = vec![ + // calibrate: read CONFIG2 + Transaction::write_read(addr, vec![0x21], vec![0x00, 0x00]), + // calibrate: write CONFIG2 with range bit cleared + Transaction::write(addr, vec![0x21, 0x00, 0x00]), + // calibrate: write calibration_ch_1 (0x05) + Transaction::write(addr, vec![0x05, cal_hi, cal_lo]), + // current read (0x02) + Transaction::write_read(addr, vec![0x02], vec![hi, lo]), + ]; + let i2c = Mock::new(&expectations); + let mut sensor = Ina4230::new(i2c, A0::Gnd, A1::Gnd); + sensor + .calibrate(Channel::Ch1, 100e-6, 0.010, AdcRange::Range0) + .await + .unwrap(); + let ma = sensor.current(Channel::Ch1).await.unwrap(); + assert!((ma - 100.0).abs() < 0.01, "expected 100.0 mA, got {ma}"); + sensor.release().done(); + } + #[tokio::test] + async fn current_returns_error_when_not_calibrated() { + // Attempting to read current before calibrate() should return NotCalibrated let raw: u16 = 1000; let [hi, lo] = raw.to_be_bytes(); let expectations = vec![Transaction::write_read( - INA4230_ADDR, + i2c_address(A0::Gnd, A1::Gnd), vec![0x02], vec![hi, lo], )]; let i2c = Mock::new(&expectations); - let mut sensor = Ina4230::new(i2c, INA4230_ADDR); - sensor.current_lsb_a = 100e-6; - let ma = sensor.current(Channel::Ch1).await.unwrap(); - assert!((ma - 100.0).abs() < 0.01, "expected 100.0 mA, got {ma}"); - sensor.device.interface.i2c.done(); + let mut sensor = Ina4230::new(i2c, A0::Gnd, A1::Gnd); + let result = sensor.current(Channel::Ch1).await; + assert!(matches!(result, Err(Ina4230Error::NotCalibrated))); + sensor.release().done(); + } + + #[tokio::test] + async fn calibrate_stores_per_channel() { + let cal: u16 = 5120; + let [cal_hi, cal_lo] = cal.to_be_bytes(); + let raw: u16 = 1000; + let [hi, lo] = raw.to_be_bytes(); + let addr = i2c_address(A0::Gnd, A1::Gnd); + let expectations = vec![ + // calibrate CH1: read CONFIG2 + Transaction::write_read(addr, vec![0x21], vec![0x00, 0x00]), + // calibrate CH1: write CONFIG2 + Transaction::write(addr, vec![0x21, 0x00, 0x00]), + // calibrate CH1: write calibration_ch_1 (0x05) + Transaction::write(addr, vec![0x05, cal_hi, cal_lo]), + // current CH2 read (0x0A) + Transaction::write_read(addr, vec![0x0A], vec![hi, lo]), + ]; + let i2c = Mock::new(&expectations); + let mut sensor = Ina4230::new(i2c, A0::Gnd, A1::Gnd); + sensor + .calibrate(Channel::Ch1, 100e-6, 0.010, AdcRange::Range0) + .await + .unwrap(); + let result = sensor.current(Channel::Ch2).await; + assert!(matches!(result, Err(Ina4230Error::NotCalibrated))); + sensor.release().done(); + } + + #[tokio::test] + async fn bus_voltage_all_channels() { + // Verify correct register addresses for all four bus voltage channels: + // CH1=0x01, CH2=0x09, CH3=0x11, CH4=0x19 + let raw: u16 = 2000; // 2000 * 1.6 mV = 3200.0 mV + let [hi, lo] = raw.to_be_bytes(); + let expectations = vec![ + Transaction::write_read(i2c_address(A0::Gnd, A1::Gnd), vec![0x01], vec![hi, lo]), + Transaction::write_read(i2c_address(A0::Gnd, A1::Gnd), vec![0x09], vec![hi, lo]), + Transaction::write_read(i2c_address(A0::Gnd, A1::Gnd), vec![0x11], vec![hi, lo]), + Transaction::write_read(i2c_address(A0::Gnd, A1::Gnd), vec![0x19], vec![hi, lo]), + ]; + let i2c = Mock::new(&expectations); + let mut sensor = Ina4230::new(i2c, A0::Gnd, A1::Gnd); + for ch in [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] { + let mv = sensor.bus_voltage(ch).await.unwrap(); + assert!((mv - 3200.0).abs() < 0.1, "expected 3200.0 mV, got {mv}"); + } + sensor.release().done(); + } + + #[tokio::test] + async fn calibrate_all_independent_channels() { + let ch1_cal: u16 = 5120; + let ch2_cal: u16 = 1280; + let ch3_cal: u16 = 20480; + let ch4_cal: u16 = 5120; + let [h1, l1] = ch1_cal.to_be_bytes(); + let [h2, l2] = ch2_cal.to_be_bytes(); + let [h3, l3] = ch3_cal.to_be_bytes(); + let [h4, l4] = ch4_cal.to_be_bytes(); + let addr = i2c_address(A0::Gnd, A1::Gnd); + let expectations = vec![ + // calibrate CH1: read/write CONFIG2, write cal reg + Transaction::write_read(addr, vec![0x21], vec![0x00, 0x00]), + Transaction::write(addr, vec![0x21, 0x00, 0x00]), + Transaction::write(addr, vec![0x05, h1, l1]), + // calibrate CH2: read/write CONFIG2, write cal reg + Transaction::write_read(addr, vec![0x21], vec![0x00, 0x00]), + Transaction::write(addr, vec![0x21, 0x00, 0x00]), + Transaction::write(addr, vec![0x0D, h2, l2]), + // calibrate CH3: read/write CONFIG2, write cal reg + Transaction::write_read(addr, vec![0x21], vec![0x00, 0x00]), + Transaction::write(addr, vec![0x21, 0x00, 0x00]), + Transaction::write(addr, vec![0x15, h3, l3]), + // calibrate CH4: read/write CONFIG2, write cal reg + Transaction::write_read(addr, vec![0x21], vec![0x00, 0x00]), + Transaction::write(addr, vec![0x21, 0x00, 0x00]), + Transaction::write(addr, vec![0x1D, h4, l4]), + ]; + let i2c = Mock::new(&expectations); + let mut sensor = Ina4230::new(i2c, A0::Gnd, A1::Gnd); + sensor + .calibrate_all([ + (100e-6, 0.010, AdcRange::Range0), + (200e-6, 0.020, AdcRange::Range0), + (50e-6, 0.005, AdcRange::Range0), + (100e-6, 0.010, AdcRange::Range0), + ]) + .await + .unwrap(); + sensor.release().done(); + } + + #[tokio::test] + async fn i2c_address_all_combinations() { + // Verify all four address pin combinations produce correct I²C addresses + assert_eq!(i2c_address(A0::Gnd, A1::Gnd), 0x40); + assert_eq!(i2c_address(A0::Vs, A1::Gnd), 0x41); + assert_eq!(i2c_address(A0::Gnd, A1::Vs), 0x44); + assert_eq!(i2c_address(A0::Vs, A1::Vs), 0x45); } } diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 7111536..0000000 --- a/src/main.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![cfg_attr(target_os = "none", no_std)] -#![cfg_attr(target_os = "none", no_main)] - -#[cfg(target_os = "none")] -mod baremetal; - -#[cfg(not(target_os = "none"))] -fn main() { - println!("Hello, world!"); -} - -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} From 0054da1beea5cb01905cc9e83a0203a2ab1035cc Mon Sep 17 00:00:00 2001 From: Steve Wilson Date: Thu, 23 Apr 2026 07:51:21 -0700 Subject: [PATCH 03/11] Update src/lib.rs Co-authored-by: Felipe Balbi --- src/lib.rs | 53 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8868812..b55e810 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -99,35 +99,46 @@ impl device_driver::AsyncRegisterInterface fo // ── Address pins ────────────────────────────────────────────────────────────── -/// A0 pin logic level for I²C address selection. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] -pub enum A0 { - /// A0 tied to GND (default). +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum AddrPinState { + /// Address pin tied to GND (default). #[default] Gnd, - /// A0 tied to VS. + /// Address pin tied to VS. Vs, + /// Address pin tied to SDA. + Sda, + /// Address pin tied to SCL. + Scl, } -/// A1 pin logic level for I²C address selection. -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] -pub enum A1 { - /// A1 tied to GND (default). - #[default] - Gnd, - /// A1 tied to VS. - Vs, +/// Trait for converting an (A0, A1) pair of address pin states into +/// the corresponding I2C address. +trait ToAddress { + fn to_address(self) -> u8; } -/// Compute the 7-bit I²C address from A0 and A1 pin strapping. -pub fn i2c_address(a0: A0, a1: A1) -> u8 { - match (a0, a1) { - (A0::Gnd, A1::Gnd) => 0x40, - (A0::Vs, A1::Gnd) => 0x41, - (A0::Gnd, A1::Vs) => 0x44, - (A0::Vs, A1::Vs) => 0x45, +impl ToAddress for (AddrPinState, AddrPinState) { + fn to_address(self) -> u8 { + match self { + (AddrPinState::Gnd, AddrPinState::Gnd) => 0b100_0000, + (AddrPinState::Gnd, AddrPinState::Vs) => 0b100_0001, + (AddrPinState::Gnd, AddrPinState::Sda) => 0b100_0010, + (AddrPinState::Gnd, AddrPinState::Scl) => 0b100_0011, + (AddrPinState::Vs, AddrPinState::Gnd) => 0b100_0100, + (AddrPinState::Vs, AddrPinState::Vs) => 0b100_0101, + (AddrPinState::Vs, AddrPinState::Sda) => 0b100_0110, + (AddrPinState::Vs, AddrPinState::Scl) => 0b100_0111, + (AddrPinState::Sda, AddrPinState::Gnd) => 0b100_1000, + (AddrPinState::Sda, AddrPinState::Vs) => 0b100_1001, + (AddrPinState::Sda, AddrPinState::Sda) => 0b100_1010, + (AddrPinState::Sda, AddrPinState::Scl) => 0b100_1011, + (AddrPinState::Scl, AddrPinState::Gnd) => 0b100_1100, + (AddrPinState::Scl, AddrPinState::Vs) => 0b100_1101, + (AddrPinState::Scl, AddrPinState::Sda) => 0b100_1110, + (AddrPinState::Scl, AddrPinState::Scl) => 0b100_1111, + } } } From 207bc13971b237854015d8d5ca0eeb5b1ab9d78b Mon Sep 17 00:00:00 2001 From: Steve Wilson Date: Thu, 23 Apr 2026 07:54:37 -0700 Subject: [PATCH 04/11] Update src/lib.rs Co-authored-by: Felipe Balbi --- src/lib.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index b55e810..c0140de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -159,6 +159,17 @@ pub enum Channel { Ch4 = 3, } +impl Channel { + fn to_bit(self) -> u8 { + match self { + Channel::Ch0 => 0b0001, + Channel::Ch1 => 0b0010, + Channel::Ch2 => 0b0100, + Channel::Ch3 => 0b1000, + } + } +} + // ── ADC Range ───────────────────────────────────────────────────────────────── /// ADC full-scale input range for shunt voltage measurement. From 7e8bbc97a45ac5a60c1a0d9878777f4219f56d08 Mon Sep 17 00:00:00 2001 From: Steve Wilson Date: Thu, 23 Apr 2026 07:56:11 -0700 Subject: [PATCH 05/11] Update src/lib.rs Co-authored-by: Felipe Balbi --- src/lib.rs | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c0140de..07d426c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -329,25 +329,22 @@ impl Ina4230 { /// Returns [`Ina4230Error::MathOverflow`] if current or power data may be /// invalid, or [`Ina4230Error::EnergyOverflow`] if the energy accumulator /// has overflowed on any channel. Reading FLAGS clears all flags. - pub async fn check_flags(&mut self) -> Result<(), Ina4230Error> { - let flags = self.device.flags().read_async().await?; - if flags.ovf() { - return Err(Ina4230Error::MathOverflow); - } - if flags.energyof_ch1() { - return Err(Ina4230Error::EnergyOverflow(Channel::Ch1)); - } - if flags.energyof_ch2() { - return Err(Ina4230Error::EnergyOverflow(Channel::Ch2)); - } - if flags.energyof_ch3() { - return Err(Ina4230Error::EnergyOverflow(Channel::Ch3)); - } - if flags.energyof_ch4() { - return Err(Ina4230Error::EnergyOverflow(Channel::Ch4)); - } +pub async fn check_flags(&mut self) -> Result<(), Ina4230Error> { + let flags = self.device.flags().read_async().await?; + if flags.ovf() { + Err(Ina4230Error::MathOverflow) + } else if flags.energyof_ch1() { + Err(Ina4230Error::EnergyOverflow(Channel::Ch1)); + } else if flags.energyof_ch2() { + Err(Ina4230Error::EnergyOverflow(Channel::Ch2)); + } else if flags.energyof_ch3() { + Err(Ina4230Error::EnergyOverflow(Channel::Ch3)); + } else if flags.energyof_ch4() { + Err(Ina4230Error::EnergyOverflow(Channel::Ch4)); + } else { Ok(()) } +} // ── Calibration ─────────────────────────────────────────────────────── /// Write the calibration register for a single channel. From dae7cd24acb0978371e76fd934da56e5234884cb Mon Sep 17 00:00:00 2001 From: Steve Wilson Date: Thu, 23 Apr 2026 07:57:01 -0700 Subject: [PATCH 06/11] Update src/lib.rs Co-authored-by: Felipe Balbi --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 07d426c..63abd8d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -310,7 +310,7 @@ impl Ina4230 { /// Enable or disable a channel in `CONFIG1.ACTIVE_CHANNEL`. ← add here pub async fn set_channel_active(&mut self, channel: Channel, active: bool) -> Result<(), Ina4230Error> { - let bit = 1u8 << (channel as usize); + let bit = channel.to_bit(); self.device .config_1() .modify_async(|w| { From 79088c257ca0a1788022a190d480bd57b6e9b7e6 Mon Sep 17 00:00:00 2001 From: parallels Date: Thu, 23 Apr 2026 10:01:01 -0700 Subject: [PATCH 07/11] Update defmt feature, address pins, and address combinations - Rename defmt-03 feature to defmt, update to defmt 1.0 - Update INA4230.toml defmt_feature to defmt - Regenerate src/device.rs with updated defmt feature name - Add Sda and Scl variants to A0 and A1 enums - Replace i2c_address() free function with ToAddress trait - Update ToAddress impl to cover all 16 address combinations - Update i2c_address_all_combinations test to verify all 16 addresses --- Cargo.lock | 2 +- Cargo.toml | 4 +- INA4230.toml | 2 +- src/device.rs | 1377 ++++++++++++------------------------------------- src/lib.rs | 164 +++--- 5 files changed, 423 insertions(+), 1126 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 49712db..3a2a86a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -168,7 +168,7 @@ dependencies = [ name = "ina4230" version = "0.1.0" dependencies = [ - "defmt 0.3.100", + "defmt 1.0.1", "device-driver", "embedded-hal-async", "embedded-hal-mock", diff --git a/Cargo.toml b/Cargo.toml index c844163..858b764 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ rust-version = "1.88" [dependencies] device-driver = { version = "1.0.7", default-features = false } -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0", optional = true } embedded-hal-async = "1.0.0" embedded-sensors-hal-async = "0.4.0" @@ -37,7 +37,7 @@ style = "forbid" pedantic = "deny" [features] -defmt-03 = [ +defmt = [ "dep:defmt", "device-driver/defmt-03", "embedded-sensors-hal-async/defmt", diff --git a/INA4230.toml b/INA4230.toml index 5d2afaf..592c962 100644 --- a/INA4230.toml +++ b/INA4230.toml @@ -2,7 +2,7 @@ register_address_type = "u8" default_byte_order = "BE" name_word_boundaries = ["Hyphen"] -defmt_feature = "defmt-03" +defmt_feature = "defmt" # ============================================================ # CONFIG1 Register (Address = 0x20, Reset = 0xF127) # ============================================================ diff --git a/src/device.rs b/src/device.rs index a9fbe60..655ac21 100644 --- a/src/device.rs +++ b/src/device.rs @@ -212,49 +212,31 @@ impl Device { /// Configuration register 1 pub fn config_1( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::Config1, ::device_driver::RW> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::Config1, ::device_driver::RW> { let address = self.base_address + 32; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::Config1, - ::device_driver::RW, - >::new(self.interface(), address as u8, field_sets::Config1::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::Config1, ::device_driver::RW>::new( + self.interface(), + address as u8, + field_sets::Config1::new, + ) } /// Configuration register 2 pub fn config_2( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::Config2, ::device_driver::RW> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::Config2, ::device_driver::RW> { let address = self.base_address + 33; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::Config2, - ::device_driver::RW, - >::new(self.interface(), address as u8, field_sets::Config2::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::Config2, ::device_driver::RW>::new( + self.interface(), + address as u8, + field_sets::Config2::new, + ) } /// Calibration register channel 1 pub fn calibration_ch_1( &mut self, - ) -> ::device_driver::RegisterOperation< - '_, - I, - u8, - field_sets::CalibrationCh1, - ::device_driver::RW, - > { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::CalibrationCh1, ::device_driver::RW> { let address = self.base_address + 5; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::CalibrationCh1, - ::device_driver::RW, - >::new( + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::CalibrationCh1, ::device_driver::RW>::new( self.interface(), address as u8, field_sets::CalibrationCh1::new, @@ -263,21 +245,9 @@ impl Device { /// Calibration register channel 2 pub fn calibration_ch_2( &mut self, - ) -> ::device_driver::RegisterOperation< - '_, - I, - u8, - field_sets::CalibrationCh2, - ::device_driver::RW, - > { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::CalibrationCh2, ::device_driver::RW> { let address = self.base_address + 13; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::CalibrationCh2, - ::device_driver::RW, - >::new( + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::CalibrationCh2, ::device_driver::RW>::new( self.interface(), address as u8, field_sets::CalibrationCh2::new, @@ -286,21 +256,9 @@ impl Device { /// Calibration register channel 3 pub fn calibration_ch_3( &mut self, - ) -> ::device_driver::RegisterOperation< - '_, - I, - u8, - field_sets::CalibrationCh3, - ::device_driver::RW, - > { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::CalibrationCh3, ::device_driver::RW> { let address = self.base_address + 21; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::CalibrationCh3, - ::device_driver::RW, - >::new( + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::CalibrationCh3, ::device_driver::RW>::new( self.interface(), address as u8, field_sets::CalibrationCh3::new, @@ -309,21 +267,9 @@ impl Device { /// Calibration register channel 4 pub fn calibration_ch_4( &mut self, - ) -> ::device_driver::RegisterOperation< - '_, - I, - u8, - field_sets::CalibrationCh4, - ::device_driver::RW, - > { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::CalibrationCh4, ::device_driver::RW> { let address = self.base_address + 29; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::CalibrationCh4, - ::device_driver::RW, - >::new( + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::CalibrationCh4, ::device_driver::RW>::new( self.interface(), address as u8, field_sets::CalibrationCh4::new, @@ -332,133 +278,97 @@ impl Device { /// Alert configuration register 1 pub fn alert_config_1( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertConfig1, ::device_driver::RW> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertConfig1, ::device_driver::RW> { let address = self.base_address + 7; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::AlertConfig1, - ::device_driver::RW, - >::new(self.interface(), address as u8, field_sets::AlertConfig1::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::AlertConfig1, ::device_driver::RW>::new( + self.interface(), + address as u8, + field_sets::AlertConfig1::new, + ) } /// Alert configuration register 2 pub fn alert_config_2( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertConfig2, ::device_driver::RW> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertConfig2, ::device_driver::RW> { let address = self.base_address + 15; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::AlertConfig2, - ::device_driver::RW, - >::new(self.interface(), address as u8, field_sets::AlertConfig2::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::AlertConfig2, ::device_driver::RW>::new( + self.interface(), + address as u8, + field_sets::AlertConfig2::new, + ) } /// Alert configuration register 3 pub fn alert_config_3( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertConfig3, ::device_driver::RW> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertConfig3, ::device_driver::RW> { let address = self.base_address + 23; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::AlertConfig3, - ::device_driver::RW, - >::new(self.interface(), address as u8, field_sets::AlertConfig3::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::AlertConfig3, ::device_driver::RW>::new( + self.interface(), + address as u8, + field_sets::AlertConfig3::new, + ) } /// Alert configuration register 4 pub fn alert_config_4( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertConfig4, ::device_driver::RW> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertConfig4, ::device_driver::RW> { let address = self.base_address + 31; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::AlertConfig4, - ::device_driver::RW, - >::new(self.interface(), address as u8, field_sets::AlertConfig4::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::AlertConfig4, ::device_driver::RW>::new( + self.interface(), + address as u8, + field_sets::AlertConfig4::new, + ) } /// Alert limit register 1. Format matches corresponding result register. pub fn alert_limit_1( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertLimit1, ::device_driver::RW> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertLimit1, ::device_driver::RW> { let address = self.base_address + 6; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::AlertLimit1, - ::device_driver::RW, - >::new(self.interface(), address as u8, field_sets::AlertLimit1::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::AlertLimit1, ::device_driver::RW>::new( + self.interface(), + address as u8, + field_sets::AlertLimit1::new, + ) } /// Alert limit register 2 pub fn alert_limit_2( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertLimit2, ::device_driver::RW> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertLimit2, ::device_driver::RW> { let address = self.base_address + 14; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::AlertLimit2, - ::device_driver::RW, - >::new(self.interface(), address as u8, field_sets::AlertLimit2::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::AlertLimit2, ::device_driver::RW>::new( + self.interface(), + address as u8, + field_sets::AlertLimit2::new, + ) } /// Alert limit register 3 pub fn alert_limit_3( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertLimit3, ::device_driver::RW> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertLimit3, ::device_driver::RW> { let address = self.base_address + 22; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::AlertLimit3, - ::device_driver::RW, - >::new(self.interface(), address as u8, field_sets::AlertLimit3::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::AlertLimit3, ::device_driver::RW>::new( + self.interface(), + address as u8, + field_sets::AlertLimit3::new, + ) } /// Alert limit register 4 pub fn alert_limit_4( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertLimit4, ::device_driver::RW> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::AlertLimit4, ::device_driver::RW> { let address = self.base_address + 30; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::AlertLimit4, - ::device_driver::RW, - >::new(self.interface(), address as u8, field_sets::AlertLimit4::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::AlertLimit4, ::device_driver::RW>::new( + self.interface(), + address as u8, + field_sets::AlertLimit4::new, + ) } /// Shunt voltage channel 1. 2's complement. LSB = 2.5uV (range=0) or 625nV (range=1) pub fn shunt_voltage_ch_1( &mut self, - ) -> ::device_driver::RegisterOperation< - '_, - I, - u8, - field_sets::ShuntVoltageCh1, - ::device_driver::RO, - > { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::ShuntVoltageCh1, ::device_driver::RO> { let address = self.base_address + 0; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::ShuntVoltageCh1, - ::device_driver::RO, - >::new( + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::ShuntVoltageCh1, ::device_driver::RO>::new( self.interface(), address as u8, field_sets::ShuntVoltageCh1::new, @@ -467,21 +377,9 @@ impl Device { /// Shunt voltage channel 2 pub fn shunt_voltage_ch_2( &mut self, - ) -> ::device_driver::RegisterOperation< - '_, - I, - u8, - field_sets::ShuntVoltageCh2, - ::device_driver::RO, - > { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::ShuntVoltageCh2, ::device_driver::RO> { let address = self.base_address + 8; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::ShuntVoltageCh2, - ::device_driver::RO, - >::new( + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::ShuntVoltageCh2, ::device_driver::RO>::new( self.interface(), address as u8, field_sets::ShuntVoltageCh2::new, @@ -490,21 +388,9 @@ impl Device { /// Shunt voltage channel 3 pub fn shunt_voltage_ch_3( &mut self, - ) -> ::device_driver::RegisterOperation< - '_, - I, - u8, - field_sets::ShuntVoltageCh3, - ::device_driver::RO, - > { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::ShuntVoltageCh3, ::device_driver::RO> { let address = self.base_address + 16; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::ShuntVoltageCh3, - ::device_driver::RO, - >::new( + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::ShuntVoltageCh3, ::device_driver::RO>::new( self.interface(), address as u8, field_sets::ShuntVoltageCh3::new, @@ -513,21 +399,9 @@ impl Device { /// Shunt voltage channel 4 pub fn shunt_voltage_ch_4( &mut self, - ) -> ::device_driver::RegisterOperation< - '_, - I, - u8, - field_sets::ShuntVoltageCh4, - ::device_driver::RO, - > { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::ShuntVoltageCh4, ::device_driver::RO> { let address = self.base_address + 24; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::ShuntVoltageCh4, - ::device_driver::RO, - >::new( + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::ShuntVoltageCh4, ::device_driver::RO>::new( self.interface(), address as u8, field_sets::ShuntVoltageCh4::new, @@ -536,16 +410,9 @@ impl Device { /// Bus voltage channel 1. Always positive. LSB = 1.6mV pub fn bus_voltage_ch_1( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::BusVoltageCh1, ::device_driver::RO> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::BusVoltageCh1, ::device_driver::RO> { let address = self.base_address + 1; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::BusVoltageCh1, - ::device_driver::RO, - >::new( + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::BusVoltageCh1, ::device_driver::RO>::new( self.interface(), address as u8, field_sets::BusVoltageCh1::new, @@ -554,16 +421,9 @@ impl Device { /// Bus voltage channel 2 pub fn bus_voltage_ch_2( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::BusVoltageCh2, ::device_driver::RO> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::BusVoltageCh2, ::device_driver::RO> { let address = self.base_address + 9; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::BusVoltageCh2, - ::device_driver::RO, - >::new( + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::BusVoltageCh2, ::device_driver::RO>::new( self.interface(), address as u8, field_sets::BusVoltageCh2::new, @@ -572,16 +432,9 @@ impl Device { /// Bus voltage channel 3 pub fn bus_voltage_ch_3( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::BusVoltageCh3, ::device_driver::RO> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::BusVoltageCh3, ::device_driver::RO> { let address = self.base_address + 17; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::BusVoltageCh3, - ::device_driver::RO, - >::new( + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::BusVoltageCh3, ::device_driver::RO>::new( self.interface(), address as u8, field_sets::BusVoltageCh3::new, @@ -590,16 +443,9 @@ impl Device { /// Bus voltage channel 4 pub fn bus_voltage_ch_4( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::BusVoltageCh4, ::device_driver::RO> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::BusVoltageCh4, ::device_driver::RO> { let address = self.base_address + 25; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::BusVoltageCh4, - ::device_driver::RO, - >::new( + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::BusVoltageCh4, ::device_driver::RO>::new( self.interface(), address as u8, field_sets::BusVoltageCh4::new, @@ -608,175 +454,137 @@ impl Device { /// Current channel 1. Value [A] = CURRENT_LSB x register_value pub fn current_ch_1( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::CurrentCh1, ::device_driver::RO> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::CurrentCh1, ::device_driver::RO> { let address = self.base_address + 2; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::CurrentCh1, - ::device_driver::RO, - >::new(self.interface(), address as u8, field_sets::CurrentCh1::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::CurrentCh1, ::device_driver::RO>::new( + self.interface(), + address as u8, + field_sets::CurrentCh1::new, + ) } /// Current channel 2 pub fn current_ch_2( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::CurrentCh2, ::device_driver::RO> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::CurrentCh2, ::device_driver::RO> { let address = self.base_address + 10; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::CurrentCh2, - ::device_driver::RO, - >::new(self.interface(), address as u8, field_sets::CurrentCh2::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::CurrentCh2, ::device_driver::RO>::new( + self.interface(), + address as u8, + field_sets::CurrentCh2::new, + ) } /// Current channel 3 pub fn current_ch_3( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::CurrentCh3, ::device_driver::RO> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::CurrentCh3, ::device_driver::RO> { let address = self.base_address + 18; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::CurrentCh3, - ::device_driver::RO, - >::new(self.interface(), address as u8, field_sets::CurrentCh3::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::CurrentCh3, ::device_driver::RO>::new( + self.interface(), + address as u8, + field_sets::CurrentCh3::new, + ) } /// Current channel 4 pub fn current_ch_4( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::CurrentCh4, ::device_driver::RO> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::CurrentCh4, ::device_driver::RO> { let address = self.base_address + 26; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::CurrentCh4, - ::device_driver::RO, - >::new(self.interface(), address as u8, field_sets::CurrentCh4::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::CurrentCh4, ::device_driver::RO>::new( + self.interface(), + address as u8, + field_sets::CurrentCh4::new, + ) } /// Power channel 1. Value [W] = 32 x CURRENT_LSB x register_value. Unsigned. pub fn power_ch_1( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::PowerCh1, ::device_driver::RO> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::PowerCh1, ::device_driver::RO> { let address = self.base_address + 3; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::PowerCh1, - ::device_driver::RO, - >::new(self.interface(), address as u8, field_sets::PowerCh1::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::PowerCh1, ::device_driver::RO>::new( + self.interface(), + address as u8, + field_sets::PowerCh1::new, + ) } /// Power channel 2 pub fn power_ch_2( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::PowerCh2, ::device_driver::RO> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::PowerCh2, ::device_driver::RO> { let address = self.base_address + 11; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::PowerCh2, - ::device_driver::RO, - >::new(self.interface(), address as u8, field_sets::PowerCh2::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::PowerCh2, ::device_driver::RO>::new( + self.interface(), + address as u8, + field_sets::PowerCh2::new, + ) } /// Power channel 3 pub fn power_ch_3( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::PowerCh3, ::device_driver::RO> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::PowerCh3, ::device_driver::RO> { let address = self.base_address + 19; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::PowerCh3, - ::device_driver::RO, - >::new(self.interface(), address as u8, field_sets::PowerCh3::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::PowerCh3, ::device_driver::RO>::new( + self.interface(), + address as u8, + field_sets::PowerCh3::new, + ) } /// Power channel 4 pub fn power_ch_4( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::PowerCh4, ::device_driver::RO> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::PowerCh4, ::device_driver::RO> { let address = self.base_address + 27; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::PowerCh4, - ::device_driver::RO, - >::new(self.interface(), address as u8, field_sets::PowerCh4::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::PowerCh4, ::device_driver::RO>::new( + self.interface(), + address as u8, + field_sets::PowerCh4::new, + ) } /// Energy channel 1. Value [J] = 32 x CURRENT_LSB x register_value. Unsigned. pub fn energy_ch_1( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::EnergyCh1, ::device_driver::RO> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::EnergyCh1, ::device_driver::RO> { let address = self.base_address + 4; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::EnergyCh1, - ::device_driver::RO, - >::new(self.interface(), address as u8, field_sets::EnergyCh1::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::EnergyCh1, ::device_driver::RO>::new( + self.interface(), + address as u8, + field_sets::EnergyCh1::new, + ) } /// Energy channel 2 pub fn energy_ch_2( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::EnergyCh2, ::device_driver::RO> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::EnergyCh2, ::device_driver::RO> { let address = self.base_address + 12; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::EnergyCh2, - ::device_driver::RO, - >::new(self.interface(), address as u8, field_sets::EnergyCh2::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::EnergyCh2, ::device_driver::RO>::new( + self.interface(), + address as u8, + field_sets::EnergyCh2::new, + ) } /// Energy channel 3 pub fn energy_ch_3( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::EnergyCh3, ::device_driver::RO> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::EnergyCh3, ::device_driver::RO> { let address = self.base_address + 20; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::EnergyCh3, - ::device_driver::RO, - >::new(self.interface(), address as u8, field_sets::EnergyCh3::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::EnergyCh3, ::device_driver::RO>::new( + self.interface(), + address as u8, + field_sets::EnergyCh3::new, + ) } /// Energy channel 4 pub fn energy_ch_4( &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::EnergyCh4, ::device_driver::RO> - { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::EnergyCh4, ::device_driver::RO> { let address = self.base_address + 28; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::EnergyCh4, - ::device_driver::RO, - >::new(self.interface(), address as u8, field_sets::EnergyCh4::new) + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::EnergyCh4, ::device_driver::RO>::new( + self.interface(), + address as u8, + field_sets::EnergyCh4::new, + ) } /// Flags register - pub fn flags( - &mut self, - ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::Flags, ::device_driver::RO> { + pub fn flags(&mut self) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::Flags, ::device_driver::RO> { let address = self.base_address + 34; ::device_driver::RegisterOperation::<'_, I, u8, field_sets::Flags, ::device_driver::RO>::new( self.interface(), @@ -787,21 +595,9 @@ impl Device { /// Manufacturer ID. Reads back 0x5449 ('TI' in ASCII) pub fn manufacturer_id( &mut self, - ) -> ::device_driver::RegisterOperation< - '_, - I, - u8, - field_sets::ManufacturerId, - ::device_driver::RO, - > { + ) -> ::device_driver::RegisterOperation<'_, I, u8, field_sets::ManufacturerId, ::device_driver::RO> { let address = self.base_address + 126; - ::device_driver::RegisterOperation::< - '_, - I, - u8, - field_sets::ManufacturerId, - ::device_driver::RO, - >::new( + ::device_driver::RegisterOperation::<'_, I, u8, field_sets::ManufacturerId, ::device_driver::RO>::new( self.interface(), address as u8, field_sets::ManufacturerId::new, @@ -843,45 +639,35 @@ pub mod field_sets { /// /// Active channel enable bits. Bit15=CH4, Bit14=CH3, Bit13=CH2, Bit12=CH1 pub fn active_channel(&self) -> u8 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 12, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 12, 16) }; raw } ///Read the `avg` field of the register. /// /// Number of ADC conversion results to average pub fn avg(&self) -> super::Averaging { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 9, 12) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 9, 12) }; unsafe { raw.try_into().unwrap_unchecked() } } ///Read the `vbusct` field of the register. /// /// Bus voltage conversion time pub fn vbusct(&self) -> super::BusConversionTime { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 6, 9) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 6, 9) }; unsafe { raw.try_into().unwrap_unchecked() } } ///Read the `vshct` field of the register. /// /// Shunt voltage conversion time pub fn vshct(&self) -> super::ShuntConversionTime { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 3, 6) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 3, 6) }; unsafe { raw.try_into().unwrap_unchecked() } } ///Read the `mode` field of the register. /// /// Operating mode pub fn mode(&self) -> super::Mode { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 3) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 3) }; unsafe { raw.try_into().unwrap_unchecked() } } ///Write the `active_channel` field of the register. @@ -889,70 +675,35 @@ pub mod field_sets { /// Active channel enable bits. Bit15=CH4, Bit14=CH3, Bit13=CH2, Bit12=CH1 pub fn set_active_channel(&mut self, value: u8) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 12, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 12, 16, &mut self.bits) }; } ///Write the `avg` field of the register. /// /// Number of ADC conversion results to average pub fn set_avg(&mut self, value: super::Averaging) { let raw = value.into(); - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 9, - 12, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 9, 12, &mut self.bits) }; } ///Write the `vbusct` field of the register. /// /// Bus voltage conversion time pub fn set_vbusct(&mut self, value: super::BusConversionTime) { let raw = value.into(); - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 6, - 9, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 6, 9, &mut self.bits) }; } ///Write the `vshct` field of the register. /// /// Shunt voltage conversion time pub fn set_vshct(&mut self, value: super::ShuntConversionTime) { let raw = value.into(); - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 3, - 6, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 3, 6, &mut self.bits) }; } ///Write the `mode` field of the register. /// /// Operating mode pub fn set_mode(&mut self, value: super::Mode) { let raw = value.into(); - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 3, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 3, &mut self.bits) }; } } impl From<[u8; 2]> for Config1 { @@ -976,7 +727,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for Config1 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "Config1 {{ "); @@ -1070,63 +821,49 @@ pub mod field_sets { /// /// System reset. Set to 1 to reset all registers to default. Self-clears. pub fn rst(&self) -> bool { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 15, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 15, 16) }; raw > 0 } ///Read the `acc_rst` field of the register. /// /// Energy accumulator reset per channel. Bit11=CH4, Bit10=CH3, Bit9=CH2, Bit8=CH1. Bits self-clear after write. pub fn acc_rst(&self) -> u8 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 8, 12) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 8, 12) }; raw } ///Read the `cnvr_mask` field of the register. /// /// Conversion ready flag on ALERT pin enable pub fn cnvr_mask(&self) -> bool { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 7, 8) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 7, 8) }; raw > 0 } ///Read the `enof_mask` field of the register. /// /// Energy overflow alert enable pub fn enof_mask(&self) -> bool { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 6, 7) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 6, 7) }; raw > 0 } ///Read the `alert_latch` field of the register. /// /// Alert pin latch enable. When set, alert latches until flags register is read. pub fn alert_latch(&self) -> bool { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 5, 6) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 5, 6) }; raw > 0 } ///Read the `alert_pol` field of the register. /// /// Alert pin polarity pub fn alert_pol(&self) -> super::AlertPolarity { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 4, 5) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 4, 5) }; unsafe { raw.try_into().unwrap_unchecked() } } ///Read the `range` field of the register. /// /// Shunt full scale input range per channel. Bit3=CH4, Bit2=CH3, Bit1=CH2, Bit0=CH1. 0=±81.92mV, 1=±20.48mV pub fn range(&self) -> u8 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 4) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 4) }; raw } ///Write the `rst` field of the register. @@ -1134,98 +871,49 @@ pub mod field_sets { /// System reset. Set to 1 to reset all registers to default. Self-clears. pub fn set_rst(&mut self, value: bool) { let raw = value as _; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 15, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 15, 16, &mut self.bits) }; } ///Write the `acc_rst` field of the register. /// /// Energy accumulator reset per channel. Bit11=CH4, Bit10=CH3, Bit9=CH2, Bit8=CH1. Bits self-clear after write. pub fn set_acc_rst(&mut self, value: u8) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 8, - 12, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 8, 12, &mut self.bits) }; } ///Write the `cnvr_mask` field of the register. /// /// Conversion ready flag on ALERT pin enable pub fn set_cnvr_mask(&mut self, value: bool) { let raw = value as _; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 7, - 8, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 7, 8, &mut self.bits) }; } ///Write the `enof_mask` field of the register. /// /// Energy overflow alert enable pub fn set_enof_mask(&mut self, value: bool) { let raw = value as _; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 6, - 7, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 6, 7, &mut self.bits) }; } ///Write the `alert_latch` field of the register. /// /// Alert pin latch enable. When set, alert latches until flags register is read. pub fn set_alert_latch(&mut self, value: bool) { let raw = value as _; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 5, - 6, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 5, 6, &mut self.bits) }; } ///Write the `alert_pol` field of the register. /// /// Alert pin polarity pub fn set_alert_pol(&mut self, value: super::AlertPolarity) { let raw = value.into(); - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 4, - 5, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 4, 5, &mut self.bits) }; } ///Write the `range` field of the register. /// /// Shunt full scale input range per channel. Bit3=CH4, Bit2=CH3, Bit1=CH2, Bit0=CH1. 0=±81.92mV, 1=±20.48mV pub fn set_range(&mut self, value: u8) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 4, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 4, &mut self.bits) }; } } impl From<[u8; 2]> for Config2 { @@ -1251,7 +939,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for Config2 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "Config2 {{ "); @@ -1347,9 +1035,7 @@ pub mod field_sets { /// /// Shunt calibration value for current conversion pub fn shunt_cal(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 15) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 15) }; raw } ///Write the `shunt_cal` field of the register. @@ -1357,14 +1043,7 @@ pub mod field_sets { /// Shunt calibration value for current conversion pub fn set_shunt_cal(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 15, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 15, &mut self.bits) }; } } impl From<[u8; 2]> for CalibrationCh1 { @@ -1384,7 +1063,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for CalibrationCh1 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "CalibrationCh1 {{ "); @@ -1474,9 +1153,7 @@ pub mod field_sets { /// /// Shunt calibration value for current conversion pub fn shunt_cal(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 15) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 15) }; raw } ///Write the `shunt_cal` field of the register. @@ -1484,14 +1161,7 @@ pub mod field_sets { /// Shunt calibration value for current conversion pub fn set_shunt_cal(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 15, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 15, &mut self.bits) }; } } impl From<[u8; 2]> for CalibrationCh2 { @@ -1511,7 +1181,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for CalibrationCh2 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "CalibrationCh2 {{ "); @@ -1601,9 +1271,7 @@ pub mod field_sets { /// /// Shunt calibration value for current conversion pub fn shunt_cal(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 15) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 15) }; raw } ///Write the `shunt_cal` field of the register. @@ -1611,14 +1279,7 @@ pub mod field_sets { /// Shunt calibration value for current conversion pub fn set_shunt_cal(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 15, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 15, &mut self.bits) }; } } impl From<[u8; 2]> for CalibrationCh3 { @@ -1638,7 +1299,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for CalibrationCh3 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "CalibrationCh3 {{ "); @@ -1728,9 +1389,7 @@ pub mod field_sets { /// /// Shunt calibration value for current conversion pub fn shunt_cal(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 15) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 15) }; raw } ///Write the `shunt_cal` field of the register. @@ -1738,14 +1397,7 @@ pub mod field_sets { /// Shunt calibration value for current conversion pub fn set_shunt_cal(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 15, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 15, &mut self.bits) }; } } impl From<[u8; 2]> for CalibrationCh4 { @@ -1765,7 +1417,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for CalibrationCh4 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "CalibrationCh4 {{ "); @@ -1855,18 +1507,14 @@ pub mod field_sets { /// /// Channel assignment for this alert pub fn channel(&self) -> super::AlertChannel { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 3, 5) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 3, 5) }; unsafe { raw.try_into().unwrap_unchecked() } } ///Read the `alert_mask` field of the register. /// /// Active alert function selection pub fn alert_mask(&self) -> super::AlertFunction { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 3) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 3) }; unsafe { raw.try_into().unwrap_unchecked() } } ///Write the `channel` field of the register. @@ -1874,28 +1522,14 @@ pub mod field_sets { /// Channel assignment for this alert pub fn set_channel(&mut self, value: super::AlertChannel) { let raw = value.into(); - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 3, - 5, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 3, 5, &mut self.bits) }; } ///Write the `alert_mask` field of the register. /// /// Active alert function selection pub fn set_alert_mask(&mut self, value: super::AlertFunction) { let raw = value.into(); - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 3, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 3, &mut self.bits) }; } } impl From<[u8; 2]> for AlertConfig1 { @@ -1916,7 +1550,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for AlertConfig1 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "AlertConfig1 {{ "); @@ -2007,18 +1641,14 @@ pub mod field_sets { /// /// Channel assignment for this alert pub fn channel(&self) -> u8 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 3, 5) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 3, 5) }; raw } ///Read the `alert_mask` field of the register. /// /// Active alert function selection pub fn alert_mask(&self) -> u8 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 3) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 3) }; raw } ///Write the `channel` field of the register. @@ -2026,28 +1656,14 @@ pub mod field_sets { /// Channel assignment for this alert pub fn set_channel(&mut self, value: u8) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 3, - 5, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 3, 5, &mut self.bits) }; } ///Write the `alert_mask` field of the register. /// /// Active alert function selection pub fn set_alert_mask(&mut self, value: u8) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 3, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 3, &mut self.bits) }; } } impl From<[u8; 2]> for AlertConfig2 { @@ -2068,7 +1684,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for AlertConfig2 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "AlertConfig2 {{ "); @@ -2159,18 +1775,14 @@ pub mod field_sets { /// /// Channel assignment for this alert pub fn channel(&self) -> u8 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 3, 5) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 3, 5) }; raw } ///Read the `alert_mask` field of the register. /// /// Active alert function selection pub fn alert_mask(&self) -> u8 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 3) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 3) }; raw } ///Write the `channel` field of the register. @@ -2178,28 +1790,14 @@ pub mod field_sets { /// Channel assignment for this alert pub fn set_channel(&mut self, value: u8) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 3, - 5, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 3, 5, &mut self.bits) }; } ///Write the `alert_mask` field of the register. /// /// Active alert function selection pub fn set_alert_mask(&mut self, value: u8) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 3, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 3, &mut self.bits) }; } } impl From<[u8; 2]> for AlertConfig3 { @@ -2220,7 +1818,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for AlertConfig3 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "AlertConfig3 {{ "); @@ -2311,18 +1909,14 @@ pub mod field_sets { /// /// Channel assignment for this alert pub fn channel(&self) -> u8 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 3, 5) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 3, 5) }; raw } ///Read the `alert_mask` field of the register. /// /// Active alert function selection pub fn alert_mask(&self) -> u8 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 3) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 3) }; raw } ///Write the `channel` field of the register. @@ -2330,28 +1924,14 @@ pub mod field_sets { /// Channel assignment for this alert pub fn set_channel(&mut self, value: u8) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 3, - 5, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 3, 5, &mut self.bits) }; } ///Write the `alert_mask` field of the register. /// /// Active alert function selection pub fn set_alert_mask(&mut self, value: u8) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 3, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 3, &mut self.bits) }; } } impl From<[u8; 2]> for AlertConfig4 { @@ -2372,7 +1952,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for AlertConfig4 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "AlertConfig4 {{ "); @@ -2463,9 +2043,7 @@ pub mod field_sets { /// /// Alert threshold. Shunt=signed 16-bit, Bus=unsigned 15-bit, Power=unsigned 16-bit pub fn limit(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `limit` field of the register. @@ -2473,14 +2051,7 @@ pub mod field_sets { /// Alert threshold. Shunt=signed 16-bit, Bus=unsigned 15-bit, Power=unsigned 16-bit pub fn set_limit(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for AlertLimit1 { @@ -2500,7 +2071,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for AlertLimit1 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "AlertLimit1 {{ "); @@ -2590,9 +2161,7 @@ pub mod field_sets { /// /// Alert threshold pub fn limit(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `limit` field of the register. @@ -2600,14 +2169,7 @@ pub mod field_sets { /// Alert threshold pub fn set_limit(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for AlertLimit2 { @@ -2627,7 +2189,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for AlertLimit2 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "AlertLimit2 {{ "); @@ -2717,9 +2279,7 @@ pub mod field_sets { /// /// Alert threshold pub fn limit(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `limit` field of the register. @@ -2727,14 +2287,7 @@ pub mod field_sets { /// Alert threshold pub fn set_limit(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for AlertLimit3 { @@ -2754,7 +2307,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for AlertLimit3 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "AlertLimit3 {{ "); @@ -2844,9 +2397,7 @@ pub mod field_sets { /// /// Alert threshold pub fn limit(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `limit` field of the register. @@ -2854,14 +2405,7 @@ pub mod field_sets { /// Alert threshold pub fn set_limit(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for AlertLimit4 { @@ -2881,7 +2425,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for AlertLimit4 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "AlertLimit4 {{ "); @@ -2971,9 +2515,7 @@ pub mod field_sets { /// /// Differential shunt voltage, 2's complement pub fn vshunt(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `vshunt` field of the register. @@ -2981,14 +2523,7 @@ pub mod field_sets { /// Differential shunt voltage, 2's complement pub fn set_vshunt(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for ShuntVoltageCh1 { @@ -3008,7 +2543,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for ShuntVoltageCh1 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "ShuntVoltageCh1 {{ "); @@ -3098,9 +2633,7 @@ pub mod field_sets { /// /// Differential shunt voltage, 2's complement pub fn vshunt(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `vshunt` field of the register. @@ -3108,14 +2641,7 @@ pub mod field_sets { /// Differential shunt voltage, 2's complement pub fn set_vshunt(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for ShuntVoltageCh2 { @@ -3135,7 +2661,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for ShuntVoltageCh2 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "ShuntVoltageCh2 {{ "); @@ -3225,9 +2751,7 @@ pub mod field_sets { /// /// Differential shunt voltage, 2's complement pub fn vshunt(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `vshunt` field of the register. @@ -3235,14 +2759,7 @@ pub mod field_sets { /// Differential shunt voltage, 2's complement pub fn set_vshunt(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for ShuntVoltageCh3 { @@ -3262,7 +2779,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for ShuntVoltageCh3 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "ShuntVoltageCh3 {{ "); @@ -3352,9 +2869,7 @@ pub mod field_sets { /// /// Differential shunt voltage, 2's complement pub fn vshunt(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `vshunt` field of the register. @@ -3362,14 +2877,7 @@ pub mod field_sets { /// Differential shunt voltage, 2's complement pub fn set_vshunt(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for ShuntVoltageCh4 { @@ -3389,7 +2897,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for ShuntVoltageCh4 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "ShuntVoltageCh4 {{ "); @@ -3479,9 +2987,7 @@ pub mod field_sets { /// /// Bus voltage, always positive, 2's complement format pub fn vbus(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `vbus` field of the register. @@ -3489,14 +2995,7 @@ pub mod field_sets { /// Bus voltage, always positive, 2's complement format pub fn set_vbus(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for BusVoltageCh1 { @@ -3516,7 +3015,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for BusVoltageCh1 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "BusVoltageCh1 {{ "); @@ -3606,9 +3105,7 @@ pub mod field_sets { /// /// Bus voltage pub fn vbus(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `vbus` field of the register. @@ -3616,14 +3113,7 @@ pub mod field_sets { /// Bus voltage pub fn set_vbus(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for BusVoltageCh2 { @@ -3643,7 +3133,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for BusVoltageCh2 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "BusVoltageCh2 {{ "); @@ -3733,9 +3223,7 @@ pub mod field_sets { /// /// Bus voltage pub fn vbus(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `vbus` field of the register. @@ -3743,14 +3231,7 @@ pub mod field_sets { /// Bus voltage pub fn set_vbus(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for BusVoltageCh3 { @@ -3770,7 +3251,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for BusVoltageCh3 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "BusVoltageCh3 {{ "); @@ -3860,9 +3341,7 @@ pub mod field_sets { /// /// Bus voltage pub fn vbus(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `vbus` field of the register. @@ -3870,14 +3349,7 @@ pub mod field_sets { /// Bus voltage pub fn set_vbus(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for BusVoltageCh4 { @@ -3897,7 +3369,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for BusVoltageCh4 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "BusVoltageCh4 {{ "); @@ -3987,9 +3459,7 @@ pub mod field_sets { /// /// Calculated current in amperes, 2's complement pub fn current(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `current` field of the register. @@ -3997,14 +3467,7 @@ pub mod field_sets { /// Calculated current in amperes, 2's complement pub fn set_current(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for CurrentCh1 { @@ -4024,7 +3487,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for CurrentCh1 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "CurrentCh1 {{ "); @@ -4114,9 +3577,7 @@ pub mod field_sets { /// /// Calculated current in amperes, 2's complement pub fn current(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `current` field of the register. @@ -4124,14 +3585,7 @@ pub mod field_sets { /// Calculated current in amperes, 2's complement pub fn set_current(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for CurrentCh2 { @@ -4151,7 +3605,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for CurrentCh2 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "CurrentCh2 {{ "); @@ -4241,9 +3695,7 @@ pub mod field_sets { /// /// Calculated current in amperes, 2's complement pub fn current(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `current` field of the register. @@ -4251,14 +3703,7 @@ pub mod field_sets { /// Calculated current in amperes, 2's complement pub fn set_current(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for CurrentCh3 { @@ -4278,7 +3723,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for CurrentCh3 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "CurrentCh3 {{ "); @@ -4368,9 +3813,7 @@ pub mod field_sets { /// /// Calculated current in amperes, 2's complement pub fn current(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `current` field of the register. @@ -4378,14 +3821,7 @@ pub mod field_sets { /// Calculated current in amperes, 2's complement pub fn set_current(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for CurrentCh4 { @@ -4405,7 +3841,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for CurrentCh4 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "CurrentCh4 {{ "); @@ -4495,9 +3931,7 @@ pub mod field_sets { /// /// Calculated power in watts, unsigned pub fn power(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `power` field of the register. @@ -4505,14 +3939,7 @@ pub mod field_sets { /// Calculated power in watts, unsigned pub fn set_power(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for PowerCh1 { @@ -4532,7 +3959,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for PowerCh1 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "PowerCh1 {{ "); @@ -4622,9 +4049,7 @@ pub mod field_sets { /// /// Calculated power in watts, unsigned pub fn power(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `power` field of the register. @@ -4632,14 +4057,7 @@ pub mod field_sets { /// Calculated power in watts, unsigned pub fn set_power(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for PowerCh2 { @@ -4659,7 +4077,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for PowerCh2 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "PowerCh2 {{ "); @@ -4749,9 +4167,7 @@ pub mod field_sets { /// /// Calculated power in watts, unsigned pub fn power(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `power` field of the register. @@ -4759,14 +4175,7 @@ pub mod field_sets { /// Calculated power in watts, unsigned pub fn set_power(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for PowerCh3 { @@ -4786,7 +4195,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for PowerCh3 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "PowerCh3 {{ "); @@ -4876,9 +4285,7 @@ pub mod field_sets { /// /// Calculated power in watts, unsigned pub fn power(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `power` field of the register. @@ -4886,14 +4293,7 @@ pub mod field_sets { /// Calculated power in watts, unsigned pub fn set_power(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for PowerCh4 { @@ -4913,7 +4313,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for PowerCh4 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "PowerCh4 {{ "); @@ -5003,9 +4403,7 @@ pub mod field_sets { /// /// Accumulated energy in joules, unsigned pub fn energy(&self) -> u32 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 32) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 32) }; raw } ///Write the `energy` field of the register. @@ -5013,14 +4411,7 @@ pub mod field_sets { /// Accumulated energy in joules, unsigned pub fn set_energy(&mut self, value: u32) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 32, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 32, &mut self.bits) }; } } impl From<[u8; 4]> for EnergyCh1 { @@ -5040,7 +4431,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for EnergyCh1 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "EnergyCh1 {{ "); @@ -5130,9 +4521,7 @@ pub mod field_sets { /// /// Accumulated energy in joules, unsigned pub fn energy(&self) -> u32 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 32) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 32) }; raw } ///Write the `energy` field of the register. @@ -5140,14 +4529,7 @@ pub mod field_sets { /// Accumulated energy in joules, unsigned pub fn set_energy(&mut self, value: u32) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 32, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 32, &mut self.bits) }; } } impl From<[u8; 4]> for EnergyCh2 { @@ -5167,7 +4549,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for EnergyCh2 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "EnergyCh2 {{ "); @@ -5257,9 +4639,7 @@ pub mod field_sets { /// /// Accumulated energy in joules, unsigned pub fn energy(&self) -> u32 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 32) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 32) }; raw } ///Write the `energy` field of the register. @@ -5267,14 +4647,7 @@ pub mod field_sets { /// Accumulated energy in joules, unsigned pub fn set_energy(&mut self, value: u32) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 32, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 32, &mut self.bits) }; } } impl From<[u8; 4]> for EnergyCh3 { @@ -5294,7 +4667,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for EnergyCh3 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "EnergyCh3 {{ "); @@ -5384,9 +4757,7 @@ pub mod field_sets { /// /// Accumulated energy in joules, unsigned pub fn energy(&self) -> u32 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 32) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 32) }; raw } ///Write the `energy` field of the register. @@ -5394,14 +4765,7 @@ pub mod field_sets { /// Accumulated energy in joules, unsigned pub fn set_energy(&mut self, value: u32) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 32, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 32, &mut self.bits) }; } } impl From<[u8; 4]> for EnergyCh4 { @@ -5421,7 +4785,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for EnergyCh4 { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "EnergyCh4 {{ "); @@ -5511,90 +4875,70 @@ pub mod field_sets { /// /// Alert limit 4 exceeded pub fn limit4_alert(&self) -> bool { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 15, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 15, 16) }; raw > 0 } ///Read the `limit3_alert` field of the register. /// /// Alert limit 3 exceeded pub fn limit3_alert(&self) -> bool { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 14, 15) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 14, 15) }; raw > 0 } ///Read the `limit2_alert` field of the register. /// /// Alert limit 2 exceeded pub fn limit2_alert(&self) -> bool { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 13, 14) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 13, 14) }; raw > 0 } ///Read the `limit1_alert` field of the register. /// /// Alert limit 1 exceeded pub fn limit1_alert(&self) -> bool { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 12, 13) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 12, 13) }; raw > 0 } ///Read the `energyof_ch4` field of the register. /// /// Energy register overflow channel 4 pub fn energyof_ch4(&self) -> bool { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 11, 12) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 11, 12) }; raw > 0 } ///Read the `energyof_ch3` field of the register. /// /// Energy register overflow channel 3 pub fn energyof_ch3(&self) -> bool { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 10, 11) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 10, 11) }; raw > 0 } ///Read the `energyof_ch2` field of the register. /// /// Energy register overflow channel 2 pub fn energyof_ch2(&self) -> bool { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 9, 10) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 9, 10) }; raw > 0 } ///Read the `energyof_ch1` field of the register. /// /// Energy register overflow channel 1 pub fn energyof_ch1(&self) -> bool { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 8, 9) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 8, 9) }; raw > 0 } ///Read the `cvrf` field of the register. /// /// Conversion ready flag. Set when all conversions and averaging complete. Cleared by writing CONFIG1 or reading FLAGS. pub fn cvrf(&self) -> bool { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 7, 8) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 7, 8) }; raw > 0 } ///Read the `ovf` field of the register. /// /// Math overflow flag. Indicates current and power data may be invalid. pub fn ovf(&self) -> bool { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 6, 7) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 6, 7) }; raw > 0 } ///Write the `limit4_alert` field of the register. @@ -5602,140 +4946,70 @@ pub mod field_sets { /// Alert limit 4 exceeded pub fn set_limit4_alert(&mut self, value: bool) { let raw = value as _; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 15, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 15, 16, &mut self.bits) }; } ///Write the `limit3_alert` field of the register. /// /// Alert limit 3 exceeded pub fn set_limit3_alert(&mut self, value: bool) { let raw = value as _; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 14, - 15, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 14, 15, &mut self.bits) }; } ///Write the `limit2_alert` field of the register. /// /// Alert limit 2 exceeded pub fn set_limit2_alert(&mut self, value: bool) { let raw = value as _; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 13, - 14, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 13, 14, &mut self.bits) }; } ///Write the `limit1_alert` field of the register. /// /// Alert limit 1 exceeded pub fn set_limit1_alert(&mut self, value: bool) { let raw = value as _; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 12, - 13, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 12, 13, &mut self.bits) }; } ///Write the `energyof_ch4` field of the register. /// /// Energy register overflow channel 4 pub fn set_energyof_ch4(&mut self, value: bool) { let raw = value as _; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 11, - 12, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 11, 12, &mut self.bits) }; } ///Write the `energyof_ch3` field of the register. /// /// Energy register overflow channel 3 pub fn set_energyof_ch3(&mut self, value: bool) { let raw = value as _; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 10, - 11, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 10, 11, &mut self.bits) }; } ///Write the `energyof_ch2` field of the register. /// /// Energy register overflow channel 2 pub fn set_energyof_ch2(&mut self, value: bool) { let raw = value as _; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 9, - 10, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 9, 10, &mut self.bits) }; } ///Write the `energyof_ch1` field of the register. /// /// Energy register overflow channel 1 pub fn set_energyof_ch1(&mut self, value: bool) { let raw = value as _; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 8, - 9, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 8, 9, &mut self.bits) }; } ///Write the `cvrf` field of the register. /// /// Conversion ready flag. Set when all conversions and averaging complete. Cleared by writing CONFIG1 or reading FLAGS. pub fn set_cvrf(&mut self, value: bool) { let raw = value as _; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 7, - 8, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 7, 8, &mut self.bits) }; } ///Write the `ovf` field of the register. /// /// Math overflow flag. Indicates current and power data may be invalid. pub fn set_ovf(&mut self, value: bool) { let raw = value as _; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 6, - 7, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 6, 7, &mut self.bits) }; } } impl From<[u8; 2]> for Flags { @@ -5764,7 +5038,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for Flags { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "Flags {{ "); @@ -5863,9 +5137,7 @@ pub mod field_sets { /// /// Manufacturer ID pub fn id(&self) -> u16 { - let raw = unsafe { - ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) - }; + let raw = unsafe { ::device_driver::ops::load_lsb0::(&self.bits, 0, 16) }; raw } ///Write the `id` field of the register. @@ -5873,14 +5145,7 @@ pub mod field_sets { /// Manufacturer ID pub fn set_id(&mut self, value: u16) { let raw = value; - unsafe { - ::device_driver::ops::store_lsb0::( - raw, - 0, - 16, - &mut self.bits, - ) - }; + unsafe { ::device_driver::ops::store_lsb0::(raw, 0, 16, &mut self.bits) }; } } impl From<[u8; 2]> for ManufacturerId { @@ -5900,7 +5165,7 @@ pub mod field_sets { d.finish() } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for ManufacturerId { fn format(&self, f: defmt::Formatter) { defmt::write!(f, "ManufacturerId {{ "); @@ -6078,7 +5343,7 @@ pub mod field_sets { } } } - #[cfg(feature = "defmt-03")] + #[cfg(feature = "defmt")] impl defmt::Format for FieldSetValue { fn format(&self, f: defmt::Formatter) { match self { @@ -6305,7 +5570,7 @@ pub mod field_sets { /// Averaging count #[repr(u8)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Averaging { _1 = 0, _4 = 1, @@ -6352,7 +5617,7 @@ impl From for u8 { /// Bus voltage conversion time #[repr(u8)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum BusConversionTime { _140Us = 0, _204Us = 1, @@ -6399,7 +5664,7 @@ impl From for u8 { /// Shunt voltage conversion time #[repr(u8)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum ShuntConversionTime { _140Us = 0, _204Us = 1, @@ -6446,7 +5711,7 @@ impl From for u8 { /// Operating mode #[repr(u8)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Mode { Shutdown = 0, ShuntTriggered = 1, @@ -6492,7 +5757,7 @@ impl From for u8 { } #[repr(u8)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum AlertPolarity { ActiveLow = 0, ActiveHigh = 1, @@ -6520,7 +5785,7 @@ impl From for u8 { } #[repr(u8)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum AlertChannel { Ch1 = 0, Ch2 = 1, @@ -6554,7 +5819,7 @@ impl From for u8 { } #[repr(u8)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum AlertFunction { None = 0, ShuntOverLimit = 1, diff --git a/src/lib.rs b/src/lib.rs index 63abd8d..8bd7976 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,7 +29,7 @@ const LARGEST_REG_SIZE_BYTES: usize = 4; /// INA4230 driver error. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Ina4230Error { /// An error occurred on the I²C bus. Bus(I2cError), @@ -98,7 +98,7 @@ impl device_driver::AsyncRegisterInterface fo } // ── Address pins ────────────────────────────────────────────────────────────── - +/// Logic level of an I²C address pin (A0 or A1) for device address selection. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum AddrPinState { @@ -115,29 +115,30 @@ pub enum AddrPinState { /// Trait for converting an (A0, A1) pair of address pin states into /// the corresponding I2C address. -trait ToAddress { +pub trait ToAddress { + /// Convert pin strapping to a 7-bit I²C address. fn to_address(self) -> u8; } impl ToAddress for (AddrPinState, AddrPinState) { fn to_address(self) -> u8 { match self { - (AddrPinState::Gnd, AddrPinState::Gnd) => 0b100_0000, - (AddrPinState::Gnd, AddrPinState::Vs) => 0b100_0001, - (AddrPinState::Gnd, AddrPinState::Sda) => 0b100_0010, - (AddrPinState::Gnd, AddrPinState::Scl) => 0b100_0011, - (AddrPinState::Vs, AddrPinState::Gnd) => 0b100_0100, - (AddrPinState::Vs, AddrPinState::Vs) => 0b100_0101, - (AddrPinState::Vs, AddrPinState::Sda) => 0b100_0110, - (AddrPinState::Vs, AddrPinState::Scl) => 0b100_0111, - (AddrPinState::Sda, AddrPinState::Gnd) => 0b100_1000, - (AddrPinState::Sda, AddrPinState::Vs) => 0b100_1001, - (AddrPinState::Sda, AddrPinState::Sda) => 0b100_1010, - (AddrPinState::Sda, AddrPinState::Scl) => 0b100_1011, - (AddrPinState::Scl, AddrPinState::Gnd) => 0b100_1100, - (AddrPinState::Scl, AddrPinState::Vs) => 0b100_1101, - (AddrPinState::Scl, AddrPinState::Sda) => 0b100_1110, - (AddrPinState::Scl, AddrPinState::Scl) => 0b100_1111, + (AddrPinState::Gnd, AddrPinState::Gnd) => 0x40, + (AddrPinState::Vs, AddrPinState::Gnd) => 0x41, + (AddrPinState::Gnd, AddrPinState::Sda) => 0x42, + (AddrPinState::Gnd, AddrPinState::Scl) => 0x43, + (AddrPinState::Gnd, AddrPinState::Vs) => 0x44, + (AddrPinState::Vs, AddrPinState::Vs) => 0x45, + (AddrPinState::Vs, AddrPinState::Sda) => 0x46, + (AddrPinState::Vs, AddrPinState::Scl) => 0x47, + (AddrPinState::Sda, AddrPinState::Gnd) => 0x48, + (AddrPinState::Sda, AddrPinState::Vs) => 0x49, + (AddrPinState::Sda, AddrPinState::Sda) => 0x4A, + (AddrPinState::Sda, AddrPinState::Scl) => 0x4B, + (AddrPinState::Scl, AddrPinState::Gnd) => 0x4C, + (AddrPinState::Scl, AddrPinState::Vs) => 0x4D, + (AddrPinState::Scl, AddrPinState::Sda) => 0x4E, + (AddrPinState::Scl, AddrPinState::Scl) => 0x4F, } } } @@ -146,7 +147,7 @@ impl ToAddress for (AddrPinState, AddrPinState) { /// One of the four measurement channels on the INA4230. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(usize)] pub enum Channel { /// Channel 1 @@ -162,10 +163,10 @@ pub enum Channel { impl Channel { fn to_bit(self) -> u8 { match self { - Channel::Ch0 => 0b0001, - Channel::Ch1 => 0b0010, - Channel::Ch2 => 0b0100, - Channel::Ch3 => 0b1000, + Channel::Ch1 => 0b0001, + Channel::Ch2 => 0b0010, + Channel::Ch3 => 0b0100, + Channel::Ch4 => 0b1000, } } } @@ -174,7 +175,7 @@ impl Channel { /// ADC full-scale input range for shunt voltage measurement. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum AdcRange { /// ±81.92 mV full scale, LSB = 2.5 µV (default) #[default] @@ -268,11 +269,11 @@ impl Ina4230 { /// Create a new driver instance. /// /// `a0` and `a1` select the I²C address via the pin strapping on the device. - pub fn new(i2c: I2c, a0: A0, a1: A1) -> Self { + pub fn new(i2c: I2c, a0: AddrPinState, a1: AddrPinState) -> Self { Self { device: Device::new(DeviceInterface { i2c, - address: i2c_address(a0, a1), + address: (a0, a1).to_address(), }), current_lsb_a: [None; 4], adc_range: [AdcRange::Range0; 4], @@ -329,22 +330,22 @@ impl Ina4230 { /// Returns [`Ina4230Error::MathOverflow`] if current or power data may be /// invalid, or [`Ina4230Error::EnergyOverflow`] if the energy accumulator /// has overflowed on any channel. Reading FLAGS clears all flags. -pub async fn check_flags(&mut self) -> Result<(), Ina4230Error> { - let flags = self.device.flags().read_async().await?; - if flags.ovf() { - Err(Ina4230Error::MathOverflow) - } else if flags.energyof_ch1() { - Err(Ina4230Error::EnergyOverflow(Channel::Ch1)); - } else if flags.energyof_ch2() { - Err(Ina4230Error::EnergyOverflow(Channel::Ch2)); - } else if flags.energyof_ch3() { - Err(Ina4230Error::EnergyOverflow(Channel::Ch3)); - } else if flags.energyof_ch4() { - Err(Ina4230Error::EnergyOverflow(Channel::Ch4)); - } else { - Ok(()) + pub async fn check_flags(&mut self) -> Result<(), Ina4230Error> { + let flags = self.device.flags().read_async().await?; + if flags.ovf() { + Err(Ina4230Error::MathOverflow) + } else if flags.energyof_ch1() { + Err(Ina4230Error::EnergyOverflow(Channel::Ch1)) + } else if flags.energyof_ch2() { + Err(Ina4230Error::EnergyOverflow(Channel::Ch2)) + } else if flags.energyof_ch3() { + Err(Ina4230Error::EnergyOverflow(Channel::Ch3)) + } else if flags.energyof_ch4() { + Err(Ina4230Error::EnergyOverflow(Channel::Ch4)) + } else { + Ok(()) + } } -} // ── Calibration ─────────────────────────────────────────────────────── /// Write the calibration register for a single channel. @@ -547,14 +548,14 @@ mod tests { async fn read_manufacturer_id() { // ManufacturerId: address 0x7E, 2 bytes BE, resets to 0x5449 ("TI" in ASCII) let expectations = vec![Transaction::write_read( - i2c_address(A0::Gnd, A1::Gnd), + (AddrPinState::Gnd, AddrPinState::Gnd).to_address(), vec![0x7E], vec![0x54, 0x49], )]; let i2c = Mock::new(&expectations); let mut dev = Device::new(DeviceInterface { i2c, - address: i2c_address(A0::Gnd, A1::Gnd), + address: (AddrPinState::Gnd, AddrPinState::Gnd).to_address(), }); let id = dev.manufacturer_id().read_async().await.unwrap(); assert_eq!(id.id(), 0x5449); @@ -567,11 +568,14 @@ mod tests { // shunt_cal for 100µA/LSB, 10mΩ: 0.00512 / (100e-6 * 0.010) = 5120 let cal: u16 = 5120; let [hi, lo] = cal.to_be_bytes(); - let expectations = vec![Transaction::write(i2c_address(A0::Gnd, A1::Gnd), vec![0x05, hi, lo])]; + let expectations = vec![Transaction::write( + (AddrPinState::Gnd, AddrPinState::Gnd).to_address(), + vec![0x05, hi, lo], + )]; let i2c = Mock::new(&expectations); let mut dev = Device::new(DeviceInterface { i2c, - address: i2c_address(A0::Gnd, A1::Gnd), + address: (AddrPinState::Gnd, AddrPinState::Gnd).to_address(), }); dev.calibration_ch_1() .write_async(|w| w.set_shunt_cal(cal)) @@ -587,12 +591,12 @@ mod tests { let raw: u16 = 5000; let [hi, lo] = raw.to_be_bytes(); let expectations = vec![Transaction::write_read( - i2c_address(A0::Gnd, A1::Gnd), + (AddrPinState::Gnd, AddrPinState::Gnd).to_address(), vec![0x01], vec![hi, lo], )]; let i2c = Mock::new(&expectations); - let mut sensor = Ina4230::new(i2c, A0::Gnd, A1::Gnd); + let mut sensor = Ina4230::new(i2c, AddrPinState::Gnd, AddrPinState::Gnd); let mv = sensor.bus_voltage(Channel::Ch1).await.unwrap(); assert!((mv - 8000.0).abs() < 0.1, "expected 8000.0 mV, got {mv}"); sensor.release().done(); @@ -604,7 +608,7 @@ mod tests { let [cal_hi, cal_lo] = cal.to_be_bytes(); let raw: u16 = 1000; let [hi, lo] = raw.to_be_bytes(); - let addr = i2c_address(A0::Gnd, A1::Gnd); + let addr = (AddrPinState::Gnd, AddrPinState::Gnd).to_address(); let expectations = vec![ // calibrate: read CONFIG2 Transaction::write_read(addr, vec![0x21], vec![0x00, 0x00]), @@ -616,7 +620,7 @@ mod tests { Transaction::write_read(addr, vec![0x02], vec![hi, lo]), ]; let i2c = Mock::new(&expectations); - let mut sensor = Ina4230::new(i2c, A0::Gnd, A1::Gnd); + let mut sensor = Ina4230::new(i2c, AddrPinState::Gnd, AddrPinState::Gnd); sensor .calibrate(Channel::Ch1, 100e-6, 0.010, AdcRange::Range0) .await @@ -631,12 +635,12 @@ mod tests { let raw: u16 = 1000; let [hi, lo] = raw.to_be_bytes(); let expectations = vec![Transaction::write_read( - i2c_address(A0::Gnd, A1::Gnd), + (AddrPinState::Gnd, AddrPinState::Gnd).to_address(), vec![0x02], vec![hi, lo], )]; let i2c = Mock::new(&expectations); - let mut sensor = Ina4230::new(i2c, A0::Gnd, A1::Gnd); + let mut sensor = Ina4230::new(i2c, AddrPinState::Gnd, AddrPinState::Gnd); let result = sensor.current(Channel::Ch1).await; assert!(matches!(result, Err(Ina4230Error::NotCalibrated))); sensor.release().done(); @@ -648,7 +652,7 @@ mod tests { let [cal_hi, cal_lo] = cal.to_be_bytes(); let raw: u16 = 1000; let [hi, lo] = raw.to_be_bytes(); - let addr = i2c_address(A0::Gnd, A1::Gnd); + let addr = (AddrPinState::Gnd, AddrPinState::Gnd).to_address(); let expectations = vec![ // calibrate CH1: read CONFIG2 Transaction::write_read(addr, vec![0x21], vec![0x00, 0x00]), @@ -660,7 +664,7 @@ mod tests { Transaction::write_read(addr, vec![0x0A], vec![hi, lo]), ]; let i2c = Mock::new(&expectations); - let mut sensor = Ina4230::new(i2c, A0::Gnd, A1::Gnd); + let mut sensor = Ina4230::new(i2c, AddrPinState::Gnd, AddrPinState::Gnd); sensor .calibrate(Channel::Ch1, 100e-6, 0.010, AdcRange::Range0) .await @@ -677,13 +681,29 @@ mod tests { let raw: u16 = 2000; // 2000 * 1.6 mV = 3200.0 mV let [hi, lo] = raw.to_be_bytes(); let expectations = vec![ - Transaction::write_read(i2c_address(A0::Gnd, A1::Gnd), vec![0x01], vec![hi, lo]), - Transaction::write_read(i2c_address(A0::Gnd, A1::Gnd), vec![0x09], vec![hi, lo]), - Transaction::write_read(i2c_address(A0::Gnd, A1::Gnd), vec![0x11], vec![hi, lo]), - Transaction::write_read(i2c_address(A0::Gnd, A1::Gnd), vec![0x19], vec![hi, lo]), + Transaction::write_read( + (AddrPinState::Gnd, AddrPinState::Gnd).to_address(), + vec![0x01], + vec![hi, lo], + ), + Transaction::write_read( + (AddrPinState::Gnd, AddrPinState::Gnd).to_address(), + vec![0x09], + vec![hi, lo], + ), + Transaction::write_read( + (AddrPinState::Gnd, AddrPinState::Gnd).to_address(), + vec![0x11], + vec![hi, lo], + ), + Transaction::write_read( + (AddrPinState::Gnd, AddrPinState::Gnd).to_address(), + vec![0x19], + vec![hi, lo], + ), ]; let i2c = Mock::new(&expectations); - let mut sensor = Ina4230::new(i2c, A0::Gnd, A1::Gnd); + let mut sensor = Ina4230::new(i2c, AddrPinState::Gnd, AddrPinState::Gnd); for ch in [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] { let mv = sensor.bus_voltage(ch).await.unwrap(); assert!((mv - 3200.0).abs() < 0.1, "expected 3200.0 mV, got {mv}"); @@ -701,7 +721,7 @@ mod tests { let [h2, l2] = ch2_cal.to_be_bytes(); let [h3, l3] = ch3_cal.to_be_bytes(); let [h4, l4] = ch4_cal.to_be_bytes(); - let addr = i2c_address(A0::Gnd, A1::Gnd); + let addr = (AddrPinState::Gnd, AddrPinState::Gnd).to_address(); let expectations = vec![ // calibrate CH1: read/write CONFIG2, write cal reg Transaction::write_read(addr, vec![0x21], vec![0x00, 0x00]), @@ -721,7 +741,7 @@ mod tests { Transaction::write(addr, vec![0x1D, h4, l4]), ]; let i2c = Mock::new(&expectations); - let mut sensor = Ina4230::new(i2c, A0::Gnd, A1::Gnd); + let mut sensor = Ina4230::new(i2c, AddrPinState::Gnd, AddrPinState::Gnd); sensor .calibrate_all([ (100e-6, 0.010, AdcRange::Range0), @@ -736,10 +756,22 @@ mod tests { #[tokio::test] async fn i2c_address_all_combinations() { - // Verify all four address pin combinations produce correct I²C addresses - assert_eq!(i2c_address(A0::Gnd, A1::Gnd), 0x40); - assert_eq!(i2c_address(A0::Vs, A1::Gnd), 0x41); - assert_eq!(i2c_address(A0::Gnd, A1::Vs), 0x44); - assert_eq!(i2c_address(A0::Vs, A1::Vs), 0x45); + // Verify all 16 address pin combinations per datasheet Table 6-1 + assert_eq!((AddrPinState::Gnd, AddrPinState::Gnd).to_address(), 0x40); + assert_eq!((AddrPinState::Vs, AddrPinState::Gnd).to_address(), 0x41); + assert_eq!((AddrPinState::Gnd, AddrPinState::Sda).to_address(), 0x42); + assert_eq!((AddrPinState::Gnd, AddrPinState::Scl).to_address(), 0x43); + assert_eq!((AddrPinState::Gnd, AddrPinState::Vs).to_address(), 0x44); + assert_eq!((AddrPinState::Vs, AddrPinState::Vs).to_address(), 0x45); + assert_eq!((AddrPinState::Vs, AddrPinState::Sda).to_address(), 0x46); + assert_eq!((AddrPinState::Vs, AddrPinState::Scl).to_address(), 0x47); + assert_eq!((AddrPinState::Sda, AddrPinState::Gnd).to_address(), 0x48); + assert_eq!((AddrPinState::Sda, AddrPinState::Vs).to_address(), 0x49); + assert_eq!((AddrPinState::Sda, AddrPinState::Sda).to_address(), 0x4A); + assert_eq!((AddrPinState::Sda, AddrPinState::Scl).to_address(), 0x4B); + assert_eq!((AddrPinState::Scl, AddrPinState::Gnd).to_address(), 0x4C); + assert_eq!((AddrPinState::Scl, AddrPinState::Vs).to_address(), 0x4D); + assert_eq!((AddrPinState::Scl, AddrPinState::Sda).to_address(), 0x4E); + assert_eq!((AddrPinState::Scl, AddrPinState::Scl).to_address(), 0x4F); } } From 4f14695e275a9294cc77644990e0acb9b4e2aa9f Mon Sep 17 00:00:00 2001 From: parallels Date: Thu, 23 Apr 2026 12:07:17 -0700 Subject: [PATCH 08/11] Update README for AddrPinState, defmt 1.0, and all 16 I2C addresses --- README.md | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 13431d1..984c2d8 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ async sensor traits (`VoltageSensor`, `CurrentSensor`, `PowerSensor`, `EnergySen - ADC range selection (±81.92 mV or ±20.48 mV full scale) written to hardware on calibration - Channel enable/disable support - INA4230-specific error variants (`NotCalibrated`, `MathOverflow`, `EnergyOverflow`) -- Optional `defmt-03` logging support +- Optional `defmt` logging support - `no_std` compatible ## Usage @@ -27,11 +27,11 @@ embedded-hal-async = "1" ``` ```rust,no_run -use ina4230::{A0, A1, AdcRange, Channel, Ina4230}; +use ina4230::{AddrPinState, AdcRange, Channel, Ina4230}; // i2c implements embedded_hal_async::i2c::I2c -// A0 and A1 select the I²C address via pin strapping on the device -let mut sensor = Ina4230::new(i2c, A0::Gnd, A1::Gnd); +// AddrPinState selects the I²C address via A0 and A1 pin strapping on the device +let mut sensor = Ina4230::new(i2c, AddrPinState::Gnd, AddrPinState::Gnd); // Reset, then calibrate each channel before taking measurements sensor.reset().await?; @@ -184,21 +184,37 @@ if let Err(e) = sensor.check_flags().await { ## I²C Addresses The I²C address is selected by the A0 and A1 pin strapping on the device. -Pass `A0` and `A1` values to `Ina4230::new()`: +Pass two `AddrPinState` values to `Ina4230::new()` — the first for A0, the +second for A1: ```rust,no_run -let sensor = Ina4230::new(i2c, A0::Gnd, A1::Gnd); // address 0x40 -let sensor = Ina4230::new(i2c, A0::Vs, A1::Gnd); // address 0x41 -let sensor = Ina4230::new(i2c, A0::Gnd, A1::Vs); // address 0x44 -let sensor = Ina4230::new(i2c, A0::Vs, A1::Vs); // address 0x45 +// A0=GND, A1=GND → address 0x40 +let sensor = Ina4230::new(i2c, AddrPinState::Gnd, AddrPinState::Gnd); + +// A0=VS, A1=SDA → address 0x46 +let sensor = Ina4230::new(i2c, AddrPinState::Vs, AddrPinState::Sda); ``` -| A1 | A0 | Address | +All 16 address combinations (per datasheet Table 6-1): + +| A0 | A1 | Address | |-----|-----|---------| | GND | GND | `0x40` | -| GND | VS | `0x41` | -| VS | GND | `0x44` | +| VS | GND | `0x41` | +| GND | SDA | `0x42` | +| GND | SCL | `0x43` | +| GND | VS | `0x44` | | VS | VS | `0x45` | +| VS | SDA | `0x46` | +| VS | SCL | `0x47` | +| SDA | GND | `0x48` | +| SDA | VS | `0x49` | +| SDA | SDA | `0x4A` | +| SDA | SCL | `0x4B` | +| SCL | GND | `0x4C` | +| SCL | VS | `0x4D` | +| SCL | SDA | `0x4E` | +| SCL | SCL | `0x4F` | ## Regenerating `src/device.rs` From 48b2f6b6decfda45da804746726383a215e5eb77 Mon Sep 17 00:00:00 2001 From: parallels Date: Sat, 25 Apr 2026 02:00:49 -0700 Subject: [PATCH 09/11] Fix doctests, pin tokio, remove doctest = false MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove [lib] doctest = false — doctests now enabled - Pin tokio to =1.45.0 - Fix math formula blocks to use text fence in README - Change rust,no_run to rust,ignore for examples that cannot compile in doctest context - Keep simple const declaration blocks as runnable doctests --- Cargo.toml | 5 ++--- README.md | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 858b764..9bb130e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,10 +20,9 @@ embedded-sensors-hal-async = "0.4.0" [dev-dependencies] embedded-hal-mock = { version = "0.11.1", features = ["embedded-hal-async"] } -tokio = { version = "1", features = ["rt", "macros"] } +tokio = { version = "=1.45.0", features = ["rt", "macros"] } + -[lib] -doctest = false [lints.rust] unsafe_code = "deny" diff --git a/README.md b/README.md index 984c2d8..21b9bd8 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ ina4230 = "0.1.0" embedded-hal-async = "1" ``` -```rust,no_run +```rust,ignore use ina4230::{AddrPinState, AdcRange, Channel, Ina4230}; // i2c implements embedded_hal_async::i2c::I2c @@ -54,7 +54,7 @@ Before taking measurements, two hardware-specific parameters must be set per cha Set `SHUNT_OHMS_CHx` to the resistance of the shunt resistor fitted on that channel, in ohms: -```rust,no_run +```rust const SHUNT_OHMS_CH1: f32 = 0.010; // 10 mΩ shunt on channel 1 ``` @@ -72,7 +72,7 @@ giving 32767 steps above zero. Set `MAX_CURRENT_CHx` to the maximum current you expect on that channel — the driver calculates the optimal `CURRENT_LSB` automatically: -```rust,no_run +```rust // Example: expecting up to 100 mA on channel 1 const MAX_CURRENT_CH1: f32 = 0.1; // amps const CURRENT_LSB_CH1: f32 = MAX_CURRENT_CH1 / 32767.0; // ~3.05 µA/LSB @@ -81,13 +81,13 @@ const CURRENT_LSB_CH1: f32 = MAX_CURRENT_CH1 / 32767.0; // ~3.05 µA/LSB The driver uses `CURRENT_LSB` to compute the `SHUNT_CAL` register value written during `calibrate()`: -``` +```text SHUNT_CAL = 0.00512 / (CURRENT_LSB × R_SHUNT) ``` And to convert the raw current register reading back to milliamperes: -``` +```text Current [mA] = raw × CURRENT_LSB × 1000 ``` @@ -111,7 +111,7 @@ When using `Range1`, the `SHUNT_CAL` register value is automatically divided by 4, the shunt voltage LSB is adjusted to 625 nV, and `CONFIG2.RANGE` is updated in hardware: -``` +```text Range0: SHUNT_CAL = 0.00512 / (CURRENT_LSB × R_SHUNT) Range1: SHUNT_CAL = 0.00512 / (CURRENT_LSB × R_SHUNT) / 4 ``` @@ -126,7 +126,7 @@ registers through the `CURRENT_LSB` and `Power_LSB` values. Call `calibrate()` before taking current, power, or energy measurements. Each channel is calibrated independently: -```rust,no_run +```rust,ignore sensor.calibrate(Channel::Ch1, CURRENT_LSB_CH1, SHUNT_OHMS_CH1, AdcRange::Range0).await?; sensor.calibrate(Channel::Ch2, CURRENT_LSB_CH2, SHUNT_OHMS_CH2, AdcRange::Range0).await?; sensor.calibrate(Channel::Ch3, CURRENT_LSB_CH3, SHUNT_OHMS_CH3, AdcRange::Range1).await?; @@ -135,7 +135,7 @@ sensor.calibrate(Channel::Ch4, CURRENT_LSB_CH4, SHUNT_OHMS_CH4, AdcRange::Range0 Or use `calibrate_all()` to configure all four channels in one call: -```rust,no_run +```rust,ignore sensor.calibrate_all([ (CURRENT_LSB_CH1, SHUNT_OHMS_CH1, AdcRange::Range0), (CURRENT_LSB_CH2, SHUNT_OHMS_CH2, AdcRange::Range0), @@ -153,7 +153,7 @@ results. Bus voltage and shunt voltage readings do not require calibration. All four channels are active by default after power up. Unused channels can be disabled to reduce conversion time: -```rust,no_run +```rust,ignore sensor.set_channel_active(Channel::Ch3, false).await?; sensor.set_channel_active(Channel::Ch4, false).await?; ``` @@ -163,7 +163,7 @@ sensor.set_channel_active(Channel::Ch4, false).await?; The driver returns `Ina4230Error` which covers both I²C bus errors and device-level conditions: -```rust,no_run +```rust,ignore match sensor.current(Channel::Ch1).await { Ok(ma) => info!("Current: {} mA", ma), Err(Ina4230Error::NotCalibrated) => error!("Call calibrate() first"), @@ -175,7 +175,7 @@ match sensor.current(Channel::Ch1).await { Use `check_flags()` to explicitly poll for overflow conditions: -```rust,no_run +```rust,ignore if let Err(e) = sensor.check_flags().await { warn!("INA4230 flag: {:?}", e); } @@ -187,7 +187,7 @@ The I²C address is selected by the A0 and A1 pin strapping on the device. Pass two `AddrPinState` values to `Ina4230::new()` — the first for A0, the second for A1: -```rust,no_run +```rust,ignore // A0=GND, A1=GND → address 0x40 let sensor = Ina4230::new(i2c, AddrPinState::Gnd, AddrPinState::Gnd); From 776a450a56171f29d4cb3e658f7358f4110c1e37 Mon Sep 17 00:00:00 2001 From: parallels Date: Sat, 25 Apr 2026 08:05:53 -0700 Subject: [PATCH 10/11] Fix clippy, doctests, cargo-vet, and supply chain configuration - Fix all clippy errors in lib.rs - Restore device module allow attributes matching bq25723 approved pattern - Regenerate src/device.rs with updated defmt feature name - Remove [lib] doctest = false, enable doctests - Change rust,no_run to rust,ignore in README - Fix math formula blocks in README - Pin tokio to =1.45.0 - Add cargo-vet supply chain with ODP shared audits - Add exemptions for embedded-sensors-hal, embedded-sensors-hal-async, libc and paste --- Cargo.lock | 93 ++++- src/lib.rs | 63 +++- supply-chain/audits.toml | 195 ++++++++++- supply-chain/config.toml | 114 ++++++ supply-chain/imports.lock | 709 +++++++++++++++++++++++++++++++++++++- 5 files changed, 1153 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3a2a86a..bdce83e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,18 +2,54 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link", +] + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + [[package]] name = "defmt" version = "0.3.100" @@ -164,6 +200,12 @@ dependencies = [ "num", ] +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + [[package]] name = "ina4230" version = "0.1.0" @@ -176,6 +218,27 @@ dependencies = [ "tokio", ] +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + [[package]] name = "nb" version = "0.1.3" @@ -253,6 +316,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + [[package]] name = "paste" version = "1.0.15" @@ -305,6 +377,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rustc-demangle" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" + [[package]] name = "syn" version = "2.0.117" @@ -338,19 +416,20 @@ dependencies = [ [[package]] name = "tokio" -version = "1.52.1" +version = "1.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" dependencies = [ + "backtrace", "pin-project-lite", "tokio-macros", ] [[package]] name = "tokio-macros" -version = "2.7.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", @@ -368,3 +447,9 @@ name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" diff --git a/src/lib.rs b/src/lib.rs index 8bd7976..41f563c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,6 @@ use embedded_sensors_hal_async::sensor; #[allow(unsafe_code)] #[allow(missing_docs)] mod device; - pub use crate::device::*; /// Maximum register data size in bytes (energy registers are 32-bit = 4 bytes). @@ -48,8 +47,7 @@ impl sensor::Error for Ina4230Error { match self { Self::Bus(_) => sensor::ErrorKind::Peripheral, Self::NotCalibrated => sensor::ErrorKind::NotReady, - Self::MathOverflow => sensor::ErrorKind::Saturated, - Self::EnergyOverflow(_) => sensor::ErrorKind::Saturated, + Self::MathOverflow | Self::EnergyOverflow(_) => sensor::ErrorKind::Saturated, } } } @@ -98,6 +96,7 @@ impl device_driver::AsyncRegisterInterface fo } // ── Address pins ────────────────────────────────────────────────────────────── + /// Logic level of an I²C address pin (A0 or A1) for device address selection. #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -114,7 +113,7 @@ pub enum AddrPinState { } /// Trait for converting an (A0, A1) pair of address pin states into -/// the corresponding I2C address. +/// the corresponding I²C address. pub trait ToAddress { /// Convert pin strapping to a 7-bit I²C address. fn to_address(self) -> u8; @@ -180,7 +179,7 @@ pub enum AdcRange { /// ±81.92 mV full scale, LSB = 2.5 µV (default) #[default] Range0, - /// ±20.48 mV full scale, LSB = 625 nV. SHUNT_CAL divided by 4. + /// ±20.48 mV full scale, LSB = 625 nV. `SHUNT_CAL` divided by 4. Range1, } @@ -259,7 +258,7 @@ impl EnergySensor for &mut T { pub struct Ina4230 { /// The generated low-level register accessor. device: Device>, - /// CURRENT_LSB per channel in A/LSB. None means not yet calibrated. + /// `CURRENT_LSB` per channel in A/LSB. None means not yet calibrated. current_lsb_a: [Option; 4], /// ADC input range per channel. adc_range: [AdcRange; 4], @@ -289,27 +288,47 @@ impl Ina4230 { /// Issue a full device reset (`CONFIG2.RST = 1`). All registers return to /// power-on defaults. The bit self-clears. + /// + /// # Errors + /// + /// Returns [`Ina4230Error::Bus`] if an I²C bus error occurs. pub async fn reset(&mut self) -> Result<(), Ina4230Error> { self.device.config_2().write_async(|w| w.set_rst(true)).await } /// Read the manufacturer ID register. Returns `0x5449` ("TI") on a healthy device. + /// + /// # Errors + /// + /// Returns [`Ina4230Error::Bus`] if an I²C bus error occurs. pub async fn manufacturer_id(&mut self) -> Result> { Ok(self.device.manufacturer_id().read_async().await?.id()) } /// Poll the Conversion Ready Flag (`FLAGS.CVRF`). Returns `true` when all /// enabled channels have completed conversion and averaging. + /// + /// # Errors + /// + /// Returns [`Ina4230Error::Bus`] if an I²C bus error occurs. pub async fn conversion_ready(&mut self) -> Result> { Ok(self.device.flags().read_async().await?.cvrf()) } /// Read the full flags register in one call. + /// + /// # Errors + /// + /// Returns [`Ina4230Error::Bus`] if an I²C bus error occurs. pub async fn flags(&mut self) -> Result> { self.device.flags().read_async().await } - /// Enable or disable a channel in `CONFIG1.ACTIVE_CHANNEL`. ← add here + /// Enable or disable a channel in `CONFIG1.ACTIVE_CHANNEL`. + /// + /// # Errors + /// + /// Returns [`Ina4230Error::Bus`] if an I²C bus error occurs. pub async fn set_channel_active(&mut self, channel: Channel, active: bool) -> Result<(), Ina4230Error> { let bit = channel.to_bit(); self.device @@ -317,19 +336,26 @@ impl Ina4230 { .modify_async(|w| { let mut active_channels = w.active_channel(); if active { - active_channels |= bit; // set bit to enable channel + active_channels |= bit; } else { - active_channels &= !bit; // clear bit to disable channel + active_channels &= !bit; } w.set_active_channel(active_channels); }) .await } + /// Check the FLAGS register for overflow conditions. /// /// Returns [`Ina4230Error::MathOverflow`] if current or power data may be /// invalid, or [`Ina4230Error::EnergyOverflow`] if the energy accumulator /// has overflowed on any channel. Reading FLAGS clears all flags. + /// + /// # Errors + /// + /// Returns [`Ina4230Error::Bus`] if an I²C bus error occurs. + /// Returns [`Ina4230Error::MathOverflow`] if the math overflow flag is set. + /// Returns [`Ina4230Error::EnergyOverflow`] if an energy overflow flag is set. pub async fn check_flags(&mut self) -> Result<(), Ina4230Error> { let flags = self.device.flags().read_async().await?; if flags.ovf() { @@ -346,6 +372,7 @@ impl Ina4230 { Ok(()) } } + // ── Calibration ─────────────────────────────────────────────────────── /// Write the calibration register for a single channel. @@ -356,6 +383,10 @@ impl Ina4230 { /// /// Formula (ADCRANGE = 0): `SHUNT_CAL = 0.00512 / (CURRENT_LSB × R_SHUNT)` /// Formula (ADCRANGE = 1): `SHUNT_CAL = 0.00512 / (CURRENT_LSB × R_SHUNT) / 4` + /// + /// # Errors + /// + /// Returns [`Ina4230Error::Bus`] if an I²C bus error occurs. pub async fn calibrate( &mut self, channel: Channel, @@ -375,8 +406,8 @@ impl Ina4230 { .modify_async(|w| { let mut range = w.range(); match adc_range { - AdcRange::Range0 => range &= !bit, // clear bit → ±81.92 mV - AdcRange::Range1 => range |= bit, // set bit → ±20.48 mV + AdcRange::Range0 => range &= !bit, + AdcRange::Range1 => range |= bit, } w.set_range(range); }) @@ -416,6 +447,10 @@ impl Ina4230 { /// /// Each channel can have independent parameters. `params` is ordered /// `[Ch1, Ch2, Ch3, Ch4]` as `(current_lsb_a, shunt_ohms, adc_range)`. + /// + /// # Errors + /// + /// Returns [`Ina4230Error::Bus`] if an I²C bus error occurs. pub async fn calibrate_all(&mut self, params: [(f32, f32, AdcRange); 4]) -> Result<(), Ina4230Error> { for (ch, (current_lsb_a, shunt_ohms, adc_range)) in [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] .iter() @@ -448,8 +483,8 @@ impl Ina4230 { fn shunt_mv(&self, channel: Channel, raw: u16) -> MilliVolts { let signed = raw as i16; let lsb_mv = match self.adc_range[channel as usize] { - AdcRange::Range0 => 0.0025, // 2.5 µV - AdcRange::Range1 => 0.000625, // 625 nV + AdcRange::Range0 => 0.0025, // 2.5 µV + AdcRange::Range1 => 0.000_625, // 625 nV }; f32::from(signed) * lsb_mv } @@ -468,6 +503,7 @@ impl Ina4230 { fn energy_mj(&self, channel: Channel, raw: u32) -> Result> { let lsb = self.current_lsb_a[channel as usize].ok_or(Ina4230Error::NotCalibrated)?; + #[allow(clippy::cast_precision_loss)] Ok(raw as f32 * 32.0 * lsb * 1000.0) } } @@ -629,6 +665,7 @@ mod tests { assert!((ma - 100.0).abs() < 0.01, "expected 100.0 mA, got {ma}"); sensor.release().done(); } + #[tokio::test] async fn current_returns_error_when_not_calibrated() { // Attempting to read current before calibrate() should return NotCalibrated diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index 2772ccb..44d2132 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -1,4 +1,197 @@ # cargo-vet audits file -[audits] +[[audits.bitfield-struct]] +who = "matteotullo " +criteria = "safe-to-deploy" +version = "0.10.1" + +[[audits.bitflags]] +who = "matteotullo " +criteria = "safe-to-deploy" +delta = "2.9.1 -> 2.9.4" + +[[audits.embedded-batteries]] +who = "matteotullo " +criteria = "safe-to-deploy" +version = "0.2.1" + +[[audits.embedded-batteries-async]] +who = "matteotullo " +criteria = "safe-to-deploy" +version = "0.2.1" + +[[audits.once_cell]] +who = "Jerry Xie " +criteria = "safe-to-deploy" +delta = "1.21.3 -> 1.21.4" + +[[audits.pin-project-lite]] +who = "Jerry Xie " +criteria = "safe-to-run" +delta = "0.2.16 -> 0.2.17" + +[[audits.windows-sys]] +who = "matteotullo " +criteria = "safe-to-run" +version = "0.59.0" + +[[audits.zerocopy]] +who = "matteotullo " +criteria = "safe-to-deploy" +delta = "0.8.25 -> 0.8.26" + +[[audits.zerocopy-derive]] +who = "matteotullo " +criteria = "safe-to-deploy" +delta = "0.8.25 -> 0.8.26" + +[[trusted.anyhow]] +criteria = "safe-to-deploy" +user-id = 3618 # David Tolnay (dtolnay) +start = "2019-10-05" +end = "2026-09-04" + +[[trusted.backtrace]] +criteria = "safe-to-deploy" +user-id = 55123 # rust-lang-owner +start = "2025-05-06" +end = "2027-03-13" + +[[trusted.bitflags]] +criteria = "safe-to-deploy" +user-id = 3204 # Ashley Mannix (KodrAus) +start = "2019-05-02" +end = "2027-03-13" + +[[trusted.cfg-if]] +criteria = "safe-to-deploy" +user-id = 55123 # rust-lang-owner +start = "2025-06-09" +end = "2026-09-04" + +[[trusted.dd-manifest-tree]] +criteria = "safe-to-deploy" +user-id = 85562 # Dion Dokter (diondokter) +start = "2024-11-10" +end = "2027-03-13" + +[[trusted.device-driver]] +criteria = "safe-to-deploy" +user-id = 85562 # Dion Dokter (diondokter) +start = "2020-09-28" +end = "2027-03-13" + +[[trusted.device-driver-generation]] +criteria = "safe-to-deploy" +user-id = 85562 # Dion Dokter (diondokter) +start = "2024-01-07" +end = "2027-03-13" + +[[trusted.device-driver-macros]] +criteria = "safe-to-deploy" +user-id = 85562 # Dion Dokter (diondokter) +start = "2024-01-07" +end = "2027-03-13" + +[[trusted.itoa]] +criteria = "safe-to-deploy" +user-id = 3618 # David Tolnay (dtolnay) +start = "2019-05-02" +end = "2027-03-13" + +[[trusted.libc]] +criteria = "safe-to-deploy" +user-id = 55123 # rust-lang-owner +start = "2024-08-15" +end = "2026-09-04" + +[[trusted.memchr]] +criteria = "safe-to-deploy" +user-id = 189 # Andrew Gallant (BurntSushi) +start = "2019-07-07" +end = "2027-03-13" + +[[trusted.object]] +criteria = "safe-to-run" +user-id = 4415 # Philip Craig (philipc) +start = "2019-04-26" +end = "2027-03-13" + +[[trusted.prettyplease]] +criteria = "safe-to-deploy" +user-id = 3618 # David Tolnay (dtolnay) +start = "2022-01-04" +end = "2027-03-13" + +[[trusted.proc-macro2]] +criteria = "safe-to-deploy" +user-id = 3618 # David Tolnay (dtolnay) +start = "2019-04-23" +end = "2026-09-04" + +[[trusted.quote]] +criteria = "safe-to-deploy" +user-id = 3618 # David Tolnay (dtolnay) +start = "2019-04-09" +end = "2027-03-13" + +[[trusted.rustc-demangle]] +criteria = "safe-to-deploy" +user-id = 55123 # rust-lang-owner +start = "2023-03-23" +end = "2026-09-04" + +[[trusted.serde_json]] +criteria = "safe-to-deploy" +user-id = 3618 # David Tolnay (dtolnay) +start = "2019-02-28" +end = "2027-03-13" + +[[trusted.syn]] +criteria = "safe-to-deploy" +user-id = 3618 # David Tolnay (dtolnay) +start = "2019-03-01" +end = "2026-09-04" + +[[trusted.thiserror]] +criteria = "safe-to-deploy" +user-id = 3618 # David Tolnay (dtolnay) +start = "2019-10-09" +end = "2026-09-04" + +[[trusted.thiserror-impl]] +criteria = "safe-to-deploy" +user-id = 3618 # David Tolnay (dtolnay) +start = "2019-10-09" +end = "2026-09-04" + +[[trusted.unicode-ident]] +criteria = "safe-to-deploy" +user-id = 3618 # David Tolnay (dtolnay) +start = "2021-10-02" +end = "2027-03-13" + +[[trusted.winnow]] +criteria = "safe-to-deploy" +user-id = 6743 # Ed Page (epage) +start = "2023-02-22" +end = "2027-03-13" + +[[trusted.zerocopy]] +criteria = "safe-to-deploy" +user-id = 7178 # Joshua Liebow-Feeser (joshlf) +start = "2019-02-28" +end = "2027-03-13" + +[[trusted.zerocopy-derive]] +criteria = "safe-to-deploy" +user-id = 7178 # Joshua Liebow-Feeser (joshlf) +start = "2019-02-28" +end = "2027-03-13" + +[[trusted.zmij]] +criteria = "safe-to-deploy" +user-id = 3618 # David Tolnay (dtolnay) +start = "2025-12-18" +end = "2027-03-13" diff --git a/supply-chain/config.toml b/supply-chain/config.toml index 55618c2..e269b65 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -7,8 +7,122 @@ version = "0.10" [imports.OpenDevicePartnership] url = "https://raw.githubusercontent.com/OpenDevicePartnership/rust-crate-audits/main/audits.toml" +[imports.bytecode-alliance] +url = "https://raw.githubusercontent.com/bytecodealliance/wasmtime/main/supply-chain/audits.toml" + [imports.google] url = "https://raw.githubusercontent.com/google/rust-crate-audits/main/audits.toml" [imports.mozilla] url = "https://raw.githubusercontent.com/mozilla/supply-chain/main/audits.toml" + +[imports.zcash] +url = "https://raw.githubusercontent.com/zcash/rust-ecosystem/main/supply-chain/audits.toml" + +[[exemptions.ahash]] +version = "0.8.12" +criteria = "safe-to-deploy" + +[[exemptions.bitvec]] +version = "1.0.1" +criteria = "safe-to-deploy" + +[[exemptions.convert_case]] +version = "0.6.0" +criteria = "safe-to-deploy" + +[[exemptions.defmt]] +version = "0.3.100" +criteria = "safe-to-deploy" + +[[exemptions.embedded-hal]] +version = "1.0.0" +criteria = "safe-to-deploy" + +[[exemptions.embedded-hal-async]] +version = "1.0.0" +criteria = "safe-to-deploy" + +[[exemptions.embedded-hal-mock]] +version = "0.11.1" +criteria = "safe-to-run" + +[[exemptions.embedded-hal-nb]] +version = "1.0.0" +criteria = "safe-to-run" + +[[exemptions.embedded-io-async]] +version = "0.6.1" +criteria = "safe-to-deploy" + +[[exemptions.embedded-sensors-hal]] +version = "0.1.1" +criteria = "safe-to-deploy" + +[[exemptions.embedded-sensors-hal-async]] +version = "0.4.0" +criteria = "safe-to-deploy" + +[[exemptions.embedded-time]] +version = "0.12.1" +criteria = "safe-to-run" + +[[exemptions.funty]] +version = "2.0.0" +criteria = "safe-to-deploy" + +[[exemptions.hashbrown]] +version = "0.14.5" +criteria = "safe-to-deploy" + +[[exemptions.hashlink]] +version = "0.9.1" +criteria = "safe-to-deploy" + +[[exemptions.libc]] +version = "0.2.186" +criteria = "safe-to-run" + +[[exemptions.num]] +version = "0.3.1" +criteria = "safe-to-run" + +[[exemptions.num-complex]] +version = "0.3.1" +criteria = "safe-to-run" + +[[exemptions.num-iter]] +version = "0.1.45" +criteria = "safe-to-run" + +[[exemptions.num-rational]] +version = "0.3.2" +criteria = "safe-to-run" + +[[exemptions.once_cell]] +version = "1.21.3" +criteria = "safe-to-deploy" + +[[exemptions.paste]] +version = "1.0.15" +criteria = "safe-to-deploy" + +[[exemptions.radium]] +version = "0.7.0" +criteria = "safe-to-deploy" + +[[exemptions.tap]] +version = "1.0.1" +criteria = "safe-to-deploy" + +[[exemptions.version_check]] +version = "0.9.5" +criteria = "safe-to-deploy" + +[[exemptions.wyz]] +version = "0.5.1" +criteria = "safe-to-deploy" + +[[exemptions.yaml-rust2]] +version = "0.9.0" +criteria = "safe-to-deploy" diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock index 219dba4..9c05555 100644 --- a/supply-chain/imports.lock +++ b/supply-chain/imports.lock @@ -1,8 +1,711 @@ # cargo-vet imports lock -[audits.OpenDevicePartnership.audits] +[[publisher.anyhow]] +version = "1.0.102" +when = "2026-02-20" +user-id = 3618 +user-login = "dtolnay" +user-name = "David Tolnay" -[audits.google.audits] +[[publisher.backtrace]] +version = "0.3.76" +when = "2025-09-26" +user-id = 55123 +user-login = "rust-lang-owner" -[audits.mozilla.audits] +[[publisher.bitflags]] +version = "2.11.0" +when = "2026-02-14" +user-id = 3204 +user-login = "KodrAus" +user-name = "Ashley Mannix" + +[[publisher.cfg-if]] +version = "1.0.4" +when = "2025-10-15" +user-id = 55123 +user-login = "rust-lang-owner" + +[[publisher.dd-manifest-tree]] +version = "1.0.0" +when = "2024-12-28" +user-id = 85562 +user-login = "diondokter" +user-name = "Dion Dokter" + +[[publisher.device-driver]] +version = "1.0.8" +when = "2026-03-06" +user-id = 85562 +user-login = "diondokter" +user-name = "Dion Dokter" + +[[publisher.device-driver-generation]] +version = "1.0.8" +when = "2026-03-06" +user-id = 85562 +user-login = "diondokter" +user-name = "Dion Dokter" + +[[publisher.device-driver-macros]] +version = "1.0.8" +when = "2026-03-06" +user-id = 85562 +user-login = "diondokter" +user-name = "Dion Dokter" + +[[publisher.encoding_rs]] +version = "0.8.35" +when = "2024-10-24" +user-id = 4484 +user-login = "hsivonen" +user-name = "Henri Sivonen" + +[[publisher.itoa]] +version = "1.0.17" +when = "2025-12-27" +user-id = 3618 +user-login = "dtolnay" +user-name = "David Tolnay" + +[[publisher.libc]] +version = "0.2.183" +when = "2026-03-08" +user-id = 55123 +user-login = "rust-lang-owner" + +[[publisher.memchr]] +version = "2.8.0" +when = "2026-02-06" +user-id = 189 +user-login = "BurntSushi" +user-name = "Andrew Gallant" + +[[publisher.object]] +version = "0.37.3" +when = "2025-08-13" +user-id = 4415 +user-login = "philipc" +user-name = "Philip Craig" + +[[publisher.prettyplease]] +version = "0.2.37" +when = "2025-08-19" +user-id = 3618 +user-login = "dtolnay" +user-name = "David Tolnay" + +[[publisher.proc-macro2]] +version = "1.0.106" +when = "2026-01-21" +user-id = 3618 +user-login = "dtolnay" +user-name = "David Tolnay" + +[[publisher.quote]] +version = "1.0.45" +when = "2026-03-03" +user-id = 3618 +user-login = "dtolnay" +user-name = "David Tolnay" + +[[publisher.rustc-demangle]] +version = "0.1.27" +when = "2026-01-15" +user-id = 55123 +user-login = "rust-lang-owner" + +[[publisher.serde_json]] +version = "1.0.149" +when = "2026-01-06" +user-id = 3618 +user-login = "dtolnay" +user-name = "David Tolnay" + +[[publisher.syn]] +version = "2.0.117" +when = "2026-02-20" +user-id = 3618 +user-login = "dtolnay" +user-name = "David Tolnay" + +[[publisher.thiserror]] +version = "2.0.18" +when = "2026-01-18" +user-id = 3618 +user-login = "dtolnay" +user-name = "David Tolnay" + +[[publisher.thiserror-impl]] +version = "2.0.18" +when = "2026-01-18" +user-id = 3618 +user-login = "dtolnay" +user-name = "David Tolnay" + +[[publisher.unicode-ident]] +version = "1.0.24" +when = "2026-02-16" +user-id = 3618 +user-login = "dtolnay" +user-name = "David Tolnay" + +[[publisher.unicode-segmentation]] +version = "1.12.0" +when = "2024-09-13" +user-id = 1139 +user-login = "Manishearth" +user-name = "Manish Goregaokar" + +[[publisher.winnow]] +version = "0.7.15" +when = "2026-03-05" +user-id = 6743 +user-login = "epage" +user-name = "Ed Page" + +[[publisher.zerocopy]] +version = "0.8.42" +when = "2026-03-09" +user-id = 7178 +user-login = "joshlf" +user-name = "Joshua Liebow-Feeser" + +[[publisher.zerocopy-derive]] +version = "0.8.42" +when = "2026-03-09" +user-id = 7178 +user-login = "joshlf" +user-name = "Joshua Liebow-Feeser" + +[[publisher.zmij]] +version = "1.0.21" +when = "2026-02-12" +user-id = 3618 +user-login = "dtolnay" +user-name = "David Tolnay" + +[[audits.OpenDevicePartnership.audits.bitfield-struct]] +who = "matteotullo " +criteria = "safe-to-deploy" +delta = "0.10.1 -> 0.12.1" +notes = "Adds hash and bitenum derives, mostly parsing and refactoring changes. No code execution nor writing to the filesystem." +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.defmt]] +who = "Felipe Balbi " +criteria = "safe-to-deploy" +version = "1.0.1" +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/mcxa-pac/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.defmt-macros]] +who = "Felipe Balbi " +criteria = "safe-to-deploy" +version = "1.0.1" +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/mcxa-pac/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.defmt-parser]] +who = "Felipe Balbi " +criteria = "safe-to-deploy" +version = "1.0.0" +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/mcxa-pac/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.embedded-batteries]] +who = "matteotullo " +criteria = "safe-to-deploy" +version = "0.3.4" +notes = "ODP crates are always trusted." +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.embedded-batteries-async]] +who = "matteotullo " +criteria = "safe-to-deploy" +version = "0.3.4" +notes = "ODP crates are always trusted." +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.embedded-hal]] +who = "Felipe Balbi " +criteria = "safe-to-deploy" +version = "0.2.7" +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/mcxa-pac/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.gimli]] +who = "Robert Zieba " +criteria = "safe-to-run" +version = "0.31.1" +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.itertools]] +who = "Robert Zieba " +criteria = "safe-to-deploy" +version = "0.10.5" +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.proc-macro-error-attr2]] +who = "Felipe Balbi " +criteria = "safe-to-deploy" +version = "2.0.0" +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/mcxa-pac/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.proc-macro-error2]] +who = "Felipe Balbi " +criteria = "safe-to-deploy" +version = "2.0.1" +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/mcxa-pac/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.serde]] +who = "Robert Zieba " +criteria = "safe-to-deploy" +version = "1.0.228" +notes = "Changes are mostly a reorganization of the internal module structure" +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.serde_core]] +who = "Robert Zieba " +criteria = "safe-to-deploy" +version = "1.0.226" +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.serde_derive]] +who = "Robert Zieba " +criteria = "safe-to-deploy" +version = "1.0.228" +notes = "Diff is clean-up in proc macros" +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.tokio]] +who = "Robert Zieba " +criteria = "safe-to-run" +version = "1.45.0" +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.tokio-macros]] +who = "Robert Zieba " +criteria = "safe-to-run" +version = "2.5.0" +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.windows-link]] +who = "Felipe Balbi " +criteria = "safe-to-run" +delta = "0.2.0 -> 0.2.1" +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-mcu/refs/heads/main/supply-chain/audits.toml" + +[[audits.bytecode-alliance.audits.addr2line]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.19.0 -> 0.20.0" +notes = "This version brings support for split-dwarf which while it uses the filesystem is always done at the behest of the caller, so everything is as expected for this update." + +[[audits.bytecode-alliance.audits.addr2line]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.20.0 -> 0.21.0" +notes = "This version bump updated some dependencies and optimized some internals. All looks good." + +[[audits.bytecode-alliance.audits.addr2line]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.21.0 -> 0.22.0" + +[[audits.bytecode-alliance.audits.addr2line]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.22.0 -> 0.24.1" +notes = "Lots of internal code refactorings and code movement. Nothing out of place however." + +[[audits.bytecode-alliance.audits.addr2line]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.24.1 -> 0.25.0" +notes = "All minor changes, even a net reduction of `unsafe`." + +[[audits.bytecode-alliance.audits.addr2line]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.25.0 -> 0.25.1" +notes = "Minor updates, looks like a minor bug fix, nothing awry." + +[[audits.bytecode-alliance.audits.embedded-io]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +version = "0.4.0" +notes = "No `unsafe` code and only uses `std` in ways one would expect the crate to do so." + +[[audits.bytecode-alliance.audits.embedded-io]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.4.0 -> 0.6.1" +notes = "Major updates, but almost all safe code. Lots of pruning/deletions, nothing out of the ordrinary." + +[[audits.bytecode-alliance.audits.gimli]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.31.1 -> 0.32.0" +notes = "Ever more DWARF to parse, but also no new `unsafe` and everything looks like gimli." + +[[audits.bytecode-alliance.audits.gimli]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.32.0 -> 0.32.3" +notes = "Ever more dwarf, it never ends! (nothing out of the ordinary)" + +[[audits.bytecode-alliance.audits.itertools]] +who = "Nick Fitzgerald " +criteria = "safe-to-deploy" +delta = "0.10.5 -> 0.12.1" +notes = """ +Minimal `unsafe` usage. Few blocks that existed looked reasonable. Does what it +says on the tin: lots of iterators. +""" + +[[audits.bytecode-alliance.audits.itertools]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.12.1 -> 0.14.0" +notes = """ +Lots of new iterators and shuffling some things around. Some new unsafe code but +it's well-documented and well-tested. Nothing suspicious. +""" + +[[audits.bytecode-alliance.audits.miniz_oxide]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +version = "0.7.1" +notes = """ +This crate is a Rust implementation of zlib compression/decompression and has +been used by default by the Rust standard library for quite some time. It's also +a default dependency of the popular `backtrace` crate for decompressing debug +information. This crate forbids unsafe code and does not otherwise access system +resources. It's originally a port of the `miniz.c` library as well, and given +its own longevity should be relatively hardened against some of the more common +compression-related issues. +""" + +[[audits.bytecode-alliance.audits.miniz_oxide]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.7.1 -> 0.8.0" +notes = "Minor updates, using new Rust features like `const`, no major changes." + +[[audits.bytecode-alliance.audits.miniz_oxide]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.8.0 -> 0.8.5" +notes = """ +Lots of small updates here and there, for example around modernizing Rust +idioms. No new `unsafe` code and everything looks like what you'd expect a +compression library to be doing. +""" + +[[audits.bytecode-alliance.audits.miniz_oxide]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.8.5 -> 0.8.9" +notes = "No new unsafe code, just refactorings." + +[[audits.bytecode-alliance.audits.percent-encoding]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +version = "2.2.0" +notes = """ +This crate is a single-file crate that does what it says on the tin. There are +a few `unsafe` blocks related to utf-8 validation which are locally verifiable +as correct and otherwise this crate is good to go. +""" + +[[audits.google.audits.addr2line]] +who = "George Burgess IV " +criteria = "safe-to-run" +version = "0.19.0" +aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT" + +[[audits.google.audits.adler2]] +who = "Lukasz Anforowicz " +criteria = "safe-to-deploy" +version = "2.0.0" +notes = ''' +This audit has been reviewed in https://crrev.com/c/5811890 + +The crate is fairly easy to read thanks to its small size and rich comments. + +I've grepped for `-i cipher`, `-i crypto`, `\bfs\b`, `\bnet\b`, and +`\bunsafe\b`. There were no hits (except for a comment in `README.md` +and `lib.rs` pointing out "Zero `unsafe`"). +''' +aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" + +[[audits.google.audits.autocfg]] +who = "Manish Goregaokar " +criteria = "safe-to-deploy" +version = "1.4.0" +notes = "Contains no unsafe" +aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" + +[[audits.google.audits.bitflags]] +who = "Lukasz Anforowicz " +criteria = "safe-to-deploy" +version = "1.3.2" +notes = """ +Security review of earlier versions of the crate can be found at +(Google-internal, sorry): go/image-crate-chromium-security-review + +The crate exposes a function marked as `unsafe`, but doesn't use any +`unsafe` blocks (except for tests of the single `unsafe` function). I +think this justifies marking this crate as `ub-risk-1`. + +Additional review comments can be found at https://crrev.com/c/4723145/31 +""" +aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" + +[[audits.google.audits.either]] +who = "Manish Goregaokar " +criteria = "safe-to-deploy" +version = "1.13.0" +notes = "Unsafe code pertaining to wrapping Pin APIs. Mostly passes invariants down." +aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" + +[[audits.google.audits.either]] +who = "Daniel Cheng " +criteria = "safe-to-deploy" +delta = "1.13.0 -> 1.14.0" +notes = """ +Inheriting ub-risk-1 from the baseline review of 1.13.0. While the delta has some diffs in unsafe code, they are either: +- migrating code to use helper macros +- migrating match patterns to take advantage of default bindings mode from RFC 2005 +Either way, the result is code that does exactly the same thing and does not change the risk of UB. + +See https://crrev.com/c/6323164 for more audit details. +""" +aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" + +[[audits.google.audits.either]] +who = "Lukasz Anforowicz " +criteria = "safe-to-deploy" +delta = "1.14.0 -> 1.15.0" +notes = 'The delta in `lib.rs` only tweaks doc comments and `#[cfg(feature = "std")]`.' +aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" + +[[audits.google.audits.nb]] +who = "George Burgess IV " +criteria = "safe-to-deploy" +version = "1.0.0" +aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT" + +[[audits.google.audits.nb]] +who = "George Burgess IV " +criteria = "safe-to-deploy" +delta = "1.0.0 -> 0.1.3" +aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT" + +[[audits.google.audits.nb]] +who = "George Burgess IV " +criteria = "safe-to-deploy" +delta = "1.0.0 -> 1.1.0" +aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT" + +[[audits.google.audits.num-integer]] +who = "Manish Goregaokar " +criteria = "safe-to-deploy" +version = "0.1.46" +notes = "Contains no unsafe" +aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" + +[[audits.google.audits.num-traits]] +who = "Manish Goregaokar " +criteria = "safe-to-deploy" +version = "0.2.19" +notes = "Contains a single line of float-to-int unsafe with decent safety comments" +aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" + +[[audits.google.audits.pin-project-lite]] +who = "ChromeOS" +criteria = "safe-to-run" +version = "0.2.9" +aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT" + +[[audits.google.audits.pin-project-lite]] +who = "David Koloski " +criteria = "safe-to-deploy" +delta = "0.2.9 -> 0.2.13" +notes = "Audited at https://fxrev.dev/946396" +aggregated-from = "https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/third_party/rust_crates/supply-chain/audits.toml?format=TEXT" + +[[audits.google.audits.void]] +who = "George Burgess IV " +criteria = "safe-to-deploy" +version = "1.0.2" +aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT" + +[[audits.mozilla.wildcard-audits.encoding_rs]] +who = "Henri Sivonen " +criteria = "safe-to-deploy" +user-id = 4484 # Henri Sivonen (hsivonen) +start = "2019-02-26" +end = "2025-10-23" +notes = "I, Henri Sivonen, wrote encoding_rs for Gecko and have reviewed contributions by others. There are two caveats to the certification: 1) The crate does things that are documented to be UB but that do not appear to actually be UB due to integer types differing from the general rule; https://github.com/hsivonen/encoding_rs/issues/79 . 2) It would be prudent to re-review the code that reinterprets buffers of integers as SIMD vectors; see https://github.com/hsivonen/encoding_rs/issues/87 ." +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.wildcard-audits.unicode-segmentation]] +who = "Manish Goregaokar " +criteria = "safe-to-deploy" +user-id = 1139 # Manish Goregaokar (Manishearth) +start = "2019-05-15" +end = "2026-02-01" +notes = "All code written or reviewed by Manish" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.arraydeque]] +who = "Lars Eggert " +criteria = "safe-to-deploy" +version = "0.5.1" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.askama]] +who = "Ben Dean-Kawamura " +criteria = "safe-to-deploy" +version = "0.13.1" +notes = """ +Template crate. This is only used to generate the Rust/JS code for UniFFI. + +We used to use askama, then we switched to rinja which was a fork. Now rinja and +askama have merged again. + +The differences from askama 0.12, are pretty straightforward and don't seem risky to me. There's +some unsafe code and macros, but nothing that complicated. +""" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.askama]] +who = "Jan-Erik Rediger " +criteria = "safe-to-deploy" +delta = "0.13.1 -> 0.14.0" +aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" + +[[audits.mozilla.audits.askama_derive]] +who = "Ben Dean-Kawamura " +criteria = "safe-to-deploy" +version = "0.13.1" +notes = """ +Template crate. This is only used to generate the Rust/JS code for UniFFI. + +We used to use askama, then we switched to rinja which was a fork. Now rinja and +askama have merged again. + +I did a quick scan of the current code and couldn't find any issues. +""" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.askama_derive]] +who = "Jan-Erik Rediger " +criteria = "safe-to-deploy" +delta = "0.13.1 -> 0.14.0" +aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" + +[[audits.mozilla.audits.askama_parser]] +who = "Ben Dean-Kawamura " +criteria = "safe-to-deploy" +version = "0.13.0" +notes = """ +Template crate. This is only used to generate the Rust/JS code for UniFFI. + +We used to use askama, then we switched to rinja which was a fork. Now rinja and +askama have merged again. + +I did a quick scan of the current code and couldn't find any issues. +""" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.askama_parser]] +who = "Jan-Erik Rediger " +criteria = "safe-to-deploy" +delta = "0.13.0 -> 0.14.0" +aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" + +[[audits.mozilla.audits.percent-encoding]] +who = "Valentin Gosu " +criteria = "safe-to-deploy" +delta = "2.2.0 -> 2.3.0" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.percent-encoding]] +who = "Valentin Gosu " +criteria = "safe-to-deploy" +delta = "2.3.0 -> 2.3.1" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.percent-encoding]] +who = "edgul " +criteria = "safe-to-deploy" +delta = "2.3.1 -> 2.3.2" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.pin-project-lite]] +who = "Mike Hommey " +criteria = "safe-to-deploy" +delta = "0.2.13 -> 0.2.14" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.pin-project-lite]] +who = "Nika Layzell " +criteria = "safe-to-deploy" +delta = "0.2.14 -> 0.2.16" +notes = """ +Only functional change is to work around a bug in the negative_impls feature +(https://github.com/taiki-e/pin-project/issues/340#issuecomment-2432146009) +""" +aggregated-from = "https://raw.githubusercontent.com/mozilla/cargo-vet/main/supply-chain/audits.toml" + +[[audits.mozilla.audits.rustc-hash]] +who = "Bobby Holley " +criteria = "safe-to-deploy" +version = "1.1.0" +notes = "Straightforward crate with no unsafe code, does what it says on the tin." +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.rustc-hash]] +who = "Ben Dean-Kawamura " +criteria = "safe-to-deploy" +delta = "1.1.0 -> 2.1.1" +notes = "Simple hashing crate, no unsafe code." +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.serde_core]] +who = "Erich Gubler " +criteria = "safe-to-deploy" +delta = "1.0.226 -> 1.0.227" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.serde_core]] +who = "Jan-Erik Rediger " +criteria = "safe-to-deploy" +delta = "1.0.227 -> 1.0.228" +aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" + +[[audits.mozilla.audits.windows-link]] +who = "Mark Hammond " +criteria = "safe-to-deploy" +version = "0.1.1" +notes = "A microsoft crate allowing unsafe calls to windows apis." +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.mozilla.audits.windows-link]] +who = "Erich Gubler " +criteria = "safe-to-deploy" +delta = "0.1.1 -> 0.2.0" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + +[[audits.zcash.audits.adler2]] +who = "Jack Grigg " +criteria = "safe-to-deploy" +delta = "2.0.0 -> 2.0.1" +aggregated-from = "https://raw.githubusercontent.com/zcash/zcash/master/qa/supply-chain/audits.toml" + +[[audits.zcash.audits.autocfg]] +who = "Jack Grigg " +criteria = "safe-to-deploy" +delta = "1.4.0 -> 1.5.0" +notes = "Filesystem change is to remove the generated LLVM IR output file after probing." +aggregated-from = "https://raw.githubusercontent.com/zcash/zcash/master/qa/supply-chain/audits.toml" From 94f32ab6d6e796caddae90a358bb32723a6810b7 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 27 Apr 2026 10:22:40 -0700 Subject: [PATCH 11/11] Fix workflows --- .github/workflows/check.yml | 2 +- .github/workflows/device-driver.yml | 2 +- supply-chain/audits.toml | 8 +- supply-chain/config.toml | 76 ------ supply-chain/imports.lock | 366 ++++------------------------ 5 files changed, 48 insertions(+), 406 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 8f2b035..42d8b74 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -141,7 +141,7 @@ jobs: strategy: fail-fast: false matrix: - msrv: ["1.85"] + msrv: ["1.88"] name: ubuntu / ${{ matrix.msrv }} steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/device-driver.yml b/.github/workflows/device-driver.yml index 153ae5c..9c7befe 100644 --- a/.github/workflows/device-driver.yml +++ b/.github/workflows/device-driver.yml @@ -22,7 +22,7 @@ jobs: with: crate: device-driver-cli - name: Generate device.rs from INA4230.toml - run: device-driver-cli --manifest ina4230.toml --device-name Device -o ci_gen.rs + run: device-driver-cli --manifest INA4230.toml --device-name Device -o ci_gen.rs - name: Format generated file run: rustfmt --edition 2024 ci_gen.rs - name: Check generated file matches committed src/device.rs diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index 44d2132..d4e5fa2 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -60,7 +60,7 @@ end = "2027-03-13" [[trusted.bitflags]] criteria = "safe-to-deploy" -user-id = 3204 # Ashley Mannix (KodrAus) +user-id = 3204 start = "2019-05-02" end = "2027-03-13" @@ -174,19 +174,19 @@ end = "2027-03-13" [[trusted.winnow]] criteria = "safe-to-deploy" -user-id = 6743 # Ed Page (epage) +user-id = 6743 start = "2023-02-22" end = "2027-03-13" [[trusted.zerocopy]] criteria = "safe-to-deploy" -user-id = 7178 # Joshua Liebow-Feeser (joshlf) +user-id = 7178 start = "2019-02-28" end = "2027-03-13" [[trusted.zerocopy-derive]] criteria = "safe-to-deploy" -user-id = 7178 # Joshua Liebow-Feeser (joshlf) +user-id = 7178 start = "2019-02-28" end = "2027-03-13" diff --git a/supply-chain/config.toml b/supply-chain/config.toml index e269b65..582523d 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -19,42 +19,10 @@ url = "https://raw.githubusercontent.com/mozilla/supply-chain/main/audits.toml" [imports.zcash] url = "https://raw.githubusercontent.com/zcash/rust-ecosystem/main/supply-chain/audits.toml" -[[exemptions.ahash]] -version = "0.8.12" -criteria = "safe-to-deploy" - -[[exemptions.bitvec]] -version = "1.0.1" -criteria = "safe-to-deploy" - -[[exemptions.convert_case]] -version = "0.6.0" -criteria = "safe-to-deploy" - -[[exemptions.defmt]] -version = "0.3.100" -criteria = "safe-to-deploy" - -[[exemptions.embedded-hal]] -version = "1.0.0" -criteria = "safe-to-deploy" - -[[exemptions.embedded-hal-async]] -version = "1.0.0" -criteria = "safe-to-deploy" - [[exemptions.embedded-hal-mock]] version = "0.11.1" criteria = "safe-to-run" -[[exemptions.embedded-hal-nb]] -version = "1.0.0" -criteria = "safe-to-run" - -[[exemptions.embedded-io-async]] -version = "0.6.1" -criteria = "safe-to-deploy" - [[exemptions.embedded-sensors-hal]] version = "0.1.1" criteria = "safe-to-deploy" @@ -67,22 +35,6 @@ criteria = "safe-to-deploy" version = "0.12.1" criteria = "safe-to-run" -[[exemptions.funty]] -version = "2.0.0" -criteria = "safe-to-deploy" - -[[exemptions.hashbrown]] -version = "0.14.5" -criteria = "safe-to-deploy" - -[[exemptions.hashlink]] -version = "0.9.1" -criteria = "safe-to-deploy" - -[[exemptions.libc]] -version = "0.2.186" -criteria = "safe-to-run" - [[exemptions.num]] version = "0.3.1" criteria = "safe-to-run" @@ -91,38 +43,10 @@ criteria = "safe-to-run" version = "0.3.1" criteria = "safe-to-run" -[[exemptions.num-iter]] -version = "0.1.45" -criteria = "safe-to-run" - [[exemptions.num-rational]] version = "0.3.2" criteria = "safe-to-run" -[[exemptions.once_cell]] -version = "1.21.3" -criteria = "safe-to-deploy" - [[exemptions.paste]] version = "1.0.15" criteria = "safe-to-deploy" - -[[exemptions.radium]] -version = "0.7.0" -criteria = "safe-to-deploy" - -[[exemptions.tap]] -version = "1.0.1" -criteria = "safe-to-deploy" - -[[exemptions.version_check]] -version = "0.9.5" -criteria = "safe-to-deploy" - -[[exemptions.wyz]] -version = "0.5.1" -criteria = "safe-to-deploy" - -[[exemptions.yaml-rust2]] -version = "0.9.0" -criteria = "safe-to-deploy" diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock index 9c05555..b9a6c15 100644 --- a/supply-chain/imports.lock +++ b/supply-chain/imports.lock @@ -1,39 +1,18 @@ # cargo-vet imports lock -[[publisher.anyhow]] -version = "1.0.102" -when = "2026-02-20" -user-id = 3618 -user-login = "dtolnay" -user-name = "David Tolnay" - [[publisher.backtrace]] version = "0.3.76" when = "2025-09-26" user-id = 55123 user-login = "rust-lang-owner" -[[publisher.bitflags]] -version = "2.11.0" -when = "2026-02-14" -user-id = 3204 -user-login = "KodrAus" -user-name = "Ashley Mannix" - [[publisher.cfg-if]] version = "1.0.4" when = "2025-10-15" user-id = 55123 user-login = "rust-lang-owner" -[[publisher.dd-manifest-tree]] -version = "1.0.0" -when = "2024-12-28" -user-id = 85562 -user-login = "diondokter" -user-name = "Dion Dokter" - [[publisher.device-driver]] version = "1.0.8" when = "2026-03-06" @@ -41,37 +20,9 @@ user-id = 85562 user-login = "diondokter" user-name = "Dion Dokter" -[[publisher.device-driver-generation]] -version = "1.0.8" -when = "2026-03-06" -user-id = 85562 -user-login = "diondokter" -user-name = "Dion Dokter" - -[[publisher.device-driver-macros]] -version = "1.0.8" -when = "2026-03-06" -user-id = 85562 -user-login = "diondokter" -user-name = "Dion Dokter" - -[[publisher.encoding_rs]] -version = "0.8.35" -when = "2024-10-24" -user-id = 4484 -user-login = "hsivonen" -user-name = "Henri Sivonen" - -[[publisher.itoa]] -version = "1.0.17" -when = "2025-12-27" -user-id = 3618 -user-login = "dtolnay" -user-name = "David Tolnay" - [[publisher.libc]] -version = "0.2.183" -when = "2026-03-08" +version = "0.2.186" +when = "2026-04-23" user-id = 55123 user-login = "rust-lang-owner" @@ -89,13 +40,6 @@ user-id = 4415 user-login = "philipc" user-name = "Philip Craig" -[[publisher.prettyplease]] -version = "0.2.37" -when = "2025-08-19" -user-id = 3618 -user-login = "dtolnay" -user-name = "David Tolnay" - [[publisher.proc-macro2]] version = "1.0.106" when = "2026-01-21" @@ -116,13 +60,6 @@ when = "2026-01-15" user-id = 55123 user-login = "rust-lang-owner" -[[publisher.serde_json]] -version = "1.0.149" -when = "2026-01-06" -user-id = 3618 -user-login = "dtolnay" -user-name = "David Tolnay" - [[publisher.syn]] version = "2.0.117" when = "2026-02-20" @@ -151,46 +88,11 @@ user-id = 3618 user-login = "dtolnay" user-name = "David Tolnay" -[[publisher.unicode-segmentation]] -version = "1.12.0" -when = "2024-09-13" -user-id = 1139 -user-login = "Manishearth" -user-name = "Manish Goregaokar" - -[[publisher.winnow]] -version = "0.7.15" -when = "2026-03-05" -user-id = 6743 -user-login = "epage" -user-name = "Ed Page" - -[[publisher.zerocopy]] -version = "0.8.42" -when = "2026-03-09" -user-id = 7178 -user-login = "joshlf" -user-name = "Joshua Liebow-Feeser" - -[[publisher.zerocopy-derive]] -version = "0.8.42" -when = "2026-03-09" -user-id = 7178 -user-login = "joshlf" -user-name = "Joshua Liebow-Feeser" - -[[publisher.zmij]] -version = "1.0.21" -when = "2026-02-12" -user-id = 3618 -user-login = "dtolnay" -user-name = "David Tolnay" - -[[audits.OpenDevicePartnership.audits.bitfield-struct]] -who = "matteotullo " +[[audits.OpenDevicePartnership.audits.defmt]] +who = "Jerry Xie " criteria = "safe-to-deploy" -delta = "0.10.1 -> 0.12.1" -notes = "Adds hash and bitenum derives, mostly parsing and refactoring changes. No code execution nor writing to the filesystem." +version = "0.3.100" +notes = "Compatibility shim: no_std crate that re-exports defmt 1.x items for 0.3 API compatibility. No unsafe code, no build script, no powerful imports, no logic - pure pub-use re-exports. Assisted-by: copilot-cli:claude-opus-4.6 cargo-vet" aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" [[audits.OpenDevicePartnership.audits.defmt]] @@ -211,25 +113,39 @@ criteria = "safe-to-deploy" version = "1.0.0" aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/mcxa-pac/refs/heads/main/supply-chain/audits.toml" -[[audits.OpenDevicePartnership.audits.embedded-batteries]] -who = "matteotullo " +[[audits.OpenDevicePartnership.audits.embedded-hal]] +who = "Felipe Balbi " +criteria = "safe-to-deploy" +version = "0.2.7" +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/mcxa-pac/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.embedded-hal]] +who = "Jerry Xie " criteria = "safe-to-deploy" -version = "0.3.4" -notes = "ODP crates are always trusted." +delta = "0.2.7 -> 1.0.0" +notes = "Pure no_std trait crate. Complete API redesign for 1.0: removed nb-based traits, CAN module, all unsafe code. Only defines traits/enums/types for digital, I2C, SPI, PWM, delay. No build script, no proc macros, no powerful imports. Assisted-by: copilot-cli:claude-opus-4.6 cargo-vet" aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" -[[audits.OpenDevicePartnership.audits.embedded-batteries-async]] -who = "matteotullo " +[[audits.OpenDevicePartnership.audits.embedded-hal-async]] +who = "Jerry Xie " criteria = "safe-to-deploy" -version = "0.3.4" -notes = "ODP crates are always trusted." +version = "1.0.0" +notes = "no_std async HAL trait definitions. No unsafe in library. Build script only runs rustc --version. Assisted-by: copilot-cli:claude-opus-4.6 cargo-vet" aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" -[[audits.OpenDevicePartnership.audits.embedded-hal]] -who = "Felipe Balbi " +[[audits.OpenDevicePartnership.audits.embedded-hal-nb]] +who = "Jerry Xie " criteria = "safe-to-deploy" -version = "0.2.7" -aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/mcxa-pac/refs/heads/main/supply-chain/audits.toml" +version = "1.0.0" +notes = "no_std trait-only crate. No unsafe, no build script, no proc macros, no powerful imports. Assisted-by: copilot-cli:claude-opus-4.6 cargo-vet" +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" + +[[audits.OpenDevicePartnership.audits.embedded-io-async]] +who = "Jerry Xie " +criteria = "safe-to-deploy" +version = "0.6.1" +notes = "No unsafe. Build script only detects nightly via rustc --version. Pure async trait definitions for embedded I/O. Assisted-by: copilot-cli:claude-opus-4.6 cargo-vet" +aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" [[audits.OpenDevicePartnership.audits.gimli]] who = "Robert Zieba " @@ -237,10 +153,11 @@ criteria = "safe-to-run" version = "0.31.1" aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" -[[audits.OpenDevicePartnership.audits.itertools]] -who = "Robert Zieba " +[[audits.OpenDevicePartnership.audits.num-iter]] +who = "Jerry Xie " criteria = "safe-to-deploy" -version = "0.10.5" +delta = "0.1.43 -> 0.1.45" +notes = "Delta audit: edition upgrade to 2018, MSRV 1.31, build.rs removed, i128 now unconditional, DoubleEndedIterator uses Integer::dec(). No unsafe, no powerful imports, no_std only. Assisted-by: copilot-cli:claude-opus-4.6 cargo-vet" aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" [[audits.OpenDevicePartnership.audits.proc-macro-error-attr2]] @@ -255,26 +172,6 @@ criteria = "safe-to-deploy" version = "2.0.1" aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/mcxa-pac/refs/heads/main/supply-chain/audits.toml" -[[audits.OpenDevicePartnership.audits.serde]] -who = "Robert Zieba " -criteria = "safe-to-deploy" -version = "1.0.228" -notes = "Changes are mostly a reorganization of the internal module structure" -aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" - -[[audits.OpenDevicePartnership.audits.serde_core]] -who = "Robert Zieba " -criteria = "safe-to-deploy" -version = "1.0.226" -aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" - -[[audits.OpenDevicePartnership.audits.serde_derive]] -who = "Robert Zieba " -criteria = "safe-to-deploy" -version = "1.0.228" -notes = "Diff is clean-up in proc macros" -aggregated-from = "https://raw.githubusercontent.com/OpenDevicePartnership/embedded-services/refs/heads/main/supply-chain/audits.toml" - [[audits.OpenDevicePartnership.audits.tokio]] who = "Robert Zieba " criteria = "safe-to-run" @@ -352,24 +249,6 @@ criteria = "safe-to-deploy" delta = "0.32.0 -> 0.32.3" notes = "Ever more dwarf, it never ends! (nothing out of the ordinary)" -[[audits.bytecode-alliance.audits.itertools]] -who = "Nick Fitzgerald " -criteria = "safe-to-deploy" -delta = "0.10.5 -> 0.12.1" -notes = """ -Minimal `unsafe` usage. Few blocks that existed looked reasonable. Does what it -says on the tin: lots of iterators. -""" - -[[audits.bytecode-alliance.audits.itertools]] -who = "Alex Crichton " -criteria = "safe-to-deploy" -delta = "0.12.1 -> 0.14.0" -notes = """ -Lots of new iterators and shuffling some things around. Some new unsafe code but -it's well-documented and well-tested. Nothing suspicious. -""" - [[audits.bytecode-alliance.audits.miniz_oxide]] who = "Alex Crichton " criteria = "safe-to-deploy" @@ -406,16 +285,6 @@ criteria = "safe-to-deploy" delta = "0.8.5 -> 0.8.9" notes = "No new unsafe code, just refactorings." -[[audits.bytecode-alliance.audits.percent-encoding]] -who = "Alex Crichton " -criteria = "safe-to-deploy" -version = "2.2.0" -notes = """ -This crate is a single-file crate that does what it says on the tin. There are -a few `unsafe` blocks related to utf-8 validation which are locally verifiable -as correct and otherwise this crate is good to go. -""" - [[audits.google.audits.addr2line]] who = "George Burgess IV " criteria = "safe-to-run" @@ -460,34 +329,6 @@ Additional review comments can be found at https://crrev.com/c/4723145/31 """ aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" -[[audits.google.audits.either]] -who = "Manish Goregaokar " -criteria = "safe-to-deploy" -version = "1.13.0" -notes = "Unsafe code pertaining to wrapping Pin APIs. Mostly passes invariants down." -aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" - -[[audits.google.audits.either]] -who = "Daniel Cheng " -criteria = "safe-to-deploy" -delta = "1.13.0 -> 1.14.0" -notes = """ -Inheriting ub-risk-1 from the baseline review of 1.13.0. While the delta has some diffs in unsafe code, they are either: -- migrating code to use helper macros -- migrating match patterns to take advantage of default bindings mode from RFC 2005 -Either way, the result is code that does exactly the same thing and does not change the risk of UB. - -See https://crrev.com/c/6323164 for more audit details. -""" -aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" - -[[audits.google.audits.either]] -who = "Lukasz Anforowicz " -criteria = "safe-to-deploy" -delta = "1.14.0 -> 1.15.0" -notes = 'The delta in `lib.rs` only tweaks doc comments and `#[cfg(feature = "std")]`.' -aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" - [[audits.google.audits.nb]] who = "George Burgess IV " criteria = "safe-to-deploy" @@ -513,6 +354,12 @@ version = "0.1.46" notes = "Contains no unsafe" aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" +[[audits.google.audits.num-iter]] +who = "George Burgess IV " +criteria = "safe-to-deploy" +version = "0.1.43" +aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT" + [[audits.google.audits.num-traits]] who = "Manish Goregaokar " criteria = "safe-to-deploy" @@ -539,109 +386,6 @@ criteria = "safe-to-deploy" version = "1.0.2" aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT" -[[audits.mozilla.wildcard-audits.encoding_rs]] -who = "Henri Sivonen " -criteria = "safe-to-deploy" -user-id = 4484 # Henri Sivonen (hsivonen) -start = "2019-02-26" -end = "2025-10-23" -notes = "I, Henri Sivonen, wrote encoding_rs for Gecko and have reviewed contributions by others. There are two caveats to the certification: 1) The crate does things that are documented to be UB but that do not appear to actually be UB due to integer types differing from the general rule; https://github.com/hsivonen/encoding_rs/issues/79 . 2) It would be prudent to re-review the code that reinterprets buffers of integers as SIMD vectors; see https://github.com/hsivonen/encoding_rs/issues/87 ." -aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" - -[[audits.mozilla.wildcard-audits.unicode-segmentation]] -who = "Manish Goregaokar " -criteria = "safe-to-deploy" -user-id = 1139 # Manish Goregaokar (Manishearth) -start = "2019-05-15" -end = "2026-02-01" -notes = "All code written or reviewed by Manish" -aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" - -[[audits.mozilla.audits.arraydeque]] -who = "Lars Eggert " -criteria = "safe-to-deploy" -version = "0.5.1" -aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" - -[[audits.mozilla.audits.askama]] -who = "Ben Dean-Kawamura " -criteria = "safe-to-deploy" -version = "0.13.1" -notes = """ -Template crate. This is only used to generate the Rust/JS code for UniFFI. - -We used to use askama, then we switched to rinja which was a fork. Now rinja and -askama have merged again. - -The differences from askama 0.12, are pretty straightforward and don't seem risky to me. There's -some unsafe code and macros, but nothing that complicated. -""" -aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" - -[[audits.mozilla.audits.askama]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -delta = "0.13.1 -> 0.14.0" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - -[[audits.mozilla.audits.askama_derive]] -who = "Ben Dean-Kawamura " -criteria = "safe-to-deploy" -version = "0.13.1" -notes = """ -Template crate. This is only used to generate the Rust/JS code for UniFFI. - -We used to use askama, then we switched to rinja which was a fork. Now rinja and -askama have merged again. - -I did a quick scan of the current code and couldn't find any issues. -""" -aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" - -[[audits.mozilla.audits.askama_derive]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -delta = "0.13.1 -> 0.14.0" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - -[[audits.mozilla.audits.askama_parser]] -who = "Ben Dean-Kawamura " -criteria = "safe-to-deploy" -version = "0.13.0" -notes = """ -Template crate. This is only used to generate the Rust/JS code for UniFFI. - -We used to use askama, then we switched to rinja which was a fork. Now rinja and -askama have merged again. - -I did a quick scan of the current code and couldn't find any issues. -""" -aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" - -[[audits.mozilla.audits.askama_parser]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -delta = "0.13.0 -> 0.14.0" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - -[[audits.mozilla.audits.percent-encoding]] -who = "Valentin Gosu " -criteria = "safe-to-deploy" -delta = "2.2.0 -> 2.3.0" -aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" - -[[audits.mozilla.audits.percent-encoding]] -who = "Valentin Gosu " -criteria = "safe-to-deploy" -delta = "2.3.0 -> 2.3.1" -aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" - -[[audits.mozilla.audits.percent-encoding]] -who = "edgul " -criteria = "safe-to-deploy" -delta = "2.3.1 -> 2.3.2" -aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" - [[audits.mozilla.audits.pin-project-lite]] who = "Mike Hommey " criteria = "safe-to-deploy" @@ -658,32 +402,6 @@ Only functional change is to work around a bug in the negative_impls feature """ aggregated-from = "https://raw.githubusercontent.com/mozilla/cargo-vet/main/supply-chain/audits.toml" -[[audits.mozilla.audits.rustc-hash]] -who = "Bobby Holley " -criteria = "safe-to-deploy" -version = "1.1.0" -notes = "Straightforward crate with no unsafe code, does what it says on the tin." -aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" - -[[audits.mozilla.audits.rustc-hash]] -who = "Ben Dean-Kawamura " -criteria = "safe-to-deploy" -delta = "1.1.0 -> 2.1.1" -notes = "Simple hashing crate, no unsafe code." -aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" - -[[audits.mozilla.audits.serde_core]] -who = "Erich Gubler " -criteria = "safe-to-deploy" -delta = "1.0.226 -> 1.0.227" -aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" - -[[audits.mozilla.audits.serde_core]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -delta = "1.0.227 -> 1.0.228" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - [[audits.mozilla.audits.windows-link]] who = "Mark Hammond " criteria = "safe-to-deploy"