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 new file mode 100644 index 0000000..9c7befe --- /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..bdce83e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,5 +3,453 @@ version = 4 [[package]] -name = "embedded-rust-template" +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" +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 = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + +[[package]] +name = "ina4230" version = "0.1.0" +dependencies = [ + "defmt 1.0.1", + "device-driver", + "embedded-hal-async", + "embedded-hal-mock", + "embedded-sensors-hal-async", + "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" +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 = "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" +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 = "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" +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.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +dependencies = [ + "backtrace", + "pin-project-lite", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +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" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" diff --git a/Cargo.toml b/Cargo.toml index 71c4806..9bb130e 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" +rust-version = "1.88" [dependencies] -# dependencies for all targets +device-driver = { version = "1.0.7", default-features = false } +defmt = { version = "1.0", 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.45.0", features = ["rt", "macros"] } + + + +[lints.rust] +unsafe_code = "deny" +missing_docs = "deny" [lints.clippy] -suspicious = "forbid" correctness = "forbid" +suspicious = "forbid" perf = "forbid" style = "forbid" +pedantic = "deny" + +[features] +defmt = [ + "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..592c962 --- /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" +# ============================================================ +# 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..21b9bd8 100644 --- a/README.md +++ b/README.md @@ -1,63 +1,242 @@ -# 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) +- 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` 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" +``` + +```rust,ignore +use ina4230::{AddrPinState, AdcRange, Channel, Ina4230}; -To temporarily analyze code for the host platform instead, you can remove the `rust-analyzer.cargo.target` setting. +// i2c implements embedded_hal_async::i2c::I2c +// 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); -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. +// Reset, then calibrate each channel before taking measurements +sensor.reset().await?; +sensor.calibrate(Channel::Ch1, CURRENT_LSB_CH1, SHUNT_OHMS_CH1, AdcRange::Range0).await?; -3. **Cargo Configuration**: If needed, you can add target-specific configuration in a `.cargo/config.toml` file. +// Wait for conversion +while !sensor.conversion_ready().await? {} -### Converting from Binary to 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?; +``` -To convert this project from a binary to a library: +## Configuration -1. **Cargo.toml**: Update your project structure: - ```toml - [lib] - name = "your_library_name" - ``` +Before taking measurements, two hardware-specific parameters must be set per channel. -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 +### Shunt Resistor Value -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 - ``` +Set `SHUNT_OHMS_CHx` to the resistance of the shunt resistor fitted on that channel, in ohms: -### Project Dependencies +```rust +const SHUNT_OHMS_CH1: f32 = 0.010; // 10 mΩ shunt on channel 1 +``` -Update the dependencies in `Cargo.toml` based on your target platform: +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. -```toml -[dependencies] -# Common dependencies for all targets +### 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. + +Set `MAX_CURRENT_CHx` to the maximum current you expect on that channel — the +driver calculates the optimal `CURRENT_LSB` automatically: + +```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 +``` + +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 +``` + +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, 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 +``` + +### 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. +Each channel is calibrated independently: -[target.'cfg(target_os = "none")'.dependencies] -# Dependencies for no-std targets +```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?; +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,ignore +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,ignore +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,ignore +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,ignore +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 two `AddrPinState` values to `Ina4230::new()` — the first for A0, the +second for A1: + +```rust,ignore +// 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); +``` + +All 16 address combinations (per datasheet Table 6-1): + +| A0 | A1 | Address | +|-----|-----|---------| +| GND | GND | `0x40` | +| 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` + +```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..655ac21 --- /dev/null +++ b/src/device.rs @@ -0,0 +1,5865 @@ +/// 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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")] + 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", 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", 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", 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", 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", 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", 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", 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..41f563c --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,814 @@ +//! 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::*; + +/// 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", derive(defmt::Format))] +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 | Self::EnergyOverflow(_) => sensor::ErrorKind::Saturated, + } + } +} + +// ── 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. + 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) + } +} + +// ── 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 { + /// Address pin tied to GND (default). + #[default] + Gnd, + /// Address pin tied to VS. + Vs, + /// Address pin tied to SDA. + Sda, + /// Address pin tied to SCL. + Scl, +} + +/// Trait for converting an (A0, A1) pair of address pin states into +/// the corresponding I²C address. +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) => 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, + } + } +} + +// ── Channel ─────────────────────────────────────────────────────────────────── + +/// One of the four measurement channels on the INA4230. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(usize)] +pub enum Channel { + /// Channel 1 + Ch1 = 0, + /// Channel 2 + Ch2 = 1, + /// Channel 3 + Ch3 = 2, + /// Channel 4 + Ch4 = 3, +} + +impl Channel { + fn to_bit(self) -> u8 { + match self { + Channel::Ch1 => 0b0001, + Channel::Ch2 => 0b0010, + Channel::Ch3 => 0b0100, + Channel::Ch4 => 0b1000, + } + } +} + +// ── ADC Range ───────────────────────────────────────────────────────────────── + +/// ADC full-scale input range for shunt voltage measurement. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", 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, +} + +// ── 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. + 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. + 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. + /// + /// `a0` and `a1` select the I²C address via the pin strapping on the device. + pub fn new(i2c: I2c, a0: AddrPinState, a1: AddrPinState) -> Self { + Self { + device: Device::new(DeviceInterface { + i2c, + address: (a0, a1).to_address(), + }), + current_lsb_a: [None; 4], + adc_range: [AdcRange::Range0; 4], + } + } + + /// 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. + /// + /// # 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`. + /// + /// # 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 + .config_1() + .modify_async(|w| { + let mut active_channels = w.active_channel(); + if active { + active_channels |= bit; + } else { + 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() { + 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. + /// + /// - `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` + /// + /// # Errors + /// + /// Returns [`Ina4230Error::Bus`] if an I²C bus error occurs. + pub async fn calibrate( + &mut self, + channel: Channel, + current_lsb_a: f32, + shunt_ohms: f32, + adc_range: AdcRange, + ) -> Result<(), Ina4230Error> { + 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, + AdcRange::Range1 => range |= bit, + } + 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 + } + 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. + /// + /// 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() + .zip(params.iter()) + { + 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 { + 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(SHUNT_CAL_MAX) as u16 + } + + fn bus_mv(raw: u16) -> MilliVolts { + f32::from(raw) * 1.6 + } + + #[allow(clippy::cast_possible_wrap)] + 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.000_625, // 625 nV + }; + f32::from(signed) * lsb_mv + } + + #[allow(clippy::cast_possible_wrap)] + 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; + Ok(f32::from(signed) * lsb * 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, 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) + } +} + +// ── 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(channel, 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(), + }; + self.current_ma(channel, 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(), + }; + self.power_mw(channel, 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(), + }; + self.energy_mj(channel, 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( + (AddrPinState::Gnd, AddrPinState::Gnd).to_address(), + vec![0x7E], + vec![0x54, 0x49], + )]; + let i2c = Mock::new(&expectations); + let mut dev = Device::new(DeviceInterface { + i2c, + address: (AddrPinState::Gnd, AddrPinState::Gnd).to_address(), + }); + 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( + (AddrPinState::Gnd, AddrPinState::Gnd).to_address(), + vec![0x05, hi, lo], + )]; + let i2c = Mock::new(&expectations); + let mut dev = Device::new(DeviceInterface { + i2c, + address: (AddrPinState::Gnd, AddrPinState::Gnd).to_address(), + }); + 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( + (AddrPinState::Gnd, AddrPinState::Gnd).to_address(), + vec![0x01], + vec![hi, lo], + )]; + let i2c = Mock::new(&expectations); + 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(); + } + + #[tokio::test] + async fn current_ch1_trait() { + 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 = (AddrPinState::Gnd, AddrPinState::Gnd).to_address(); + 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, AddrPinState::Gnd, AddrPinState::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( + (AddrPinState::Gnd, AddrPinState::Gnd).to_address(), + vec![0x02], + vec![hi, lo], + )]; + let i2c = Mock::new(&expectations); + 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(); + } + + #[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 = (AddrPinState::Gnd, AddrPinState::Gnd).to_address(); + 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, AddrPinState::Gnd, AddrPinState::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( + (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, 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}"); + } + 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 = (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]), + 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, AddrPinState::Gnd, AddrPinState::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 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); + } +} 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); - } -} diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index 2772ccb..d4e5fa2 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 +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 +start = "2023-02-22" +end = "2027-03-13" + +[[trusted.zerocopy]] +criteria = "safe-to-deploy" +user-id = 7178 +start = "2019-02-28" +end = "2027-03-13" + +[[trusted.zerocopy-derive]] +criteria = "safe-to-deploy" +user-id = 7178 +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..582523d 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -7,8 +7,46 @@ 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.embedded-hal-mock]] +version = "0.11.1" +criteria = "safe-to-run" + +[[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.num]] +version = "0.3.1" +criteria = "safe-to-run" + +[[exemptions.num-complex]] +version = "0.3.1" +criteria = "safe-to-run" + +[[exemptions.num-rational]] +version = "0.3.2" +criteria = "safe-to-run" + +[[exemptions.paste]] +version = "1.0.15" +criteria = "safe-to-deploy" diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock index 219dba4..b9a6c15 100644 --- a/supply-chain/imports.lock +++ b/supply-chain/imports.lock @@ -1,8 +1,429 @@ # cargo-vet imports lock -[audits.OpenDevicePartnership.audits] +[[publisher.backtrace]] +version = "0.3.76" +when = "2025-09-26" +user-id = 55123 +user-login = "rust-lang-owner" -[audits.google.audits] +[[publisher.cfg-if]] +version = "1.0.4" +when = "2025-10-15" +user-id = 55123 +user-login = "rust-lang-owner" -[audits.mozilla.audits] +[[publisher.device-driver]] +version = "1.0.8" +when = "2026-03-06" +user-id = 85562 +user-login = "diondokter" +user-name = "Dion Dokter" + +[[publisher.libc]] +version = "0.2.186" +when = "2026-04-23" +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.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.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" + +[[audits.OpenDevicePartnership.audits.defmt]] +who = "Jerry Xie " +criteria = "safe-to-deploy" +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]] +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-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" +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-hal-async]] +who = "Jerry Xie " +criteria = "safe-to-deploy" +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-nb]] +who = "Jerry Xie " +criteria = "safe-to-deploy" +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 " +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.num-iter]] +who = "Jerry Xie " +criteria = "safe-to-deploy" +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]] +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.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.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.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.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-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" +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.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.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"