From 18197e209adbc24d812753b17be4b38847dce46b Mon Sep 17 00:00:00 2001 From: Walter Bonetti Date: Wed, 24 Apr 2024 19:17:59 -0400 Subject: [PATCH] poc: device_id --- .cargo-husky/hooks/pre-commit | 8 + .cargo-husky/hooks/pre-push | 8 + .github/FUNDING.yml | 1 + .github/workflows/rust-release.yml | 40 ++ .github/workflows/rust.yml | 43 ++ .gitignore | 13 + CHANGELOG.md | 9 + Cargo.toml | 33 + LICENSE-APACHE | 201 ++++++ LICENSE-MIT | 23 + README.md | 41 ++ README.tpl | 34 + justfile | 66 ++ src/bitfield_helper.rs | 51 ++ src/command.rs | 968 +++++++++++++++++++++++++++++ src/driver.rs | 102 +++ src/lib.rs | 70 +++ src/prelude.rs | 1 + 18 files changed, 1712 insertions(+) create mode 100755 .cargo-husky/hooks/pre-commit create mode 100755 .cargo-husky/hooks/pre-push create mode 100644 .github/FUNDING.yml create mode 100644 .github/workflows/rust-release.yml create mode 100644 .github/workflows/rust.yml create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 Cargo.toml create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT create mode 100644 README.md create mode 100644 README.tpl create mode 100644 justfile create mode 100644 src/bitfield_helper.rs create mode 100644 src/command.rs create mode 100644 src/driver.rs create mode 100644 src/lib.rs create mode 100644 src/prelude.rs diff --git a/.cargo-husky/hooks/pre-commit b/.cargo-husky/hooks/pre-commit new file mode 100755 index 0000000..9ffbb14 --- /dev/null +++ b/.cargo-husky/hooks/pre-commit @@ -0,0 +1,8 @@ +set -e + +echo '+just check-readme' +just check-readme +echo '+cargo clippy --all-targets --all-features --workspace -- -D warnings' +cargo clippy --all-targets --all-features --workspace -- -D warnings +echo '+cargo fmt ---all -- --check --color always' +cargo fmt --all -- --check --color always diff --git a/.cargo-husky/hooks/pre-push b/.cargo-husky/hooks/pre-push new file mode 100755 index 0000000..1e4d8ff --- /dev/null +++ b/.cargo-husky/hooks/pre-push @@ -0,0 +1,8 @@ +set -e + +echo '+just check-readme' +just check-readme +echo '+cargo clippy --all-targets --all-features --workspace -- -D warnings' +cargo clippy --all-targets --all-features --workspace -- -D warnings +echo '+cargo fmt ---all -- --check --color always' +cargo fmt --all -- --check --color always \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..c7b38a4 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [initerworker] diff --git a/.github/workflows/rust-release.yml b/.github/workflows/rust-release.yml new file mode 100644 index 0000000..893e8a4 --- /dev/null +++ b/.github/workflows/rust-release.yml @@ -0,0 +1,40 @@ +on: + push: + # Pattern matched against refs/tags + tags: + - '*' # Push events to every tag not containing / + workflow_dispatch: + +name: Rust Release + +jobs: + publish: + name: Publish + runs-on: ubuntu-latest + + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Install stable toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + components: clippy, rustfmt + targets: thumbv7em-none-eabihf + + - name: Build + run: cargo build --all-targets --verbose + + - name: Format with Fmt + run: cargo fmt --all -- --check --color always + + - name: Lint with Clippy + run: cargo clippy --all-targets --all-features --workspace -- -D warnings + + - name: Run Tests + run: cargo test --verbose + + - run: cargo publish --token ${CRATES_TOKEN} + env: + CRATES_TOKEN: ${{ secrets.CRATES_TOKEN }} diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..7640934 --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,43 @@ +name: Continuous Integration + +on: + push: + paths-ignore: + - "**/README.md" + pull_request: + workflow_dispatch: + +jobs: + build: + name: Build Driver + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + action: + - command: build + args: --release + - command: fmt + args: --all -- --check --color always + - command: clippy + args: --all-targets --all-features --workspace -- -D warnings + - command: test + args: --verbose + + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Install stable toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + components: clippy, rustfmt + targets: thumbv7em-none-eabihf + + - name: Enable caching + uses: Swatinem/rust-cache@v2 + + - name: Run command + run: cargo ${{ matrix.action.command }} ${{ matrix.action.args }} + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fa5b635 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +**/*.rs.bk +.#* +.gdb_history +Cargo.lock +target/ + +# editor files +.vscode/* +!.vscode/*.md +!.vscode/*.svd +!.vscode/launch.json +!.vscode/tasks.json +!.vscode/extensions.json \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ccd27f0 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,9 @@ +# Changelog + +Rust implementation I2C driver of the QMI8658 Low Noise, Wide Bandwidth 6D Inertial Measurement +Unit with Motion Co-Processor. + + + +## [Unreleased] - ReleaseDate + diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..02a8c9b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "qmi8658" +categories = ["embedded", "no-std"] +version = "0.2.1" +edition = "2021" +authors = [ + "Walter Bonetti " +] +license = "MIT OR Apache-2.0" +description = "QMI8658 Sensor/Gyroscope" +keywords = ["no-std", "qmi8658", "embedded", "embedded-hal-driver", "sensor"] +include = ["src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +repository = "https://github.com/IniterWorker/qmi8658" +readme = "README.md" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[package.metadata.docs.rs] +targets = [ "thumbv7m-none-eabi", "thumbv7em-none-eabihf" ] + +[dependencies] +# Embedded HAL abstraction +# We use this layer to abstract hardware i2c/spi +embedded-hal = { version = "1.0.0" } +bitfield = "0.15.0" + +[dev-dependencies.cargo-husky] +version = "1" +features = ["user-hooks"] + +[lib] +name = "qmi8658" +path = "src/lib.rs" diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..f8e5e5e --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..468cd79 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..13e040d --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# QMI8658 + +

+ Github CI/CD + Crates.io + Docs.rs +

+ +Rust implementation I2C driver of the QMI8658 Low Noise, Wide Bandwidth 6D Inertial Measurement +Unit with Motion Co-Processor. + +## QMI8658 Sensor/Gyroscope + +### Support + +- [Embedded-hal v1.0.0](https://github.com/rust-embedded/embedded-hal/tree/embedded-hal-v1.0.0) + +### Example + +- [Waveshare esp32-s3-touch-lcd-1-28](https://github.com/IniterWorker/esp32-s3-touch-lcd-1-28) + + +## Inspiration + +- From [jamwaffles/ssd1306](https://github.com/jamwaffles/ssd1306) + +## License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the +work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/README.tpl b/README.tpl new file mode 100644 index 0000000..6767c9f --- /dev/null +++ b/README.tpl @@ -0,0 +1,34 @@ +# QMI8658 + +

+ Github CI/CD + Crates.io + Docs.rs +

+ +Rust implementation I2C driver of the QMI8658 Low Noise, Wide Bandwidth 6D Inertial Measurement +Unit with Motion Co-Processor. + +WIP... + +## Open-To-Idea + +Please feel free to open an issue with your design improvements/considerations. + +{{readme}} + +## License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the +work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. \ No newline at end of file diff --git a/justfile b/justfile new file mode 100644 index 0000000..b1047a5 --- /dev/null +++ b/justfile @@ -0,0 +1,66 @@ +target_dir := "target" + +doc_dir := "doc" +doc_assets_dir := doc_dir + "/assets" +project_name := "qmi8658" + +#---------- +# Building +#---------- + +build: check-formatting check-clippy build-without-fmt-check + +build-without-fmt-check: test check-readme generate-docs + +# Run cargo test +test: + cargo test + +# Run cargo test with all features enabled +test-all: + cargo test --all-features + +# Check the formatting +check-formatting: + cargo fmt --all -- --check --color always + +# Check clippy +check-clippy: + cargo clippy --all-targets --all-features --workspace -- -D warnings + +#------ +# Docs +#------ + +# Generates the docs +generate-docs: + cargo clean --doc + cargo doc --all-features --no-deps + +#---------------------- +# README.md generation +#---------------------- + +# Generate README.md for a single crate +generate-readme: _build-readme + #!/usr/bin/env bash + set -euo pipefail + cp "{{target_dir}}/README.md" "README.md" + +# Check README.md for a single crate +check-readme: _build-readme + #!/usr/bin/env bash + set -euo pipefail + diff -q "{{target_dir}}/README.md" "README.md" || ( \ + echo -e "\033[1;31mError:\033[0m README.md for {{project_name}} needs to be regenerated."; \ + echo -e " Run 'just generate-readme' to regenerate.\n"; \ + exit 1 \ + ) + +# Builds README.md for a single crate +_build-readme: + #!/usr/bin/env bash + set -e -o pipefail + mkdir -p {{target_dir}} + echo "Building README.md for {{project_name}}" + cargo readme > {{target_dir}}/README.md diff --git a/src/bitfield_helper.rs b/src/bitfield_helper.rs new file mode 100644 index 0000000..849eaf9 --- /dev/null +++ b/src/bitfield_helper.rs @@ -0,0 +1,51 @@ +#[macro_export] +macro_rules! impl_enum_bitrange { + ($enum:ident { + $( + $variant:ident = $value:expr, + )* + }) => { + impl BitRange<$enum> for u8 { + fn bit_range(&self, msb: usize, lsb: usize) -> $enum { + let mask = ((1 << (msb - lsb + 1)) - 1) << lsb; + match (*self & mask) >> lsb { + $( + $value => $enum::$variant, + )* + _ => panic!("Invalid bit range for enum"), + } + } + } + + impl BitRangeMut<$enum> for u8 { + fn set_bit_range(&mut self, msb: usize, lsb: usize, value: $enum) { + let mask = !(((1 << (msb - lsb + 1)) - 1) << lsb); + *self &= mask; + *self |= (value as u8) << lsb; + } + } + }; +} + +#[macro_export] +macro_rules! define_enum_with_bitrange { + ($name:ident { + $( + $(#[$meta:meta])* + $variant:ident = $value:expr, + )* + }) => { + #[derive(Debug, PartialEq, Eq, Clone, Copy)] + #[repr(u8)] + enum $name { + $( + $(#[$meta])* + $variant = $value, + )* + } + + $crate::impl_enum_bitrange!($name { + $($variant = $value,)* + }); + }; +} diff --git a/src/command.rs b/src/command.rs new file mode 100644 index 0000000..285cb44 --- /dev/null +++ b/src/command.rs @@ -0,0 +1,968 @@ +/// Device Identifier Register (R) +/// Default: 00000101 +pub const WHO_AM_I: u8 = 0x00; +/// Device Revision ID Register (R) +/// Default: 01101000 +pub const REVISION_ID: u8 = 0x01; +/// SPI Interface and Sensor Enable Register (W) +/// Default: 00100000 +pub const CTRL1: u8 = 0x02; +/// Accelerometer: Output Data Rate, Full Scale, Self-Test Register (W) +/// Default: 00000000 +pub const CTRL2: u8 = 0x03; +/// Gyroscope: Output Data Rate, Full Scale, Self-Test Register (W) +/// Default: 00000000 +pub const CTRL3: u8 = 0x04; +/// Reserved Register (W) +/// Default: 00000000 +pub const RESERVED_U1: u8 = 0x05; +/// Low pass filter setting Register (W) +/// Default: 00000000 +pub const CTRL5: u8 = 0x06; +/// Reserved Register (W) +/// Default: 00000000 +pub const RESERVED_U2: u8 = 0x07; +/// Enable Sensors Register (W) +/// Default: 00000000 +pub const CTRL7: u8 = 0x08; +/// Motion Detection Control Register (W) +/// Default: 00000000 +pub const CTRL8: u8 = 0x09; +/// Host Commands Host Controlled Calibration Registers (See CTRL9, Usage is Optional) Register (W) +/// Default: 00000000 +pub const CTRL9: u8 = 0x0A; +/// Calibration Low Register Register (RW) +/// Default: 00000000 +pub const CAL1_LOW: u8 = 0x0B; +/// Calibration High Register Register (RW) +/// Default: 00000000 +pub const CAL1_HIGH: u8 = 0x0C; +/// Calibration Low Register Register (RW) +/// Default: 00000000 +pub const CAL2_LOW: u8 = 0x0D; +/// Calibration High Register Register (RW) +/// Default: 00000000 +pub const CAL2_HIGH: u8 = 0x0E; +/// Calibration Low Register Register (RW) +/// Default: 00000000 +pub const CAL3_LOW: u8 = 0x0F; +/// Calibration High Register Register (RW) +/// Default: 00000000 +pub const CAL3_HIGH: u8 = 0x10; +/// Calibration Low Register Register (RW) +/// Default: 00000000 +pub const CAL4_LOW: u8 = 0x11; +/// Calibration High Register Register (RW) +/// Default: 00000000 +pub const CAL4_HIGH: u8 = 0x12; +/// FIFO watermark level, in ODRs Register (W) +/// Default: 00000000 +pub const FIFO_WTM_TH: u8 = 0x13; +/// FIFO Setup Register (W) +/// Default: 00000000 +pub const FIFO_CTRL: u8 = 0x14; +/// FIFO sample count LSBs Register (R) +/// Default: 00000000 +pub const FIFO_SMPL_CNT: u8 = 0x15; +/// FIFO Status Register (R) +/// Default: 00000000 +pub const FIFO_STATUS: u8 = 0x16; +/// FIFO Data Status Registers Register (R) +/// Default: 00000000 +pub const FIFO_DATA: u8 = 0x17; +/// Sensor Data Availability with the Locking mechanism, `CmdDone` (CTRL9 protocol bit). Register (R) +/// Default: 00000000 +pub const STATUSINT: u8 = 0x2D; +/// Output Data Over Run and Data Availability. Register (R) +/// Default: 00000000 +pub const STATUS0: u8 = 0x2E; +/// Miscellaneous Status: Any Motion, No Motion, Significant Motion, Pedometer, Tap. Timestamp Register Register (R) +/// Default: 00000000 +pub const STATUS1: u8 = 0x2F; +/// Sample Time Stamp Register (R) +/// Default: 00000000 +pub const TIMESTAMP_LOW: u8 = 0x30; +/// Register (R) +/// Default: 00000000 +pub const TIMESTAMP_MID: u8 = 0x31; +/// Register (R) +/// Default: 00000000 +pub const TIMESTAMP_HIGH: u8 = 0x32; +/// Temperature Output Data Register (R) +/// Default: 00000000 +pub const TEMP_LOW: u8 = 0x33; +/// `TEMP_LOW` – Low 8 bits. `TEMP_HIGH` – upper 8 bits Register (R) +/// Default: 00000000 +pub const TEMP_HIGH: u8 = 0x34; +/// X-axis Acceleration Low Register (R) +/// Default: 00000000 +pub const AX_LOW: u8 = 0x35; +/// X-axis Acceleration High Register (R) +/// Default: 00000000 +pub const AX_HIGH: u8 = 0x36; +/// Y-axis Acceleration Low Register (R) +/// Default: 00000000 +pub const AY_LOW: u8 = 0x37; +/// Y-axis Acceleration High Register (R) +/// Default: 00000000 +pub const AY_HIGH: u8 = 0x38; +/// Z-axis Acceleration Low Register (R) +/// Default: 00000000 +pub const AZ_LOW: u8 = 0x39; +/// Z-axis Acceleration High Register (R) +/// Default: 00000000 +pub const AZ_HIGH: u8 = 0x3A; +/// X-axis Angular Rate Low Register (R) +/// Default: 00000000 +pub const GX_LOW: u8 = 0x3B; +/// X-axis Angular Rate High Register (R) +/// Default: 00000000 +pub const GX_HIGH: u8 = 0x3C; +/// Y-axis Angular Rate Low Register (R) +/// Default: 00000000 +pub const GY_LOW: u8 = 0x3D; +/// Z-axis Angular Rate High Register (R) +/// Default: 00000000 +pub const GY_HIGH: u8 = 0x3E; +/// Z-axis Angular Rate Low Register (R) +/// Default: 00000000 +pub const GZ_LOW: u8 = 0x3F; +/// Calibration-On-Demand status register Register (R) +/// Default: 00000000 +pub const COD_STATUS: u8 = 0x46; +/// General purpose register Register (R) +/// Default: 00000000 +pub const D_QW_LOW: u8 = 0x49; +/// General purpose register Register (R) +/// Default: 00000000 +pub const D_QW_HIGH: u8 = 0x4A; +/// General purpose register Register (R) +/// Default: 00000000 +pub const D_QX_LOW: u8 = 0x4B; +/// Reserved Register (R) +/// Default: 00000000 +pub const D_QX_HIGH: u8 = 0x4C; +/// General purpose register Register (R) +/// Default: 00000000 +pub const D_QY_LOW: u8 = 0x4D; +/// Reserved Register (R) +/// Default: 00000000 +pub const D_QY_HIGH: u8 = 0x4E; +/// Reserved Register (R) +/// Default: 00000000 +pub const D_QZ_LOW: u8 = 0x4F; +/// Reserved Register (R) +/// Default: 00000000 +pub const D_QZ_HIGH: u8 = 0x50; +/// General purpose register Register (R) +/// Default: 00000000 +pub const D_VX_LOW: u8 = 0x51; +/// General purpose register Register (R) +/// Default: 00000000 +pub const D_VX_HIGH: u8 = 0x52; +/// General purpose register Register (R) +/// Default: 00000000 +pub const D_VY_LOW: u8 = 0x53; +/// General purpose register Register (R) +/// Default: 00000000 +pub const D_VY_HIGH: u8 = 0x54; +/// General purpose register Register (R) +/// Default: 00000000 +pub const D_VZ_LOW: u8 = 0x55; +/// General purpose register Register (R) +/// Default: 00000000 +pub const D_VZ_HIGH: u8 = 0x56; +/// Axis, direction, number of detected Tap Register (R) +/// Default: 00000000 +pub const TAP_STATUS: u8 = 0x59; +/// Low byte of step count of Pedometer Register (R) +/// Default: 00000000 +pub const STEP_CNT_LOWOW: u8 = 0x5A; +/// Middle byte of step count of Pedometer Register (R) +/// Default: 00000000 +pub const STEP_CNT_MIDL: u8 = 0x5B; +/// High byte of step count of Pedometer Register (R) +/// Default: 00000000 +pub const STEP_CNT_HIGHIGH: u8 = 0x5C; +/// Soft Reset Register Register (W) +/// Default: 00000000 +pub const RESET: u8 = 0x60; + +pub mod register { + pub mod ship_info { + + /// Device Identifier + #[derive(Debug, Clone, Copy)] + #[repr(u8)] + pub enum DeviceID { + QSTSensor = 0x05, + Unknown, + } + + /// Device Revision ID + pub type RevisionID = u8; + } + + pub mod ctrl1 { + use bitfield::bitfield; + + bitfield! { + /// Serial Interface and Sensor Enable + pub struct Ctrl1Register(u8); + impl Debug; + bool, sim, set_sim: 7; + bool, addr_ai, set_addr_ai: 6; + bool, be, set_be: 5; + bool, int2_enable, set_int2_enable: 4; + bool, int1_enable, set_int1_enable: 3; + bool, fifo_int_sel, set_fifo_int_sel: 2; + bool, reserved, set_reserved: 1; + bool, sensor_disable, set_sensor_disable: 0; + } + } + + pub mod ctrl2 { + use bitfield::{bitfield, BitRange, BitRangeMut}; + + use crate::define_enum_with_bitrange; + + define_enum_with_bitrange!(Afs { + /// Accelerometer Full-scale = ±2 g + AFS2G = 0b000, + /// Accelerometer Full-scale = ±4 g + AFS4G = 0b001, + /// Accelerometer Full-scale = ±8 g + AFS8G = 0b010, + /// Accelerometer Full-scale = ±16 g + AFS16G = 0b011, + }); + + define_enum_with_bitrange!(Aodr { + /// N/A 7174.4 Hz, Normal, 100% + NormalAODR0 = 0b0000, + /// N/A 3587.2 Hz, Normal, 100% + NormalAODR1 = 0b0001, + /// N/A 1793.6 Hz, Normal, 100% + NormalAODR2 = 0b0010, + /// 1000 896.8 Hz, Normal, 100% + NormalAODR3 = 0b0011, + /// 500 448.4 Hz, Normal, 100% + NormalAODR4 = 0b0100, + /// 250 224.2 Hz, Normal, 100% + NormalAODR5 = 0b0101, + /// 125 112.1 Hz, Normal, 100% + NormalAODR6 = 0b0110, + /// 62.5 56.05 Hz, Normal, 100% + NormalAODR7 = 0b0111, + /// 31.25 28.025 Hz, Normal, 100% + NormalAODR8 = 0b1000, + /// N/A + ReservedAODR9 = 0b1001, + /// N/A + ReservedAODR10 = 0b1010, + /// N/A + ReservedAODR11 = 0b1011, + /// Low Power, 100% + LowPowerAODR12 = 0b1100, + /// Low Power, 58% + LowPowerAODR13 = 0b1101, + /// Low Power, 31% + LowPowerAODR14 = 0b1110, + /// Low Power, 8.5% + LowPowerAODR15 = 0b1111, + }); + + bitfield! { + /// Accelerometer Settings: Address: + pub struct Ctrl2Register(u8); + impl Debug; + bool, ast, set_ast: 7; + #[doc = "Set Accelerometer Full-scale"] + Afs, afs, set_afs: 6, 4; + #[doc = "Set Accelerometer Output Data Rate (ODR)"] + Aodr, aodr, set_aodr: 3, 0; + } + + #[cfg(test)] + mod test { + use bitfield::{BitRange, BitRangeMut}; + + use super::Afs; + use super::Aodr; + use super::Ctrl2Register; + + #[test] + fn test_afs_bit_range() { + // Test AFS2G + let value_2g: u8 = 0b0000_0000; + assert_eq!( + >::bit_range(&value_2g, 2, 0), + Afs::AFS2G + ); + + // Test AFS4G + let value_4g: u8 = 0b0000_0001; + assert_eq!( + >::bit_range(&value_4g, 2, 0), + Afs::AFS4G + ); + + // Test AFS8G + let value_8g: u8 = 0b0000_0010; + assert_eq!( + >::bit_range(&value_8g, 2, 0), + Afs::AFS8G + ); + + // Test AFS16G + let value_16g: u8 = 0b0000_0011; + assert_eq!( + >::bit_range(&value_16g, 2, 0), + Afs::AFS16G + ); + } + + #[test] + fn test_afs_set_bit_range() { + let mut value: u8 = 0; + + // Set AFS2G + value.set_bit_range(2, 0, Afs::AFS2G); + assert_eq!(value, 0b0000_0000); + + // Set AFS4G + value.set_bit_range(2, 0, Afs::AFS4G); + assert_eq!(value, 0b0000_0001); + + // Set AFS8G + value.set_bit_range(2, 0, Afs::AFS8G); + assert_eq!(value, 0b0000_0010); + + // Set AFS16G + value.set_bit_range(2, 0, Afs::AFS16G); + assert_eq!(value, 0b0000_0011); + } + + #[test] + fn test_struct_bit_range() { + let register: u8 = 0b1000_0111; + + let data = Ctrl2Register(register); + assert!(data.ast()); + assert_eq!(data.afs(), Afs::AFS2G); + assert_eq!(data.aodr(), Aodr::NormalAODR7); + } + + #[test] + fn test_struct_set_bit_range() { + let register_result: u8 = 0b1000_0111; + let register_default: u8 = 0b0000_0000; + + let mut data = Ctrl2Register(register_default); + data.set_ast(true); + data.set_afs(Afs::AFS2G); + data.set_aodr(Aodr::NormalAODR7); + assert_eq!(data.0, register_result); + } + } + } + + pub mod ctrl3 { + use bitfield::{bitfield, BitRange, BitRangeMut}; + + use crate::define_enum_with_bitrange; + + define_enum_with_bitrange!(Gfs { + /// ±16 dps + DPS16 = 0b000, + /// ±32 dps + DPS32 = 0b001, + /// ±64 dps + DPS64 = 0b010, + /// ±128 dps + DPS128 = 0b011, + /// ±256 dps + DPS256 = 0b100, + /// ±512 dps + DPS512 = 0b101, + /// ±1024 dps + DPS1024 = 0b110, + /// ±2048 dps + DPS2048 = 0b111, + }); + + // Gyroscope Settings + define_enum_with_bitrange!(Godr { + /// 7174.4 Hz Normal 100% + Hz7174_4 = 0b0000, + /// 3587.2 Hz Normal 100% + Hz3587_2 = 0b0001, + /// 1793.6 Hz Normal 100% + Hz1793_6 = 0b0010, + /// 896.8 Hz Normal 100% + Hz896_8 = 0b0011, + /// 448.4 Hz Normal 100% + Hz448_4 = 0b0100, + /// 224.2 Hz Normal 100% + Hz224_2 = 0b0101, + /// 112.1 Hz Normal 100% + Hz112_1 = 0b0110, + /// 56.05 Hz Normal 100% + Hz56_05 = 0b0111, + /// 28.025 Hz Normal 100% + Hz28_025 = 0b1000, + }); + + bitfield! { + pub struct Ctrl3Register(u8); + impl Debug; + bool, ast, set_ast: 7; + #[doc = "Set Gyroscope Full-scale"] + Gfs, gfs, set_gfs: 6, 4; + #[doc = "Set Gyroscope Output Data Rate (ODR)"] + Godr, godr, set_godr: 3, 0; + } + } + + pub mod ctrl5 { + use bitfield::{bitfield, BitRange, BitRangeMut}; + + use crate::define_enum_with_bitrange; + + define_enum_with_bitrange!(GLPFMode { + /// 2.66% of ODR + LPF2_66 = 0b00, + /// 3.63% of ODR + LPF3_63 = 0b01, + /// 5.39% of ODR + LPF5_39 = 0b10, + /// 13.37% of ODR + LPF13_37 = 0b11, + }); + + define_enum_with_bitrange!(ALPFMode { + /// 2.66% of ODR + LPF2_66 = 0b00, + /// 3.63% of ODR + LPF3_63 = 0b01, + /// 5.39% of ODR + LPF5_39 = 0b10, + /// 13.37% of ODR + LPF13_37 = 0b11, + }); + + bitfield! { + /// Sensor Data Processing Settings + pub struct Ctrl5Register(u8); + impl Debug; + #[doc = "Reserved"] + bool, reserved_7, set_reserved_7: 7; + #[doc = "Set Gyroscope LPF Mode"] + GLPFMode, glpf, set_glpf: 6, 5; + #[doc = "Set Gyroscope LPF Enable"] + bool, glpf_enable, set_glpf_enable: 4; + #[doc = "Reserved"] + bool, reserved_3, set_reserved_3: 3; + #[doc = "Set Accelerometer LPF Mode"] + ALPFMode, alpf, set_alpf: 2, 0; + #[doc = "Set Accelerometer LPF Enable"] + bool, alpf_enable, set_alpf_enable: 0; + } + } + + pub mod ctrl7 { + use bitfield::{bitfield, BitRange, BitRangeMut}; + + use crate::define_enum_with_bitrange; + + define_enum_with_bitrange!(Gsn { + /// Gyroscope in Full Mode (Drive and Sense are enabled) + FullMode = 0b00, + /// Gyroscope in Snooze Mode (only Drive enabled) + SnoozeMode = 0b01, + }); + + bitfield! { + /// Enable Sensors and COnfigure Data Reads + pub struct Ctrl7Register(u8); + impl Debug; + #[doc = "Set Sync Sample Enable"] + + bool, sync_sample_enable, set_sync_sample_enable: 7; + #[doc = "Reserved"] + bool, reserved_6, set_reserved_6: 6; + #[doc = "Set Data Ready Disabled\n\ + DRDY(Data Ready) is enabled, is driven to INT2 pin\n\ + DRDY(Data Ready) is disabled, is blocked from the INT2 pin\n\ + "] + bool, data_ready_disable, set_data_ready_disable: 5; + #[doc = "Set Gyroscope Mode. This bit is effective only when Gyroscope is enabled. Refer to 7.1."] + GSN, gsn, set_gsn: 4; + #[doc = "Reserved"] + u8, reserved_3, set_reserved_3: 3, 2; + #[doc = "Set Gyroscope Enable"] + bool, gyroscope_enable, set_gyroscope_enable: 1; + #[doc = "Set Accelerometer Enable"] + bool, accelerometer_enable, set_accelerometer_enable: 0; + } + } + + pub mod ctrl8 { + use bitfield::{bitfield, BitRange, BitRangeMut}; + + use crate::define_enum_with_bitrange; + + define_enum_with_bitrange!(HandShakeType { + /// Use INT1 as CTRL9 handshake + Int1 = 0b0, + /// Use STATUSINT.bit7 as CTRL9 handshake + StatusIntBit7 = 0b1, + }); + + define_enum_with_bitrange!(ActivityIntSelect { + /// INT2 is used for Activity Detection event interrupt + Int2 = 0b0, + /// INT1 is used for Activity Detection event interrupt + Int1 = 0b1, + }); + + bitfield! { + /// Enable Sensors and COnfigure Data Reads + pub struct Ctrl8Register(u8); + impl Debug; + #[doc = "Set CTRL9_HandShake_Type"] + HandShakeType, ctrl9_handshake_type, set_ctrl9_handshake_type: 7; + #[doc = "Set Activity Int Selection\n\ + ## NOTE: this bit influences the Any/No/Sig-motion, Pedometer, Tap Detection interrupt + "] + ActivityIntSelect, activity_int_select, set_activity_int_select: 6; + #[doc = "Set Data Ready Disabled\n\ + DRDY(Data Ready) is enabled, is driven to INT2 pin\n\ + DRDY(Data Ready) is disabled, is blocked from the INT2 pin\n\ + "] + bool, data_ready_disable, set_data_ready_disable: 5; + #[doc = "Set Gyroscope Mode. This bit is effective only when Gyroscope is enabled. Refer to 7.1."] + GSN, gsn, set_gsn: 4; + #[doc = "Reserved"] + u8, reserved_3, set_reserved_3: 3, 2; + #[doc = "Set Gyroscope Enable"] + bool, gyroscope_enable, set_gyroscope_enable: 1; + #[doc = "Set Accelerometer Enable"] + bool, accelerometer_enable, set_accelerometer_enable: 0; + } + } + + pub mod ctrl9 { + #[derive(Debug, PartialEq, Eq, Clone, Copy)] + #[repr(u8)] + pub enum Ctrl9Register { + /// Acknowledgement. Host acknowledges to QMI8658, to end the protocol. + /// Prototype Type: Ctrl9 + CtrlCmdAck = 0x00, + /// Reset FIFO from Host + /// Prototype Type: Ctrl9 + CtrlCmdRstFifo = 0x04, + /// Get FIFO data from Device + /// Prototype Type: Ctrl9 + CtrlCmdReqFifo = 0x05, + /// Set up and enable Wake on Motion (WoM) + /// Prototype Type: WCtrl9 + CtrlCmdWriteWomSetting = 0x08, + /// Change accelerometer offset + /// Prototype Type: WCtrl9 + CtrlCmdAccelHostDeltaOffset = 0x09, + /// Change gyroscope offset + /// Prototype Type: WCtrl9 + CtrlCmdGyroHostDeltaOffset = 0x0A, + /// Configure Tap detection + /// Prototype Type: WCtrl9 + CtrlCmdConfigureTap = 0x0C, + /// Configure Pedometer + /// Prototype Type: WCtrl9 + CtrlCmdConfigurePedometer = 0x0D, + /// Configure Any Motion / No Motion / Significant Motion detection + /// Prototype Type: WCtrl9 + CtrlCmdConfigureMotion = 0x0E, + /// Reset pedometer count (step count) + /// Prototype Type: WCtrl9 + CtrlCmdResetPedometer = 0x0F, + /// Copy USID and FW Version to UI registers + /// Prototype Type: Ctrl9R + CtrlCmdCopyUsid = 0x10, + /// Configures IO pull-ups + /// Prototype Type: WCtrl9 + CtrlCmdSetRpu = 0x11, + /// Internal AHB clock gating switch + /// Prototype Type: WCtrl9 + CtrlCmdAhbClockGating = 0x12, + /// On-Demand Calibration on gyroscope + /// Prototype Type: WCtrl9 + CtrlCmdOnDemandCalibration = 0xA2, + /// Restore the saved Gyroscope gains + /// Prototype Type: WCtrl9 + CtrlCmdApplyGyroGains = 0xAA, + } + } + + pub mod fifo_wtm_th { + + /// Number of ODRs(Samples) needed to trigger FIFO watermark + pub struct FIFOWTMRegister(u8); + } + + pub mod fifo_ctrl { + use bitfield::{bitfield, BitRange, BitRangeMut}; + + use crate::define_enum_with_bitrange; + + define_enum_with_bitrange!(FIFOMode { + /// Bypass (FIFO disable) + Bypass = 0b00, + /// FIFO + Fifo = 0b01, + /// Stream + Stream = 0b10, + /// Reserved + Reserved = 0b11, + }); + + define_enum_with_bitrange!(FIFOSize { + /// 16 samples + Size16 = 0b00, + /// 32 samples + Size32 = 0b01, + /// 64 samples + Size64 = 0b10, + /// 128 samples + Size128 = 0b11, + }); + + bitfield! { + /// FIFO Control Register + pub struct FIFOControlRegister(u8); + impl Debug; + /// + #[doc = "FIFO Read Mode\n\ + FIFO is in Write mode, sensor data (if enabled) can be filled into FIFO\n\ + FIFO is in Read mode, FIFO data can be read via FIFO_DATA register\n\ + "] + bool, fifo_rd_mode, set_fifo_rd_mode: 7; + #[doc = "Reserved"] + u8, reserved_4_6, set_reserved_4_6: 6, 4; + #[doc = "FIFO Size"] + FIFOSize, fifo_size, set_fifo_size: 3, 2; + #[doc = "FIFO Mode"] + FIFOMode, fifo_mode, set_fifo_mode: 1, 0; + } + } + + pub mod fifo_sample_count { + use bitfield::bitfield; + + bitfield! { + /// FIFO Sample Count Register + pub struct FIFOSampleCountRegister(u8); + impl Debug; + #[doc = "FIFO Count"] + bool, fifo_smpl_cnt_lsb: 7, 0; + } + } + + pub mod fifo_status { + use bitfield::bitfield; + + bitfield! { + /// FIFO Status Register + pub struct FIFOStatusRegister(u8); + impl Debug; + #[doc = "FIFO is full"] + bool, fifo_full, set_fifo_full: 7; + #[doc = "FIFO Water Mark Level is hit"] + bool, fifo_wtm, set_fifo_wtm: 6; + #[doc = "FIFO Overflow condition has happened"] + bool, fifo_overflow, set_fifo_overflow: 5; + #[doc = "FIFO Not Empty"] + bool, fifo_not_empty, set_fifo_not_empty: 4; + #[doc = "Reserved"] + u8, reserved_3_2, set_reserved_3_2: 3, 2; + #[doc = "2 MS bits of FIFO Sample Count in word (2bytes)"] + u8, fifo_smpl_cnt_msb, set_fifo_smpl_cnt_msb: 1, 0; + } + } + + pub mod fifo_data { + use bitfield::bitfield; + + bitfield! { + /// FIFO Data Register + pub struct FIFODataRegister(u8); + impl Debug; + #[doc = "FIFO Data, 8 bit FIFO data output."] + bool, fifo_data: 7, 0; + } + } + + pub mod status_int { + use bitfield::{bitfield, BitRange, BitRangeMut}; + + use crate::define_enum_with_bitrange; + + define_enum_with_bitrange!(Ctrl9CmdDone { + /// Not Completed + NotCompleted = 0b00, + /// Done + Done = 0b01, + }); + + bitfield! { + /// Sensor Data Available and Lock Register + pub struct SensorDataAvailableAndLockRegister(u8); + impl Debug; + /// + #[doc = "Indicates CTRL9 Command was done, as part of CTRL9 protocol"] + Ctrl9CmdDone, ctrl9_cmd_done, set_ctrl9_cmd_done: 7; + #[doc = "Reserved"] + u8, reserved_2_6, set_reserved_2_6: 6, 2; + #[doc = "if `ctrl7.sync_sample_enable` is enabled then `false` sensor data is not locked, \ + else `true` sensor data is locked.\n\ + if `ctrl7.sync_sample_enable` is disabled then the bit shows the same value of INT1.\n\ + "] + bool, locked, set_locked: 1; + #[doc = "if `ctrl7.sync_sample_enable` is enabled then `false` sensor data is not available, \ + else `true` sensor data is available for reading.\n\ + if `ctrl7.sync_sample_enable` is disabled then the bit shows the same value of INT2.\n\ + "] + bool, available, set_available: 0; + } + } + + pub mod status_0 { + use bitfield::{bitfield, BitRange, BitRangeMut}; + + use crate::define_enum_with_bitrange; + + define_enum_with_bitrange!(UpdateData { + /// No updates since last read + NoUpdate = 0b00, + /// New data available + NewData = 0b01, + }); + + bitfield! { + /// Output Data Status Register + pub struct OutputDataStatusRegister(u8); + impl Debug; + /// + #[doc = "Reserved"] + u8, reserved_2_7, set_reserved_2_7: 7, 2; + #[doc = "Gyroscope new data available"] + UpdateData, gyroscope_data_available, set_gyroscope_data_available: 1; + #[doc = "Accelerometer new data available"] + UpdateData, accelerometer_data_available, set_accelerometer_data_available: 0; + } + } + + pub mod status_1 { + use bitfield::{bitfield, BitRange, BitRangeMut}; + + use crate::define_enum_with_bitrange; + + define_enum_with_bitrange!(EngineDetect { + /// Not Detected + NotDetected = 0b00, + /// Detected + Detected = 0b01, + }); + + bitfield! { + /// Miscellaneous Status Register + pub struct MiscellaneousStatusRegister(u8); + impl Debug; + #[doc = "Significant Motion\n\ + * No Significant-Motion was detected\n\ + * Significant-Motion was detected\n\ + "] + EngineDetect, significant_motion, set_significant_motion: 7; + #[doc = "No Motion\n\ + * No No-Motion was detected\n\ + * No-Motion was detected\n\ + "] + EngineDetect, no_motion, set_no_motion: 6; + #[doc = "Any Motion\n\ + * No Any-Motion was detected\n\ + * Any-Motion was detected\n\ + "] + EngineDetect, any_motion, set_any_motion: 5; + #[doc = "Pedometer\n\ + * No step was detected\n\ + * step was detected\n\ + "] + EngineDetect, pedometer, set_pedometer: 4; + #[doc = "Reserved"] + u8, reserved_3, set_reserved_3: 3; + #[doc = "WoM\n\ + * No WoM was detected\n\ + * WoM was detected\n\ + "] + EngineDetect, wom, set_wom: 2; + #[doc = "Tap\n\ + * No Tap was detected\n\ + * Tap was detected\n\ + "] + EngineDetect, tap, set_tap: 1; + #[doc = "Reserved"] + u8, reserved_0, set_reserved_0: 0; + } + } + + pub mod timestamp { + //! Sample time stamp. Count incremented by one for each sample + //! (x, y, z data set) from sensor with highest ODR (circular register + //! 0x0-0xFFFFFF). + pub struct SampleTimeStamp(u32); + + pub struct TimeStampRegister(u8); + } + + pub mod temp { + //! Temperature output (°C) in two’s complement. + //! T = `TEMP_H` + (`TEMP_L` / 256) + + pub struct TempRegister(u8); + + /// Temperature Sensor Register Address: 0x33 – 0x34 + pub struct Temperature(u16); + } + + pub mod acceleration { + pub struct AccelerationRegister(u8); + pub struct AngularRegister(u8); + + /// Acceleration Output. Register Address: 0x35 – 0x3A + pub struct AccelerationOutput { + /// AX + pub x: u16, + /// AY + pub y: u16, + /// AZ + pub z: u16, + } + + /// Angular Rate Output. Register Address: 0x3B – 0x40 + pub struct AngularRateOutput { + /// AX + pub x: u16, + /// AY + pub y: u16, + /// AZ + pub z: u16, + } + } + + pub mod cod_status { + use bitfield::bitfield; + + bitfield! { + #[doc = "COD Status Register"] + pub struct CODStatusRegister(u8); + impl Debug; + #[doc = "COD passed for checking low sensitivity limit of X axis of gyroscope\n\ + COD failed for checking low sensitivity limit of X axis of gyroscope"] + bool, x_limit_l_fail, set_x_limit_l_fail: 7; + #[doc = "COD passed for checking high sensitivity limit of X axis of gyroscope\n\ + COD failed for checking high sensitivity limit of X axis of gyroscope"] + bool, x_limit_h_fail, set_x_limit_h_fail: 6; + #[doc = "COD passed for checking low sensitivity limit of Y axis of gyroscope\n\ + COD failed for checking low sensitivity limit of Y axis of gyroscope"] + bool, y_limit_l_fail, set_y_limit_l_fail: 5; + #[doc = "COD passed for checking high sensitivity limit of Y axis of gyroscope\n\ + COD failed for checking high sensitivity limit of Y axis of gyroscope"] + bool, y_limit_h_fail, set_y_limit_h_fail: 4; + #[doc = "Accelerometer checked pass (no significant vibration happened during COD)\n\ + Accelerometer checked failed (significant vibration happened during COD)"] + bool, accel_check, set_accel_check: 3; + #[doc = "Gyroscope startup succeeded\n\ + Gyroscope startup failure happened when COD was called"] + bool, startup_failed, set_startup_failed: 2; + #[doc = "COD was called when gyroscope was not enabled\n\ + COD was called while gyroscope was enabled, COD return failure"] + bool, gyro_enabled, set_gyro_enabled: 1; + #[doc = "COD succeeded, new gain parameters will be applied to GX & GY data\n\ + COD failed; no COD correction applied"] + bool, cod_failed, set_cod_failed: 0; + } + } + + pub mod tap_status { + use bitfield::{bitfield, BitRange, BitRangeMut}; + + use crate::define_enum_with_bitrange; + + define_enum_with_bitrange!(TapPolarity { + /// Tap was detected on the positive direction of the Tap axis + Positive = 0b0, + /// Tap was detected on the negative direction of the Tap axis + Negative = 0b1, + }); + + define_enum_with_bitrange!(TapAxis { + /// No Tap was detected + None = 0b00, + /// Tap was detected on X axis + XAxis = 0b01, + /// Tap was detected on Y axis + YAxis = 0b10, + /// Tap was detected on Z axis + ZAxis = 0b11, + }); + + define_enum_with_bitrange!(TapNumber { + /// No Tap was detected + None = 0b00, + /// Single-Tap was detected + Single = 0b01, + /// Double-Tap was detected + Double = 0b10, + /// NA + NA = 0b11, + }); + + bitfield! { + /// Tap Status Register + #[doc = "Tap Status Register"] + pub struct TapStatusRegister(u8); + impl Debug; + #[doc = "Tap was detected on the positive direction of the Tap axis\n\ + Tap was detected on the negative direction of the Tap axis\ + "] + TapPolarity, tap_polarity, set_tap_polarity: 7; + #[doc = "Reserved"] + u8, reserved_6, set_reserved_6: 6; + #[doc = "No Tap was detected\n\ + Tap was detected on X axis\n\ + Tap was detected on Y axis\n\ + Tap was detected on Z axis\ + "] + TapAxis, tap_axis, set_tap_axis: 5, 4; + #[doc = "Reserved"] + u8, reserved_3_2, set_reserved_3_2: 3, 2; + #[doc = "No Tap was detected\n\ + Single-Tap was detected\n\ + Double-Tap was detected\n\ + NA\ + "] + TapNumber, tap_num, set_tap_num: 1, 0; + } + } + + pub mod step_count { + pub struct StepCountRegister(u8); + + /// 24 `BitCounter` + pub struct StepCounter(u32); + } + + pub mod reset { + pub struct ResetRegister(u8); + } +} diff --git a/src/driver.rs b/src/driver.rs new file mode 100644 index 0000000..542906d --- /dev/null +++ b/src/driver.rs @@ -0,0 +1,102 @@ +#![allow(clippy::missing_const_for_fn)] +use embedded_hal::delay::DelayNs; +use embedded_hal::i2c::{I2c, SevenBitAddress}; + +use crate::command::register::ship_info::{DeviceID, RevisionID}; +use crate::command::WHO_AM_I; + +#[repr(u8)] +#[derive(Debug, Clone, Copy)] +pub enum DeviceAddress { + /// SA0 external pullup or floationg (intenal pullup) + Primary = 0x6A, + /// SA0 external pulldown + Secondary = 0x6B, +} + +impl From for u8 { + fn from(value: DeviceAddress) -> Self { + match value { + DeviceAddress::Primary => 0x6A, + DeviceAddress::Secondary => 0x6B, + } + } +} + +impl Default for DeviceAddress { + fn default() -> Self { + Self::Primary + } +} + +/// Qmi8658 Driver +pub struct Qmi8658 { + /// I2C Interface + pub(crate) interface: I, + /// I2C Address + pub(crate) addr: DeviceAddress, + /// Delay + pub(crate) _delay: D, +} + +// #[derive(Clone, Debug)] +// pub enum Error { +// /// I2C Error, +// I2CError(embedded_hal::i2c::Error) +// } + +impl Qmi8658 +where + I: I2c, + D: DelayNs, +{ + /// Create a new Qmi8658 driver with default I2C address. + pub fn new(interface: I, delay: D) -> Self { + Self { + interface, + addr: DeviceAddress::Primary, + _delay: delay, + } + } + + /// Create new Qmi8658 driver with secondary I2C address. + pub fn new_secondary_address(interface: I, delay: D) -> Self { + Self { + interface, + addr: DeviceAddress::Secondary, + _delay: delay, + } + } + + /// Give back the I2C interface + pub fn release(self) -> I { + self.interface + } + + /// Get the device id + /// + /// # Errors + /// + pub fn get_device_id(&mut self) -> Result { + let mut buffer = [0u8; 1]; + self.interface + .write_read(self.addr.into(), &[WHO_AM_I], &mut buffer)?; + let value = match buffer[0] { + 0x05 => DeviceID::QSTSensor, + _ => DeviceID::Unknown, + }; + + Ok(value) + } + + /// Get the device revision id + /// + /// # Errors + /// + pub fn get_device_revision_id(&mut self) -> Result { + let mut buffer = [0u8; 1]; + self.interface + .write_read(self.addr.into(), &[WHO_AM_I], &mut buffer)?; + Ok(buffer[0]) + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..019608e --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,70 @@ +//! # QMI8658 Sensor/Gyroscope +//! +//! ## Support +//! +//! - [Embedded-hal v1.0.0](https://github.com/rust-embedded/embedded-hal/tree/embedded-hal-v1.0.0) +//! +//! ## Example +//! +//! - [Waveshare esp32-s3-touch-lcd-1-28](https://github.com/IniterWorker/esp32-s3-touch-lcd-1-28) +//! + +#![cfg_attr(not(test), no_std)] +// clippy warning level lints +#![warn( + // missing_docs, + clippy::pedantic, + clippy::nursery, + clippy::dbg_macro, + clippy::unwrap_used, + clippy::map_err_ignore, + clippy::panic, + clippy::unimplemented, + clippy::unreachable, + clippy::clone_on_ref_ptr, + clippy::create_dir, + clippy::exit, + clippy::filetype_is_file, + clippy::float_cmp_const, + clippy::indexing_slicing, + clippy::let_underscore_must_use, + clippy::lossy_float_literal, + clippy::pattern_type_mismatch, + clippy::string_slice, + clippy::try_err +)] +// clippy deny/error level lints, they always have quick fix that should be preferred +#![deny( + clippy::multiple_inherent_impl, + clippy::rc_buffer, + clippy::rc_mutex, + clippy::rest_pat_in_fully_bound_structs, + clippy::self_named_module_files, + clippy::separated_literal_suffix, + clippy::str_to_string, + clippy::string_add, + clippy::string_to_string, + clippy::unnecessary_self_imports, + clippy::unneeded_field_pattern, + clippy::verbose_file_reads +)] +// allowed rules +#![allow( + clippy::module_name_repetitions, + clippy::similar_names, + clippy::cast_possible_truncation, + clippy::redundant_pub_crate, + clippy::indexing_slicing +)] + +// export commands +pub mod command; +// prelude +pub mod prelude; + +mod bitfield_helper; + +mod driver; + +// export the driver and interface +pub use driver::Qmi8658; diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 0000000..b28b396 --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1 @@ +//! Crate prelude