diff --git a/Cargo.lock b/Cargo.lock index b6ad467..9a10af5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,47 +1,3 @@ -[[package]] -name = "aho-corasick" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ansi_term" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "atty" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bindgen" -version = "0.35.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "clang-sys 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "bitflags" version = "1.0.1" @@ -51,11 +7,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "bme680-rs" version = "0.1.0" dependencies = [ - "bindgen 0.35.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "embedded-hal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -63,48 +17,6 @@ name = "byteorder" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "cc" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cexpr" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cfg-if" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "clang-sys" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "clap" -version = "2.31.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "embedded-hal" version = "0.1.2" @@ -113,293 +25,13 @@ dependencies = [ "nb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "env_logger" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gcc" -version = "0.3.54" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "glob" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "humantime" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lazy_static" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.40" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libloading" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "log" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memchr" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memchr" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "nb" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "nom" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quick-error" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quote" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_syscall" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_termios" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "strsim" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "termcolor" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "termion" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "textwrap" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ucd-util" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-width" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unreachable" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "utf8-ranges" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "vec_map" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "which" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "wincolor" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [metadata] -"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" -"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4" -"checksum bindgen 0.35.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b023955126e7909ab9fc1d1973965b8b004f1f388afb5c589640ab483b3b0ad2" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87" -"checksum cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2b4911e4bdcb4100c7680e7e854ff38e23f1b34d4d9e079efae3da2801341ffc" -"checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c" -"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" -"checksum clang-sys 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "939a1a34310b120d26eba35c29475933128b0ec58e24b43327f8dbe6036fc538" -"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536" "checksum embedded-hal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "684b1fa3196f78342296d04edc2a6e5d053729d1b64a819dcb072810d706e267" -"checksum env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0561146661ae44c579e993456bc76d11ce1e0c7d745e57b2fa7146b6e49fa2ad" -"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" -"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" -"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" -"checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" -"checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" -"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" -"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" -"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum nb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "69f380b5fe9fab8c0d7a6a99cda23e2cc0463bedb2cbc3aada0813b98496ecdc" -"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" -"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" -"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4" -"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "aec3f58d903a7d2a9dc2bf0e41a746f4530e0cab6b615494e058f67a3ef947fb" -"checksum regex-syntax 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b2550876c31dc914696a6c2e01cbce8afba79a93c8ae979d2fe051c0230b3756" -"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" -"checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" -"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" -"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" -"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" -"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" -"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e84a603e7e0b1ce1aa1ee2b109c7be00155ce52df5081590d1ffb93f4f515cb2" -"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" diff --git a/Cargo.toml b/Cargo.toml index 24ff766..743ad98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,9 @@ [package] name = "bme680-rs" version = "0.1.0" -build = "build.rs" authors = ["marcelbuesing "] [dependencies] +bitflags = "1.0" byteorder = "1.2" embedded-hal = "0.1" - -[build-dependencies] -bindgen = "0.35" -bitflags = "1.0" -gcc = "0.3" diff --git a/build.rs b/build.rs deleted file mode 100644 index d503fce..0000000 --- a/build.rs +++ /dev/null @@ -1,34 +0,0 @@ -extern crate bindgen; -extern crate gcc; - -use std::env; -use std::path::PathBuf; - -fn main() { - // Tell cargo to tell rustc to link the system bzip2 - // shared library. - //println!("cargo:rustc-link-lib=bz2"); - - // gcc::Config::new() - // .file("BME680_driver/bme680.c") - // .include("BME680_driver") - // .compile("bme680.a"); - // - // // The bindgen::Builder is the main entry point - // // to bindgen, and lets you build up options for - // // the resulting bindings. - // let bindings = bindgen::Builder::default() - // // The input header we would like to generate - // // bindings for. - // .header("wrapper.h") - // // Finish the builder and generate the bindings. - // .generate() - // // Unwrap the Result and panic on failure. - // .expect("Unable to generate bindings"); - // - // // Write the bindings to the $OUT_DIR/bindings.rs file. - // let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - // bindings - // .write_to_file(out_path.join("bindings.rs")) - // .expect("Couldn't write bindings!"); -} diff --git a/src/bme680.rs b/src/bme680.rs deleted file mode 100644 index beeddc8..0000000 --- a/src/bme680.rs +++ /dev/null @@ -1,907 +0,0 @@ -use hal::blocking::delay::DelayMs; -use hal::blocking::i2c::{Read, Write}; -use std::convert::TryFrom; - -use std::result; - -/** BME680 General config */ -pub const BME680_POLL_PERIOD_MS: u8 = 10; - -/** BME680 I2C addresses */ -pub const BME680_I2C_ADDR_PRIMARY: u8 = 0x76; -pub const BME680_I2C_ADDR_SECONDARY: u8 = 0x77; - -/** BME680 unique chip identifier */ -pub const BME680_CHIP_ID: u8 = 0x61; - -/** BME680 coefficients related defines */ -pub const BME680_COEFF_SIZE: usize = 41; -pub const BME680_COEFF_ADDR1_LEN: u8 = 25; -pub const BME680_COEFF_ADDR2_LEN: u8 = 16; - -/** BME680 field_x related defines */ -pub const BME680_FIELD_LENGTH: u8 = 15; -pub const BME680_FIELD_ADDR_OFFSET: u8 = 17; - -pub const BME680_SOFT_RESET_CMD: u8 = 0xb6; - -pub const BME680_OK: i8 = 0; - -/** Errors **/ -pub const BME680_E_NULL_PTR: i8 = -1; -pub const BME680_E_COM_FAIL: i8 = -2; -pub const BME680_E_DEV_NOT_FOUND: i8 = -3; -pub const BME680_E_INVALID_LENGTH: i8 = -4; - -/** Register map */ -/** Other coefficient's address */ -pub const BME680_ADDR_RES_HEAT_VAL_ADDR: u8 = 0x00; -pub const BME680_ADDR_RES_HEAT_RANGE_ADDR: u8 = 0x02; -pub const BME680_ADDR_RANGE_SW_ERR_ADDR: u8 = 0x04; -pub const BME680_ADDR_SENS_CONF_START: u8 = 0x5A; -pub const BME680_ADDR_GAS_CONF_START: u8 = 0x64; - -pub const BME680_SOFT_RESET_ADDR: u8 = 0xe0; - -/** Field settings */ -pub const BME680_FIELD0_ADDR: u8 = 0x1d; - -/** Heater settings */ -pub const BME680_RES_HEAT0_ADDR: u8 = 0x5a; -pub const BME680_GAS_WAIT0_ADDR: u8 = 0x64; - -/** Sensor configuration registers */ -pub const BME680_CONF_HEAT_CTRL_ADDR: u8 = 0x70; -pub const BME680_CONF_ODR_RUN_GAS_NBC_ADDR: u8 = 0x71; -pub const BME680_CONF_OS_H_ADDR: u8 = 0x72; -pub const BME680_MEM_PAGE_ADDR: u8 = 0xf3; -pub const BME680_CONF_T_P_MODE_ADDR: u8 = 0x74; -pub const BME680_CONF_ODR_FILT_ADDR: u8 = 0x75; - -/** Coefficient's address */ -pub const BME680_COEFF_ADDR1: u8 = 0x89; -pub const BME680_COEFF_ADDR2: u8 = 0xe1; - -/** Chip identifier */ -pub const BME680_CHIP_ID_ADDR: u8 = 0xd0; - -pub const BME680_SLEEP_MODE: u8 = 0; -pub const BME680_FORCED_MODE: u8 = 1; - -pub const BME680_RESET_PERIOD: u8 = 10; - -pub const BME680_GAS_MEAS_MSK: u8 = 0x30; -pub const BME680_NBCONV_MSK: u8 = 0x0F; -pub const BME680_FILTER_MSK: u8 = 0x1C; -pub const BME680_OST_MSK: u8 = 0xE0; -pub const BME680_OSP_MSK: u8 = 0x1C; -pub const BME680_OSH_MSK: u8 = 0x07; -pub const BME680_HCTRL_MSK: u8 = 0x08; -pub const BME680_RUN_GAS_MSK: u8 = 0x10; -pub const BME680_MODE_MSK: u8 = 0x03; -pub const BME680_RHRANGE_MSK: u8 = 0x30; -pub const BME680_RSERROR_MSK: u8 = 0xf0; -pub const BME680_NEW_DATA_MSK: u8 = 0x80; -pub const BME680_GAS_INDEX_MSK: u8 = 0x0f; -pub const BME680_GAS_RANGE_MSK: u8 = 0x0f; -pub const BME680_GASM_VALID_MSK: u8 = 0x20; -pub const BME680_HEAT_STAB_MSK: u8 = 0x10; -pub const BME680_MEM_PAGE_MSK: u8 = 0x10; -pub const BME680_SPI_RD_MSK: u8 = 0x80; -pub const BME680_SPI_WR_MSK: u8 = 0x7f; -pub const BME680_BIT_H1_DATA_MSK: u8 = 0x0F; - -/// -/// SPI memory page settings -/// -pub const BME680_MEM_PAGE0: u8 = 0x10; - -/// -/// SPI memory page settings -/// -pub const BME680_MEM_PAGE1: u8 = 0x00; - -/** Buffer length macro declaration */ -pub const BME680_TMP_BUFFER_LENGTH: usize = 40; -pub const BME680_REG_BUFFER_LENGTH: usize = 6; -pub const BME680_FIELD_DATA_LENGTH: usize = 3; -pub const BME680_GAS_REG_BUF_LENGTH: usize = 20; - -/* Settings selector */ -pub const BME680_OST_SEL: u16 = 1; -pub const BME680_OSP_SEL: u16 = 2; -pub const BME680_OSH_SEL: u16 = 4; -pub const BME680_GAS_MEAS_SEL: u16 = 8; -pub const BME680_FILTER_SEL: u16 = 16; -pub const BME680_HCNTRL_SEL: u16 = 32; -pub const BME680_RUN_GAS_SEL: u16 = 64; -pub const BME680_NBCONV_SEL: u16 = 128; -pub const BME680_GAS_SENSOR_SEL: u16 = BME680_GAS_MEAS_SEL | BME680_RUN_GAS_SEL | BME680_NBCONV_SEL; - -pub enum Bme680Error { - /// - /// aka BME680_E_NULL_PTR - /// - NulltPtr, - /// - /// aka BME680_E_COM_FAIL - /// - CommunicationFailure, - /// - /// aka BME680_E_DEV_NOT_FOUND - /// - DeviceNotFound, - /// - /// aka BME680_E_INVALID_LENGTH - /// - InvalidLength, - /// - /// Warning aka BME680_W_DEFINE_PWR_MODE - /// - DefinePwrMode, - /// - /// Warning aka BME680_W_DEFINE_PWR_MODE - /// - NoNewData, - /// - /// Warning Boundary Check - /// - BoundaryCheckFailure(InfoMsg, u8, u8), -} - -pub type Result = result::Result; - -/// -/// Power mode settings -/// -#[derive(PartialEq, Clone, Copy)] -pub enum PowerMode { - SleepMode, - ForcedMode, -} - -impl PowerMode { - fn from(power_mode: u8) -> Self { - match power_mode { - BME680_SLEEP_MODE => PowerMode::SleepMode, - BME680_FORCED_MODE => PowerMode::ForcedMode, - _ => panic!("Unknown power mode: {}", power_mode), - } - } - - fn value(&self) -> u8 { - match self { - PowerMode::SleepMode => BME680_SLEEP_MODE, - PowerMode::ForcedMode => BME680_FORCED_MODE, - } - } -} - -#[derive(Clone, Copy)] -#[repr(i32)] -pub enum Bme680_intf { - BME680_SPI_INTF, - BME680_I2C_INTF, -} - -#[derive(Default, Copy)] -#[repr(C)] -pub struct CalibData { - pub par_h1: u16, - pub par_h2: u16, - pub par_h3: i8, - pub par_h4: i8, - pub par_h5: i8, - pub par_h6: u8, - pub par_h7: i8, - pub par_gh1: i8, - pub par_gh2: i16, - pub par_gh3: i8, - pub par_t1: u16, - pub par_t2: i16, - pub par_t3: i8, - pub par_p1: u16, - pub par_p2: i16, - pub par_p3: i8, - pub par_p4: i16, - pub par_p5: i16, - pub par_p6: i8, - pub par_p7: i8, - pub par_p8: i16, - pub par_p9: i16, - pub par_p10: u8, - pub t_fine: i32, - pub res_heat_range: u8, - pub res_heat_val: i8, - pub range_sw_err: u8, -} - -impl Clone for CalibData { - fn clone(&self) -> Self { - *self - } -} - -#[derive(Default, Copy)] -#[repr(C)] -pub struct TphSett { - pub os_hum: Option, - pub os_temp: Option, - pub os_pres: Option, - pub filter: Option, -} - -impl Clone for TphSett { - fn clone(&self) -> Self { - *self - } -} - -#[derive(Default, Copy)] -#[repr(C)] -pub struct GasSett { - pub nb_conv: Option, - pub heatr_ctrl: Option, - pub run_gas: Option, - pub heatr_temp: Option, - pub heatr_dur: Option, -} - -impl Clone for GasSett { - fn clone(&self) -> Self { - *self - } -} - -#[derive(Default, Copy)] -#[repr(C)] -pub struct FieldData { - pub status: u8, - pub gas_index: u8, - pub meas_index: u8, - pub temperature: i16, - pub pressure: u32, - pub humidity: u32, - pub gas_resistance: u32, -} - -impl Clone for FieldData { - fn clone(&self) -> Self { - *self - } -} - -/// TODO - replace naming of "State" with something better -/// aka new_fields - BME680_NEW_DATA_MSK -/// -pub enum FieldDataState { - NewData, - // TODO find better naming to no new data - NoNewData, -} - -/// Infos -bitflags! { - #[derive(Default)] - pub struct InfoMsg: u8 { - const MIN_CORRECTION = 1; - const MAX_CORRECTION = 2; - } -} - -#[derive(Default)] -pub struct SensorSettings { - gas_sett: GasSett, - tph_sett: TphSett, -} - -bitflags! { - pub struct DesiredSensorSettings: u16 { - /// To set temperature oversampling - const OST_SEL = 1; - /// To set pressure oversampling. - const OSP_SEL = 2; - - /// To set humidity oversampling. - const OSH_SEL = 4; - /// To set gas measurement setting. - const GAS_MEAS_SEL = 8; - /// To set filter setting. - const FILTER_SEL = 16; - /// To set humidity control setting. - const HCNTRL_SEL = 32; - /// To set run gas setting. - const RUN_GAS_SEL = 64; - /// To set NB conversion setting. - const NBCONV_SEL = 128; - /// To set all gas sensor related settings - const GAS_SENSOR_SEL = Self::GAS_MEAS_SEL.bits | Self::RUN_GAS_SEL.bits | Self::NBCONV_SEL.bits; - } -} - -#[repr(C)] -pub struct Bme680_dev { - pub i2c: I2C, - pub delay: D, - pub dev_id: u8, - pub mem_page: u8, - pub amb_temp: i8, - pub calib: CalibData, - pub tph_sett: TphSett, - pub gas_sett: GasSett, - pub power_mode: PowerMode, - pub new_fields: u8, - pub info_msg: u8, -} - -fn boundary_check(value: Option, min: u8, max: u8) -> Result { - let mut info_msg: InfoMsg = Default::default(); - - // TODO give the nullptr here a different name - let value = value.ok_or(Bme680Error::NulltPtr)?; - - if value < min { - info_msg |= InfoMsg::MIN_CORRECTION; - } - - if value > max { - info_msg |= InfoMsg::MAX_CORRECTION; - } - - if info_msg.is_empty() { - return Err(Bme680Error::BoundaryCheckFailure(info_msg, min, max)); - } - Ok(value) -} - -impl Bme680_dev -where - D: DelayMs, - I2C: Read + Write, -{ - pub fn init(&mut self) -> Result<()> { - self.soft_reset()?; - - /* Soft reset to restore it to default values*/ - let chip_id = self.get_regs_u8(BME680_CHIP_ID_ADDR)?; - if chip_id == BME680_CHIP_ID { - self.calib = self.get_calib_data()?; - Ok(()) - } else { - Err(Bme680Error::DeviceNotFound) - } - } - - pub fn get_regs_u8(&mut self, reg_addr: u8) -> Result { - let mut buf = [0; 1]; - match self.i2c.read(reg_addr, &mut buf) { - Ok(()) => Ok(buf[0]), - Err(_) => Err(Bme680Error::CommunicationFailure), - } - } - - pub fn get_regs_i8(&mut self, reg_addr: u8) -> Result { - let mut buf = [0; 1]; - match self.i2c.read(reg_addr, &mut buf) { - Ok(()) => Ok(i8::try_from(buf[0]).expect("U8 overflow when reading register")), - Err(_) => Err(Bme680Error::CommunicationFailure), - } - } - - pub fn bme680_set_regs(&mut self, reg: &[(u8, u8)]) -> Result<()> { - if reg.is_empty() || reg.len() > (BME680_TMP_BUFFER_LENGTH / 2) as usize { - return Err(Bme680Error::InvalidLength); - } - - let mut tmp_buff = Vec::with_capacity(BME680_TMP_BUFFER_LENGTH); - - for (reg_addr, reg_data) in reg { - tmp_buff.push(reg_addr.to_owned()); - tmp_buff.push(reg_data.to_owned()); - } - - self.i2c - .write(self.dev_id, tmp_buff.as_slice()) - .map_err(|_| Bme680Error::CommunicationFailure) - } - - pub fn soft_reset(&mut self) -> Result<()> { - self.bme680_set_regs(&[(BME680_SOFT_RESET_ADDR, BME680_SOFT_RESET_CMD)])?; - self.delay.delay_ms(BME680_RESET_PERIOD); - Ok(()) - } - - // TODO replace parameter desired_settings with safe flags - pub fn bme680_set_sensor_settings( - &mut self, - desired_settings: DesiredSensorSettings, - gas_sett: Option, - ) -> Result<()> { - let mut reg_addr: u8; - - let mut reg = Vec::with_capacity(BME680_REG_BUFFER_LENGTH); - let intended_power_mode = self.power_mode; - - if desired_settings.contains(DesiredSensorSettings::GAS_MEAS_SEL) { - self.set_gas_config(gas_sett.unwrap())?; - } - - let power_mode = self.power_mode; - self.bme680_set_sensor_mode(power_mode)?; - - /* Selecting the filter */ - if desired_settings.contains(DesiredSensorSettings::FILTER_SEL) { - let tph_sett_filter = boundary_check(self.tph_sett.filter, 0, 7)?; - reg_addr = 0x75u8; - let mut data = self.get_regs_u8(reg_addr)?; - - // TODO duplicate check of condition ? - if desired_settings.contains(DesiredSensorSettings::FILTER_SEL) { - data = (data as (i32) & !0x1ci32 |tph_sett_filter as (i32) << 2i32 & 0x1ci32) - as (u8); - } - reg.push((reg_addr, data)); - } - - if desired_settings.contains(DesiredSensorSettings::HCNTRL_SEL) { - - let gas_sett_heatr_ctrl = boundary_check(self.gas_sett.heatr_ctrl, 0x0u8, 0x8u8)?; - reg_addr = 0x70u8; - let mut data = self.get_regs_u8(reg_addr)?; - data = (data as (i32) & !0x8i32 | gas_sett_heatr_ctrl as (i32) & 0x8) as (u8) ; - reg.push((reg_addr, data)); - } - - /* Selecting heater T,P oversampling for the sensor */ - if desired_settings - .contains(DesiredSensorSettings::OST_SEL | DesiredSensorSettings::OSP_SEL) - { - reg_addr = 0x74u8; - let mut data = self.get_regs_u8(reg_addr)?; - - if desired_settings.contains(DesiredSensorSettings::OST_SEL) { - let tph_sett_os_temp = boundary_check(self.tph_sett.os_temp, 0, 5)?; - data = (data as (i32) & !0xe0i32 | tph_sett_os_temp as (i32) << 5i32 & 0xe0i32) - as (u8); - } - - if desired_settings.contains(DesiredSensorSettings::OSP_SEL) { - let tph_sett_os_pres = self.tph_sett.os_temp.ok_or(Bme680Error::NulltPtr)?; - data = (data as (i32) & !0x1ci32 | tph_sett_os_pres as (i32) << 2i32 & 0x1ci32) - as (u8); - } - - reg.push((reg_addr, data)); - } - - /* Selecting humidity oversampling for the sensor */ - if desired_settings.contains(DesiredSensorSettings::OSH_SEL) { - let tph_sett_os_hum = boundary_check(self.tph_sett.os_hum, 0, 5)?; - reg_addr = 0x72u8; - let mut data = self.get_regs_u8(reg_addr)?; - data = (data as (i32) & !0x7i32 | tph_sett_os_hum as (i32) & 0x7i32) as (u8); - reg.push((reg_addr, data)); - } - - /* Selecting the runGas and NB conversion settings for the sensor */ - if desired_settings - .contains(DesiredSensorSettings::RUN_GAS_SEL | DesiredSensorSettings::NBCONV_SEL) - { - reg_addr = 0x71u8; - let mut data = self.get_regs_u8(reg_addr)?; - - if desired_settings.contains(DesiredSensorSettings::RUN_GAS_SEL) { - let gas_sett_run_gas = boundary_check(self.gas_sett.run_gas, 0, 1)?; - data = (data as (i32) & !0x10i32 | gas_sett_run_gas as (i32) << 4i32 & 0x10i32) - as (u8); - } - - if desired_settings.contains(DesiredSensorSettings::NBCONV_SEL) { - let gas_sett_nb_conv = boundary_check(self.gas_sett.nb_conv, 0, 10)?; - data = (data as (i32) & !0xfi32 | gas_sett_nb_conv as (i32) & 0xfi32) as (u8); - } - - reg.push((reg_addr, data)); - } - - self.bme680_set_regs(reg.as_slice())?; - - /* Restore previous intended power mode */ - self.power_mode = intended_power_mode; - Ok(()) - } - - // TODO replace desired_settings with proper flags type see lib.rs - pub fn get_sensor_settings(&mut self, desired_settings: u16) -> Result { - let reg_addr: u8 = 0x70u8; - let mut data_array: [u8; BME680_REG_BUFFER_LENGTH] = [0; BME680_REG_BUFFER_LENGTH]; - let mut sensor_settings: SensorSettings = Default::default(); - - self.i2c.read(reg_addr, &mut data_array).map_err(|_| Bme680Error::CommunicationFailure)?; - - if desired_settings & BME680_GAS_MEAS_SEL != 0 { - sensor_settings.gas_sett = self.get_gas_config()?; - } - - if desired_settings & BME680_FILTER_SEL != 0 { - sensor_settings.tph_sett.filter = - Some(((data_array[5usize] as (i32) & 0x1ci32) >> 2i32) as (u8)); - } - - if desired_settings & (BME680_OST_SEL | BME680_OSP_SEL) != 0 { - sensor_settings.tph_sett.os_temp = - Some(((data_array[4usize] as (i32) & 0xe0i32) >> 5i32) as (u8)); - sensor_settings.tph_sett.os_pres = - Some(((data_array[4usize] as (i32) & 0x1ci32) >> 2i32) as (u8)); - } - - if desired_settings & BME680_OSH_SEL != 0 { - sensor_settings.tph_sett.os_hum = Some((data_array[2usize] as (i32) & 0x7i32) as (u8)); - } - - if desired_settings & BME680_HCNTRL_SEL != 0 { - sensor_settings.gas_sett.heatr_ctrl = Some((data_array[0usize] as (i32) & 0x8i32) as (u8)); - } - - if desired_settings & (BME680_RUN_GAS_SEL | BME680_NBCONV_SEL) != 0 { - sensor_settings.gas_sett.nb_conv = Some((data_array[1usize] as (i32) & 0xfi32) as (u8)); - sensor_settings.gas_sett.run_gas = - Some(((data_array[1usize] as (i32) & 0x10i32) >> 4i32) as (u8)); - } - - Ok(sensor_settings) - } - - pub fn bme680_set_sensor_mode(&mut self, target_power_mode: PowerMode) -> Result<()> { - let mut tmp_pow_mode: u8; - let mut current_power_mode: PowerMode; - let reg_addr: u8 = 0x74u8; - - /* Call repeatedly until in sleep */ - loop { - tmp_pow_mode = self.get_regs_u8(BME680_CONF_T_P_MODE_ADDR)?; - - /* Put to sleep before changing mode */ - current_power_mode = PowerMode::from(tmp_pow_mode & BME680_MODE_MSK); - if current_power_mode != PowerMode::SleepMode { - /* Set to sleep*/ - tmp_pow_mode = tmp_pow_mode & !BME680_MODE_MSK; - let reg = vec!((reg_addr, tmp_pow_mode)); - self.bme680_set_regs(reg.as_slice())?; - self.delay.delay_ms(BME680_POLL_PERIOD_MS); - } else { - // TODO do while in Rust? - break; - } - } - - /* Already in sleep */ - if current_power_mode != PowerMode::SleepMode { - tmp_pow_mode = tmp_pow_mode & !BME680_MODE_MSK | target_power_mode.value(); - self.bme680_set_regs(&[(reg_addr, tmp_pow_mode)])?; - } - Ok(()) - } - - pub fn get_sensor_mode(&mut self) -> Result { - let regs = self.get_regs_u8(BME680_CONF_T_P_MODE_ADDR)?; - let mode = regs & BME680_MODE_MSK; - Ok(PowerMode::from(mode)) - } - - pub fn bme680_set_profile_dur(&mut self, tph_sett: TphSett, duration: u16) { - let os_to_meas_cycles: [u8; 6] = [0u8, 1u8, 2u8, 4u8, 8u8, 16u8]; - // TODO check if the following unwrap_ors do not change behaviour - let mut meas_cycles = os_to_meas_cycles[tph_sett.os_temp.unwrap_or(0) as (usize)] as (u32); - meas_cycles = - meas_cycles.wrapping_add(os_to_meas_cycles[tph_sett.os_pres.unwrap_or(0) as (usize)] as (u32)); - meas_cycles = - meas_cycles.wrapping_add(os_to_meas_cycles[tph_sett.os_hum.unwrap_or(0) as (usize)] as (u32)); - let mut tph_dur = meas_cycles.wrapping_mul(1963u32); - tph_dur = tph_dur.wrapping_add(477u32.wrapping_mul(4u32)); - tph_dur = tph_dur.wrapping_add(477u32.wrapping_mul(5u32)); - tph_dur = tph_dur.wrapping_add(500u32); - tph_dur = tph_dur.wrapping_div(1000u32); - tph_dur = tph_dur.wrapping_add(1u32); - self.gas_sett.heatr_dur = Some((duration as (i32) - tph_dur as (u16) as (i32)) as (u16)); - } - - pub fn get_profile_dur(&self, tph_sett: TphSett, gas_sett: GasSett) -> Result { - let os_to_meas_cycles: [u8; 6] = [0u8, 1u8, 2u8, 4u8, 8u8, 16u8]; - // TODO check if the following unwrap_ors do not change behaviour - let mut meas_cycles = os_to_meas_cycles[tph_sett.os_temp.unwrap_or(0) as (usize)] as (u32); - meas_cycles = - meas_cycles.wrapping_add(os_to_meas_cycles[tph_sett.os_pres.unwrap_or(0) as (usize)] as (u32)); - meas_cycles = - meas_cycles.wrapping_add(os_to_meas_cycles[tph_sett.os_hum.unwrap_or(0) as (usize)] as (u32)); - let mut tph_dur = meas_cycles.wrapping_mul(1963u32); - tph_dur = tph_dur.wrapping_add(477u32.wrapping_mul(4u32)); - tph_dur = tph_dur.wrapping_add(477u32.wrapping_mul(5u32)); - tph_dur = tph_dur.wrapping_add(500u32); - tph_dur = tph_dur.wrapping_div(1000u32); - tph_dur = tph_dur.wrapping_add(1u32); - let mut duration = tph_dur as (u16); - if gas_sett.run_gas.unwrap_or(0) != 0 { - duration = duration + gas_sett.heatr_dur.ok_or(Bme680Error::NulltPtr)?; - } - Ok(duration) - } - - /// @returns (FieldData, IsNewFields) - pub fn get_sensor_data(&mut self) -> Result<(FieldData, FieldDataState)> { - let field_data = self.read_field_data()?; - if field_data.status & BME680_NEW_DATA_MSK != 0 { - // new fields - Ok((field_data, FieldDataState::NewData)) - } else { - Ok((field_data, FieldDataState::NoNewData)) - } - } - - fn get_calib_data(&mut self) -> Result { - let mut calib: CalibData = Default::default(); - let mut coeff_array: [u8; BME680_COEFF_SIZE] = [0; BME680_COEFF_SIZE]; - - self.i2c.read( - BME680_COEFF_ADDR1, - &mut coeff_array, - ).map_err(|_| Bme680Error::CommunicationFailure)?; - - self.i2c.read( - BME680_COEFF_ADDR2, - &mut coeff_array, - ).map_err(|_| Bme680Error::CommunicationFailure)?; - - calib.par_t1 = (coeff_array[34usize] as (u16) as (i32) << 8i32 - | coeff_array[33usize] as (u16) as (i32)) as (u16); - calib.par_t2 = (coeff_array[2usize] as (u16) as (i32) << 8i32 - | coeff_array[1usize] as (u16) as (i32)) as (i16); - calib.par_t3 = coeff_array[3usize] as (i8); - calib.par_p1 = (coeff_array[6usize] as (u16) as (i32) << 8i32 - | coeff_array[5usize] as (u16) as (i32)) as (u16); - calib.par_p2 = (coeff_array[8usize] as (u16) as (i32) << 8i32 - | coeff_array[7usize] as (u16) as (i32)) as (i16); - calib.par_p3 = coeff_array[9usize] as (i8); - calib.par_p4 = (coeff_array[12usize] as (u16) as (i32) << 8i32 - | coeff_array[11usize] as (u16) as (i32)) as (i16); - calib.par_p5 = (coeff_array[14usize] as (u16) as (i32) << 8i32 - | coeff_array[13usize] as (u16) as (i32)) as (i16); - calib.par_p6 = coeff_array[16usize] as (i8); - calib.par_p7 = coeff_array[15usize] as (i8); - calib.par_p8 = (coeff_array[20usize] as (u16) as (i32) << 8i32 - | coeff_array[19usize] as (u16) as (i32)) as (i16); - calib.par_p9 = (coeff_array[22usize] as (u16) as (i32) << 8i32 - | coeff_array[21usize] as (u16) as (i32)) as (i16); - calib.par_p10 = coeff_array[23usize]; - calib.par_h1 = (coeff_array[27usize] as (u16) as (i32) << 4i32 - | coeff_array[26usize] as (i32) & 0xfi32) as (u16); - calib.par_h2 = (coeff_array[25usize] as (u16) as (i32) << 4i32 - | coeff_array[26usize] as (i32) >> 4i32) as (u16); - calib.par_h3 = coeff_array[28usize] as (i8); - calib.par_h4 = coeff_array[29usize] as (i8); - calib.par_h5 = coeff_array[30usize] as (i8); - calib.par_h6 = coeff_array[31usize]; - calib.par_h7 = coeff_array[32usize] as (i8); - calib.par_gh1 = coeff_array[37usize] as (i8); - calib.par_gh2 = (coeff_array[36usize] as (u16) as (i32) << 8i32 - | coeff_array[35usize] as (u16) as (i32)) as (i16); - calib.par_gh3 = coeff_array[38usize] as (i8); - - calib.res_heat_range = (self.get_regs_u8(BME680_ADDR_RES_HEAT_RANGE_ADDR)? & 0x30) / 16; - - calib.res_heat_val = self.get_regs_i8(BME680_ADDR_RES_HEAT_VAL_ADDR)?; - - calib.range_sw_err = (self.get_regs_u8(BME680_ADDR_RANGE_SW_ERR_ADDR)? & BME680_RSERROR_MSK) / 16; - - Ok(calib) - } - - fn set_gas_config(&mut self, gas_sett: GasSett) -> Result<()> { - let mut reg = Vec::with_capacity(2); - - if self.power_mode != PowerMode::ForcedMode { - return Err(Bme680Error::DefinePwrMode); - } - - // TODO check whether unwrap_or changes behaviour - reg.push((BME680_RES_HEAT0_ADDR, self.calc_heater_res(gas_sett.heatr_temp.unwrap_or(0)))); - reg.push((BME680_GAS_WAIT0_ADDR, self.calc_heater_dur(gas_sett.heatr_dur.unwrap_or(0)))); - - self.gas_sett.nb_conv = Some(0); - self.bme680_set_regs(reg.as_slice()) - } - - fn get_gas_config(&mut self) -> Result { - // TODO move both GasSett fields to new struct - let mut gas_sett: GasSett = Default::default(); - // TODO figure out if heat_temp and dur can be u8 - gas_sett.heatr_temp = Some(self.get_regs_u8(BME680_ADDR_SENS_CONF_START)? as u16); - gas_sett.heatr_dur = Some(self.get_regs_u8(BME680_ADDR_GAS_CONF_START)? as u16); - Ok(gas_sett) - } - - fn calc_heater_res(&self, temp: u16) -> u8 { - // cap temperature - let temp = if temp <= 400 { temp } else { 400 }; - - let var1 = self.amb_temp as (i32) * self.calib.par_gh3 as (i32) / 1000i32 * 256i32; - let var2 = (self.calib.par_gh1 as (i32) + 784i32) - * (((self.calib.par_gh2 as (i32) + 154009i32) * temp as (i32) * 5i32 / 100i32 - + 3276800i32) / 10i32); - let var3 = var1 + var2 / 2i32; - let var4 = var3 / (self.calib.res_heat_range as (i32) + 4i32); - let var5 = 131i32 * self.calib.res_heat_val as (i32) + 65536i32; - let heatr_res_x100 = (var4 / var5 - 250i32) * 34i32; - ((heatr_res_x100 + 50i32) / 100i32) as (u8) - } - - fn calc_heater_dur(&self, dur: u16) -> u8 { - let mut factor: u8 = 0u8; - let mut dur = dur; - let durval = - if dur as (i32) >= 0xfc0i32 { - 0xffu8 // Max duration - } else { - loop { - if !(dur as (i32) > 0x3fi32) { - break; - } - dur = (dur as (i32) / 4i32) as (u16); - factor = (factor as (i32) + 1i32) as (u8); - } - (dur as (i32) + factor as (i32) * 64i32) as (u8) - }; - durval - } - - fn calc_temperature(&mut self, temp_adc: u32) -> i16 { - let var1 = ((temp_adc as (i32) >> 3i32) - (self.calib.par_t1 as (i32) << 1i32)) as (isize); - let var2 = var1 * self.calib.par_t2 as (i32) as (isize) >> 11i32; - let var3 = (var1 >> 1i32) * (var1 >> 1i32) >> 12i32; - let var3 = var3 * (self.calib.par_t3 as (i32) << 4i32) as (isize) >> 14i32; - // TODO really assign here ? - self.calib.t_fine = (var2 + var3) as (i32); - let calc_temp = (self.calib.t_fine * 5i32 + 128i32 >> 8i32) as (i16); - calc_temp - } - - fn calc_pressure(&self, pres_adc: u32) -> u32 { - let mut var1 = (self.calib.t_fine >> 1i32) - 64000i32; - let mut var2 = ((var1 >> 2i32) * (var1 >> 2i32) >> 11i32) * self.calib.par_p6 as (i32) >> 2i32; - var2 = var2 + (var1 * self.calib.par_p5 as (i32) << 1i32); - var2 = (var2 >> 2i32) + (self.calib.par_p4 as (i32) << 16i32); - var1 = (((var1 >> 2i32) * (var1 >> 2i32) >> 13i32) * (self.calib.par_p3 as (i32) << 5i32) - >> 3i32) + (self.calib.par_p2 as (i32) * var1 >> 1i32); - var1 = var1 >> 18i32; - var1 = (32768i32 + var1) * self.calib.par_p1 as (i32) >> 15i32; - let mut pressure_comp = 1048576u32.wrapping_sub(pres_adc) as (i32); - pressure_comp = ((pressure_comp - (var2 >> 12i32)) as (u32)).wrapping_mul(3125u32) as (i32); - if pressure_comp >= 0x40000000i32 { - pressure_comp = ((pressure_comp as (u32)).wrapping_div(var1 as (u32)) << 1i32) as (i32); - } else { - pressure_comp = ((pressure_comp << 1i32) as (u32)).wrapping_div(var1 as (u32)) as (i32); - } - var1 = self.calib.par_p9 as (i32) - * ((pressure_comp >> 3i32) * (pressure_comp >> 3i32) >> 13i32) >> 12i32; - var2 = (pressure_comp >> 2i32) * self.calib.par_p8 as (i32) >> 13i32; - let var3 = (pressure_comp >> 8i32) * (pressure_comp >> 8i32) * (pressure_comp >> 8i32) - * self.calib.par_p10 as (i32) >> 17i32; - pressure_comp = - pressure_comp + (var1 + var2 + var3 + (self.calib.par_p7 as (i32) << 7i32) >> 4i32); - pressure_comp as (u32) - } - - fn calc_humidity(&self, hum_adc: u16) -> u32 { - let temp_scaled = self.calib.t_fine * 5i32 + 128i32 >> 8i32; - let var1 = hum_adc as (i32) - self.calib.par_h1 as (i32) * 16i32 - - (temp_scaled * self.calib.par_h3 as (i32) / 100i32 >> 1i32); - let var2 = self.calib.par_h2 as (i32) - * (temp_scaled * self.calib.par_h4 as (i32) / 100i32 - + (temp_scaled * (temp_scaled * self.calib.par_h5 as (i32) / 100i32) >> 6i32) - / 100i32 + (1i32 << 14i32)) >> 10i32; - let var3 = var1 * var2; - let var4 = self.calib.par_h6 as (i32) << 7i32; - let var4 = var4 + temp_scaled * self.calib.par_h7 as (i32) / 100i32 >> 4i32; - let var5 = (var3 >> 14i32) * (var3 >> 14i32) >> 10i32; - let var6 = var4 * var5 >> 1i32; - let mut calc_hum = (var3 + var6 >> 10i32) * 1000i32 >> 12i32; - if calc_hum > 100000i32 { - calc_hum = 100000i32; - } else if calc_hum < 0i32 { - calc_hum = 0i32; - } - calc_hum as (u32) - } - - fn calc_gas_resistance(&mut self, gas_res_adc: u16, gas_range: u8) -> u32 { - let lookupTable1: [u32; 16] = [ - 2147483647u32, - 2147483647u32, - 2147483647u32, - 2147483647u32, - 2147483647u32, - 2126008810u32, - 2147483647u32, - 2130303777u32, - 2147483647u32, - 2147483647u32, - 2143188679u32, - 2136746228u32, - 2147483647u32, - 2126008810u32, - 2147483647u32, - 2147483647u32, - ]; - let lookupTable2: [u32; 16] = [ - 4096000000u32, - 2048000000u32, - 1024000000u32, - 512000000u32, - 255744255u32, - 127110228u32, - 64000000u32, - 32258064u32, - 16016016u32, - 8000000u32, - 4000000u32, - 2000000u32, - 1, - 500000u32, - 250000u32, - 125000u32, - ]; - let var1 = (1340isize + 5isize * self.calib.range_sw_err as (isize)) - * lookupTable1[gas_range as (usize)] as (isize) >> 16i32; - let var2 = ((gas_res_adc as (isize) << 15i32) - 16777216isize + var1) as (usize); - let var3 = lookupTable2[gas_range as (usize)] as (isize) * var1 >> 9i32; - let calc_gas_res = ((var3 + (var2 as (isize) >> 1i32)) / var2 as (isize)) as (u32); - calc_gas_res - } - - fn read_field_data(&mut self) -> Result { - let mut buff = [0, BME680_FIELD_LENGTH]; - let mut data: FieldData = Default::default(); - let mut gas_range: u8; - let mut adc_temp: u32; - let mut adc_pres: u32; - let mut adc_hum: u16; - let mut adc_gas_res: u16; - let mut tries: u8 = 10u8; - - loop { - self.i2c.read(BME680_FIELD0_ADDR, &mut buff) - .map_err(|_| Bme680Error::CommunicationFailure)?; - data.status = buff[0] & BME680_NEW_DATA_MSK; - data.gas_index = buff[0] & BME680_GAS_INDEX_MSK;; - data.meas_index = buff[1]; - - adc_pres = (buff[2] as (u32)).wrapping_mul(4096) | (buff[3] as (u32)).wrapping_mul(16) - | (buff[4] as (u32)).wrapping_div(16); - adc_temp = (buff[5] as (u32)).wrapping_mul(4096) | (buff[6] as (u32)).wrapping_mul(16) - | (buff[7] as (u32)).wrapping_div(16); - adc_hum = ((buff[8] as (u32)).wrapping_mul(256) | buff[9] as (u32)) as (u16); - adc_gas_res = ((buff[13] as (u32)).wrapping_mul(4) - | (buff[14] as (u32)).wrapping_div(64)) as (u16); - gas_range = buff[14] & BME680_GAS_RANGE_MSK; - - data.status = data.status | buff[14] & BME680_GASM_VALID_MSK; - data.status = data.status | buff[14] & BME680_HEAT_STAB_MSK; - - if data.status & BME680_NEW_DATA_MSK != 0 { - data.temperature = self.calc_temperature(adc_temp); - data.pressure = self.calc_pressure(adc_pres); - data.humidity = self.calc_humidity(adc_hum); - data.gas_resistance = self.calc_gas_resistance(adc_gas_res, gas_range); - return Ok(data); - } - - self.delay.delay_ms(BME680_POLL_PERIOD_MS); - - tries = tries - 1; - if tries == 0 { - break; - } - } - Err(Bme680Error::NoNewData) - } -} diff --git a/src/consts.rs b/src/consts.rs deleted file mode 100644 index cb16986..0000000 --- a/src/consts.rs +++ /dev/null @@ -1,34 +0,0 @@ -pub const BME680_OK: i8 = 0; -pub const BME680_E_NULL_PTR: i8 = -1; -pub const BME680_E_COM_FAIL: i8 = -2; -pub const BME680_E_DEV_NOT_FOUND: i8 = -3; -pub const BME680_E_INVALID_LENGTH: i8 = -4; - -pub const BME680_I2C_ADDR_PRIMARY: u8 = 0x76; -pub const BME680_I2C_ADDR_SECONDARY: u8 = 0x77; - -pub const BME680_CHIP_ID: u8 = 0x61; - -pub const BME680_SLEEP_MODE: u8 = 0; -pub const BME680_FORCED_MODE: u8 = 1; - -/// -/// SPI memory page settings -/// -pub const BME680_MEM_PAGE0: u8 = 0x10; - -/// -/// SPI memory page settings -/// -pub const BME680_MEM_PAGE1: u8 = 0x00; - -/* Settings selector */ -pub const BME680_OST_SEL: u16 = 1; -pub const BME680_OSP_SEL: u16 = 2; -pub const BME680_OSH_SEL: u16 = 4; -pub const BME680_GAS_MEAS_SEL: u16 = 8; -pub const BME680_FILTER_SEL: u16 = 16; -pub const BME680_HCNTRL_SEL: u16 = 32; -pub const BME680_RUN_GAS_SEL: u16 = 64; -pub const BME680_NBCONV_SEL: u16 = 128; -pub const BME680_GAS_SENSOR_SEL: u16 = BME680_GAS_MEAS_SEL | BME680_RUN_GAS_SEL | BME680_NBCONV_SEL; diff --git a/src/device_builder.rs b/src/device_builder.rs deleted file mode 100644 index 795e154..0000000 --- a/src/device_builder.rs +++ /dev/null @@ -1,398 +0,0 @@ -use hal::blocking::delay::DelayMs; -use hal::blocking::i2c::{Read, Write, WriteRead}; - -use consts; -use {to_result, PowerMode, Result, SensorSettings, bme680_calib_data, bme680_dev, - bme680_field_data, bme680_gas_sett, bme680_get_profile_dur, bme680_get_regs, - bme680_get_sensor_data, bme680_get_sensor_mode, bme680_get_sensor_settings, bme680_init, - bme680_intf, bme680_intf_BME680_I2C_INTF, bme680_set_profile_dur, bme680_set_sensor_mode, - bme680_set_sensor_settings, bme680_soft_reset, bme680_tph_sett}; - -impl Default for bme680_field_data { - fn default() -> bme680_field_data { - bme680_field_data { - status: Default::default(), - /// The index of the heater profile used - gas_index: Default::default(), - /// Measurement index to track order - meas_index: Default::default(), - /// Temperature in degree celsius x100 - temperature: Default::default(), - /// Pressure in Pascal - pressure: Default::default(), - /// Humidity in % relative humidity x1000 - humidity: Default::default(), - /// Gas resistance in Ohms - gas_resistance: Default::default(), - } - } -} - -pub struct Bme680Device { - dev: bme680_dev, -} - -impl Bme680Device { - /// @brief This API is the entry point. - /// It reads the chip-id and calibration data from the sensor. - /// - /// @param[in,out] dev : Structure instance of bme680_dev - /// - /// @return Result of API execution status - pub fn init(mut self) -> Result<()> { - let dev_ptr: *mut bme680_dev = &mut self.dev; - unsafe { to_result(bme680_init(dev_ptr)) } - } - - /// @brief This API writes the given data to the register address - /// of the sensor. - /// - /// @param[in] reg_addr : Register address from where the data to be written. - /// @param[in] reg_data : Pointer to data buffer which is to be written - /// in the sensor. - /// @param[in] len : No of bytes of data to write.. - /// @param[in] dev : Structure instance of bme680_dev. - /// - /// @return Result of API execution status - pub fn set_regs(mut self, reg_addr: u8, reg_data: &mut [u8]) -> Result<()> { - let dev_ptr: *mut bme680_dev = &mut self.dev; - unsafe { - to_result(bme680_get_regs( - reg_addr, - reg_data.as_mut_ptr(), - reg_data.len() as u16, - dev_ptr, - )) - } - } - /// @brief This API reads the data from the given register address of the sensor. - /// - /// @param[in] reg_addr : Register address from where the data to be read - /// @param[out] reg_data : buffer to store the read data. - /// - /// @return Result of API execution status - pub fn get_regs(mut self, reg_addr: u8, reg_data: &mut [u8]) -> Result<()> { - let dev_ptr: *mut bme680_dev = &mut self.dev; - unsafe { - to_result(bme680_get_regs( - reg_addr, - reg_data.as_mut_ptr(), - reg_data.len() as u16, - dev_ptr, - )) - } - } - /// @brief This API performs the soft reset of the sensor. - /// - /// @return Result of API execution status - pub fn soft_reset(mut self) -> Result<()> { - let dev_ptr: *mut bme680_dev = &mut self.dev; - unsafe { to_result(bme680_soft_reset(dev_ptr)) } - } - - /// @brief This API is used to set the power mode of the sensor. - /// - /// @param[in] power_mode : Sensor power mode - /// - /// @return Result of API execution status - pub fn set_sensor_mode(mut self, power_mode: PowerMode) -> Result<()> { - self.dev.power_mode = power_mode.value(); - let dev_ptr: *mut bme680_dev = &mut self.dev; - unsafe { to_result(bme680_set_sensor_mode(dev_ptr)) } - } - - /// @brief This API is used to get the power mode of the sensor. - /// - /// @return Sensor power mode - pub fn get_sensor_mode(mut self) -> Result { - let dev_ptr: *mut bme680_dev = &mut self.dev; - let r = unsafe { to_result(bme680_get_sensor_mode(dev_ptr)) }; - r.map(|_| PowerMode::from(self.dev.power_mode)) - } - - /// @brief This API is used to set the profile duration of the sensor. - /// - /// @param[in] duration : Duration of the measurement in ms. - pub fn set_profile_dur(mut self, duration: u16) { - let dev_ptr: *mut bme680_dev = &mut self.dev; - unsafe { bme680_set_profile_dur(duration, dev_ptr) } - } - - /// @brief This API is used to get the profile duration of the sensor. - /// - /// @return Duration of the measurement in ms. - pub fn get_profile_dur(mut self) -> u16 { - let dev_ptr: *mut bme680_dev = &mut self.dev; - let mut duration = 0; - unsafe { bme680_get_profile_dur(&mut duration, dev_ptr) }; - duration - } - - /// @brief This API reads the pressure, temperature and humidity and gas data - /// from the sensor, compensates the data and store it in the bme680_data - /// structure instance passed by the user. - /// - /// @param[out] data: Structure instance to hold the data. - /// @param[in] dev : Structure instance of bme680_dev. - /// - /// @return Result of API execution status - pub fn get_sensor_data(mut self) -> Result { - let dev_ptr: *mut bme680_dev = &mut self.dev; - let mut field_data = Default::default(); - let field_data_ptr: *mut bme680_field_data = &mut field_data; - let r = unsafe { to_result(bme680_get_sensor_data(field_data_ptr, dev_ptr)) }; - r.map(|_| field_data) - } - - /// @brief This API is used to set the oversampling, filter and T,P,H, gas selection - /// settings in the sensor. - /// - /// @param[in] desired_settings : Variable used to select the settings which - /// @return Result of API execution status - - pub fn set_sensor_settings(mut self, sensor_settings: SensorSettings) -> Result<()> { - let dev_ptr: *mut bme680_dev = &mut self.dev; - unsafe { to_result(bme680_set_sensor_settings(sensor_settings.bits(), dev_ptr)) } - } - - pub fn get_tph_sett(mut self) -> Result { - let dev_ptr: *mut bme680_dev = &mut self.dev; - let settings_sel = SensorSettings::OST_SEL | SensorSettings::OSP_SEL - | SensorSettings::OSH_SEL | SensorSettings::FILTER_SEL; - - let r = unsafe { to_result(bme680_get_sensor_settings(settings_sel.bits(), dev_ptr)) }; - r.map(|_| self.dev.tph_sett) - } - - pub fn get_gas_sett(mut self) -> Result { - let dev_ptr: *mut bme680_dev = &mut self.dev; - let settings_sel = SensorSettings::GAS_SENSOR_SEL; - - let r = unsafe { to_result(bme680_get_sensor_settings(settings_sel.bits(), dev_ptr)) }; - r.map(|_| self.dev.gas_sett) - } -} - -impl Default for bme680_calib_data { - fn default() -> bme680_calib_data { - bme680_calib_data { - /// Variable to store calibrated humidity data - par_h1: Default::default(), - /// Variable to store calibrated humidity data - par_h2: Default::default(), - /// Variable to store calibrated humidity data - par_h3: Default::default(), - /// Variable to store calibrated humidity data - par_h4: Default::default(), - /// Variable to store calibrated humidity data - par_h5: Default::default(), - /// Variable to store calibrated humidity data - par_h6: Default::default(), - /// Variable to store calibrated humidity data - par_h7: Default::default(), - /// Variable to store calibrated gas data - par_gh1: Default::default(), - /// Variable to store calibrated gas data - par_gh2: Default::default(), - /// Variable to store calibrated gas data - par_gh3: Default::default(), - /// Variable to store calibrated temperature data - par_t1: Default::default(), - /// Variable to store calibrated temperature data - par_t2: Default::default(), - /// Variable to store calibrated temperature data - par_t3: Default::default(), - /// Variable to store calibrated pressure data - par_p1: Default::default(), - /// Variable to store calibrated pressure data - par_p2: Default::default(), - /// Variable to store calibrated pressure data - par_p3: Default::default(), - /// Variable to store calibrated pressure data - par_p4: Default::default(), - /// Variable to store calibrated pressure data - par_p5: Default::default(), - /// Variable to store calibrated pressure data - par_p6: Default::default(), - /// Variable to store calibrated pressure data - par_p7: Default::default(), - /// Variable to store calibrated pressure data - par_p8: Default::default(), - /// Variable to store calibrated pressure data - par_p9: Default::default(), - /// Variable to store calibrated pressure data - par_p10: Default::default(), - /// Variable to store t_fine size - t_fine: Default::default(), - /// Variable to store heater resistance range - res_heat_range: Default::default(), - /// Variable to store heater resistance value - res_heat_val: Default::default(), - /// Variable to store error range - range_sw_err: Default::default(), - } - } -} - -impl Default for bme680_gas_sett { - fn default() -> bme680_gas_sett { - bme680_gas_sett { - /// Variable to store nb conversion - nb_conv: Default::default(), - /// Variable to store heater control - heatr_ctrl: Default::default(), - /// Run gas enable value - run_gas: Default::default(), - /// Heater temperature value - heatr_temp: Default::default(), - /// Duration profile value - heatr_dur: Default::default(), - } - } -} - -impl Default for bme680_tph_sett { - fn default() -> bme680_tph_sett { - bme680_tph_sett { - /// Humidity oversampling - os_hum: Default::default(), - /// Temperature oversampling - os_temp: Default::default(), - /// Pressure oversampling - os_pres: Default::default(), - /// Filter coefficient - filter: Default::default(), - } - } -} - -pub struct Bme680DeviceBuilder { - dev: bme680_dev, -} - -/// Generic communication function pointer -/// @param[in] dev_id: Place holder to store the id of the device structure -/// Can be used to store the index of the Chip select or -/// I2C address of the device. -/// @param[in] reg_addr: Used to select the register the where data needs to -/// be read from or written to. -/// @param[in/out] reg_data: Data array to read/write -/// @param[in] len: Length of the data array -type ComFn = extern "C" fn(dev_id: u8, reg_addr: u8, data: *mut u8, len: u16) -> i8; - -type DelayFn = extern "C" fn(period: u32); - -impl Bme680DeviceBuilder where - I2C: Read + Write + WriteRead, - D: DelayMs, -{ - pub fn new(i2c: I2C, delay: D) -> Self { - let dev = bme680_dev { - /// Chip Id - chip_id: consts::BME680_CHIP_ID, - /// Device Id - dev_id: consts::BME680_I2C_ADDR_PRIMARY, - /// SPI/I2C interface - intf: bme680_intf_BME680_I2C_INTF, - /// Memory page used - mem_page: Default::default(), - /// Ambient temperature in Degree C - amb_temp: Default::default(), - /// Sensor calibration data - calib: Default::default(), - /// Sensor settings - tph_sett: Default::default(), - /// Gas Sensor settings - gas_sett: Default::default(), - /// Sensor power modes - power_mode: consts::BME680_SLEEP_MODE, - /// New sensor fields - new_fields: Default::default(), - /// Store the info messages - info_msg: Default::default(), - - fn read( - &mut self, - address: u8, - buffer: &mut [u8] - ) -> Result<(), Self::Error>; - - extern "C" fn ( dev_id : u8 , reg_addr : u8 , data : * mut u8 , len : u16 ) -> i8 - - /// Bus read function pointer - read: Some(read), - /// Bus write function pointer - write: Some(write), - /// delay function pointer - delay_ms: Some(delay.delay_ms), - /// Communication function result - com_rslt: Default::default(), - }; - - Self { dev: dev } - } - - pub fn with_chip_id(mut self, chip_id: u8) -> Self { - self.dev.chip_id = chip_id; - self - } - - pub fn with_dev_id(mut self, dev_id: u8) -> Self { - self.dev.dev_id = dev_id; - self - } - - pub fn with_intf(mut self, intf: bme680_intf) -> Self { - self.dev.intf = intf; - self - } - - pub fn with_mem_page(mut self, mem_page: u8) -> Self { - self.dev.mem_page = mem_page; - self - } - - pub fn with_amb_temp(mut self, amb_temp: i8) -> Self { - self.dev.amb_temp = amb_temp; - self - } - - pub fn with_calib(mut self, calib: bme680_calib_data) -> Self { - self.dev.calib = calib; - self - } - - pub fn with_tph_sett(mut self, tph_sett: bme680_tph_sett) -> Self { - self.dev.tph_sett = tph_sett; - self - } - - pub fn with_gas_sett(mut self, gas_sett: bme680_gas_sett) -> Self { - self.dev.gas_sett = gas_sett; - self - } - - pub fn with_power_mode(mut self, power_mode: u8) -> Self { - self.dev.power_mode = power_mode; - self - } - - pub fn with_new_fields(mut self, new_fields: u8) -> Self { - self.dev.new_fields = new_fields; - self - } - - pub fn with_info_msg(mut self, info_msg: u8) -> Self { - self.dev.info_msg = info_msg; - self - } - - pub fn with_com_rslt(mut self, com_rslt: i8) -> Self { - self.dev.com_rslt = com_rslt; - self - } - - pub fn build(self) -> Bme680Device { - Bme680Device { dev: self.dev } - } -} diff --git a/src/lib.rs b/src/lib.rs index 06c5a07..660b337 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,47 +1,128 @@ -#![allow(non_upper_case_globals)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![feature(rustc_private)] #![feature(try_from)] -//include!(concat!(env!("OUT_DIR"), "/bindings.rs")); - #[macro_use] extern crate bitflags; - -extern crate byteorder; - extern crate embedded_hal as hal; -use hal::blocking::delay::{DelayMs, DelayUs}; +use hal::blocking::delay::DelayMs; +use hal::blocking::i2c::{Read, Write}; +use std::convert::TryFrom; + use std::result; -#[link(name = "example", kind = "static")] -mod consts; -//mod device_builder; -mod bme680; +/** BME680 General config */ +pub const BME680_POLL_PERIOD_MS: u8 = 10; -#[cfg(test)] -mod tests { +/** BME680 I2C addresses */ +pub const BME680_I2C_ADDR_PRIMARY: u8 = 0x76; +pub const BME680_I2C_ADDR_SECONDARY: u8 = 0x77; - use device_builder::Bme680DeviceBuilder; +/** BME680 unique chip identifier */ +pub const BME680_CHIP_ID: u8 = 0x61; - extern "C" fn com(dev_id: u8, reg_addr: u8, data: *mut u8, len: u16) -> i8 { - 0 - } +/** BME680 coefficients related defines */ +pub const BME680_COEFF_SIZE: usize = 41; +pub const BME680_COEFF_ADDR1_LEN: u8 = 25; +pub const BME680_COEFF_ADDR2_LEN: u8 = 16; - extern "C" fn delay(period: u32) { - println!("delay {}", period); - } +/** BME680 field_x related defines */ +pub const BME680_FIELD_LENGTH: u8 = 15; +pub const BME680_FIELD_ADDR_OFFSET: u8 = 17; - #[test] - fn init() { - let dev = Bme680DeviceBuilder::new(com, com, delay).build(); - dev.init(); - } -} +pub const BME680_SOFT_RESET_CMD: u8 = 0xb6; -pub type Result = result::Result; +pub const BME680_OK: i8 = 0; + +/** Errors **/ +pub const BME680_E_NULL_PTR: i8 = -1; +pub const BME680_E_COM_FAIL: i8 = -2; +pub const BME680_E_DEV_NOT_FOUND: i8 = -3; +pub const BME680_E_INVALID_LENGTH: i8 = -4; + +/** Register map */ +/** Other coefficient's address */ +pub const BME680_ADDR_RES_HEAT_VAL_ADDR: u8 = 0x00; +pub const BME680_ADDR_RES_HEAT_RANGE_ADDR: u8 = 0x02; +pub const BME680_ADDR_RANGE_SW_ERR_ADDR: u8 = 0x04; +pub const BME680_ADDR_SENS_CONF_START: u8 = 0x5A; +pub const BME680_ADDR_GAS_CONF_START: u8 = 0x64; + +pub const BME680_SOFT_RESET_ADDR: u8 = 0xe0; + +/** Field settings */ +pub const BME680_FIELD0_ADDR: u8 = 0x1d; + +/** Heater settings */ +pub const BME680_RES_HEAT0_ADDR: u8 = 0x5a; +pub const BME680_GAS_WAIT0_ADDR: u8 = 0x64; + +/** Sensor configuration registers */ +pub const BME680_CONF_HEAT_CTRL_ADDR: u8 = 0x70; +pub const BME680_CONF_ODR_RUN_GAS_NBC_ADDR: u8 = 0x71; +pub const BME680_CONF_OS_H_ADDR: u8 = 0x72; +pub const BME680_MEM_PAGE_ADDR: u8 = 0xf3; +pub const BME680_CONF_T_P_MODE_ADDR: u8 = 0x74; +pub const BME680_CONF_ODR_FILT_ADDR: u8 = 0x75; + +/** Coefficient's address */ +pub const BME680_COEFF_ADDR1: u8 = 0x89; +pub const BME680_COEFF_ADDR2: u8 = 0xe1; + +/** Chip identifier */ +pub const BME680_CHIP_ID_ADDR: u8 = 0xd0; + +pub const BME680_SLEEP_MODE: u8 = 0; +pub const BME680_FORCED_MODE: u8 = 1; + +pub const BME680_RESET_PERIOD: u8 = 10; + +pub const BME680_GAS_MEAS_MSK: u8 = 0x30; +pub const BME680_NBCONV_MSK: u8 = 0x0F; +pub const BME680_FILTER_MSK: u8 = 0x1C; +pub const BME680_OST_MSK: u8 = 0xE0; +pub const BME680_OSP_MSK: u8 = 0x1C; +pub const BME680_OSH_MSK: u8 = 0x07; +pub const BME680_HCTRL_MSK: u8 = 0x08; +pub const BME680_RUN_GAS_MSK: u8 = 0x10; +pub const BME680_MODE_MSK: u8 = 0x03; +pub const BME680_RHRANGE_MSK: u8 = 0x30; +pub const BME680_RSERROR_MSK: u8 = 0xf0; +pub const BME680_NEW_DATA_MSK: u8 = 0x80; +pub const BME680_GAS_INDEX_MSK: u8 = 0x0f; +pub const BME680_GAS_RANGE_MSK: u8 = 0x0f; +pub const BME680_GASM_VALID_MSK: u8 = 0x20; +pub const BME680_HEAT_STAB_MSK: u8 = 0x10; +pub const BME680_MEM_PAGE_MSK: u8 = 0x10; +pub const BME680_SPI_RD_MSK: u8 = 0x80; +pub const BME680_SPI_WR_MSK: u8 = 0x7f; +pub const BME680_BIT_H1_DATA_MSK: u8 = 0x0F; + +/// +/// SPI memory page settings +/// +pub const BME680_MEM_PAGE0: u8 = 0x10; + +/// +/// SPI memory page settings +/// +pub const BME680_MEM_PAGE1: u8 = 0x00; + +/** Buffer length macro declaration */ +pub const BME680_TMP_BUFFER_LENGTH: usize = 40; +pub const BME680_REG_BUFFER_LENGTH: usize = 6; +pub const BME680_FIELD_DATA_LENGTH: usize = 3; +pub const BME680_GAS_REG_BUF_LENGTH: usize = 20; + +/* Settings selector */ +pub const BME680_OST_SEL: u16 = 1; +pub const BME680_OSP_SEL: u16 = 2; +pub const BME680_OSH_SEL: u16 = 4; +pub const BME680_GAS_MEAS_SEL: u16 = 8; +pub const BME680_FILTER_SEL: u16 = 16; +pub const BME680_HCNTRL_SEL: u16 = 32; +pub const BME680_RUN_GAS_SEL: u16 = 64; +pub const BME680_NBCONV_SEL: u16 = 128; +pub const BME680_GAS_SENSOR_SEL: u16 = BME680_GAS_MEAS_SEL | BME680_RUN_GAS_SEL | BME680_NBCONV_SEL; pub enum Bme680Error { /// @@ -60,26 +141,161 @@ pub enum Bme680Error { /// aka BME680_E_INVALID_LENGTH /// InvalidLength, + /// + /// Warning aka BME680_W_DEFINE_PWR_MODE + /// + DefinePwrMode, + /// + /// Warning aka BME680_W_DEFINE_PWR_MODE + /// + NoNewData, + /// + /// Warning Boundary Check + /// + BoundaryCheckFailure(InfoMsg, u8, u8), } -fn to_result(res: i8) -> Result<()> { - match res { - consts::BME680_OK => Ok(()), - consts::BME680_E_NULL_PTR => Err(Bme680Error::NulltPtr), - consts::BME680_E_COM_FAIL => Err(Bme680Error::CommunicationFailure), - consts::BME680_E_DEV_NOT_FOUND => Err(Bme680Error::DeviceNotFound), - consts::BME680_E_INVALID_LENGTH => Err(Bme680Error::InvalidLength), - _ => panic!("Invalid bme680 result: {}", res), +pub type Result = result::Result; + +/// +/// Power mode settings +/// +#[derive(PartialEq, Clone, Copy)] +pub enum PowerMode { + SleepMode, + ForcedMode, +} + +impl PowerMode { + fn from(power_mode: u8) -> Self { + match power_mode { + BME680_SLEEP_MODE => PowerMode::SleepMode, + BME680_FORCED_MODE => PowerMode::ForcedMode, + _ => panic!("Unknown power mode: {}", power_mode), + } + } + + fn value(&self) -> u8 { + match self { + PowerMode::SleepMode => BME680_SLEEP_MODE, + PowerMode::ForcedMode => BME680_FORCED_MODE, + } } } -pub enum I2CAddr { - Primary, - Secondary, +#[derive(Default, Copy)] +#[repr(C)] +pub struct CalibData { + pub par_h1: u16, + pub par_h2: u16, + pub par_h3: i8, + pub par_h4: i8, + pub par_h5: i8, + pub par_h6: u8, + pub par_h7: i8, + pub par_gh1: i8, + pub par_gh2: i16, + pub par_gh3: i8, + pub par_t1: u16, + pub par_t2: i16, + pub par_t3: i8, + pub par_p1: u16, + pub par_p2: i16, + pub par_p3: i8, + pub par_p4: i16, + pub par_p5: i16, + pub par_p6: i8, + pub par_p7: i8, + pub par_p8: i16, + pub par_p9: i16, + pub par_p10: u8, + pub t_fine: i32, + pub res_heat_range: u8, + pub res_heat_val: i8, + pub range_sw_err: u8, +} + +impl Clone for CalibData { + fn clone(&self) -> Self { + *self + } +} + +#[derive(Default, Copy)] +#[repr(C)] +pub struct TphSett { + pub os_hum: Option, + pub os_temp: Option, + pub os_pres: Option, + pub filter: Option, +} + +impl Clone for TphSett { + fn clone(&self) -> Self { + *self + } +} + +#[derive(Default, Copy)] +#[repr(C)] +pub struct GasSett { + pub nb_conv: Option, + pub heatr_ctrl: Option, + pub run_gas: Option, + pub heatr_temp: Option, + pub heatr_dur: Option, +} + +impl Clone for GasSett { + fn clone(&self) -> Self { + *self + } +} + +#[derive(Default, Copy)] +#[repr(C)] +pub struct FieldData { + pub status: u8, + pub gas_index: u8, + pub meas_index: u8, + pub temperature: i16, + pub pressure: u32, + pub humidity: u32, + pub gas_resistance: u32, +} + +impl Clone for FieldData { + fn clone(&self) -> Self { + *self + } +} + +/// TODO - replace naming of "State" with something better +/// aka new_fields - BME680_NEW_DATA_MSK +/// +pub enum FieldDataState { + NewData, + // TODO find better naming to no new data + NoNewData, +} + +/// Infos +bitflags! { + #[derive(Default)] + pub struct InfoMsg: u8 { + const MIN_CORRECTION = 1; + const MAX_CORRECTION = 2; + } +} + +#[derive(Default)] +pub struct SensorSettings { + gas_sett: GasSett, + tph_sett: TphSett, } bitflags! { - pub struct SensorSettings: u16 { + pub struct DesiredSensorSettings: u16 { /// To set temperature oversampling const OST_SEL = 1; /// To set pressure oversampling. @@ -101,3 +317,590 @@ bitflags! { const GAS_SENSOR_SEL = Self::GAS_MEAS_SEL.bits | Self::RUN_GAS_SEL.bits | Self::NBCONV_SEL.bits; } } + +#[repr(C)] +pub struct Bme680_dev { + pub i2c: I2C, + pub delay: D, + pub dev_id: u8, + pub mem_page: u8, + pub amb_temp: i8, + pub calib: CalibData, + pub tph_sett: TphSett, + pub gas_sett: GasSett, + pub power_mode: PowerMode, + pub new_fields: u8, + pub info_msg: u8, +} + +fn boundary_check(value: Option, min: u8, max: u8) -> Result { + let mut info_msg: InfoMsg = Default::default(); + + // TODO give the nullptr here a different name + let value = value.ok_or(Bme680Error::NulltPtr)?; + + if value < min { + info_msg |= InfoMsg::MIN_CORRECTION; + } + + if value > max { + info_msg |= InfoMsg::MAX_CORRECTION; + } + + if info_msg.is_empty() { + return Err(Bme680Error::BoundaryCheckFailure(info_msg, min, max)); + } + Ok(value) +} + +impl Bme680_dev +where + D: DelayMs, + I2C: Read + Write, +{ + pub fn init(&mut self) -> Result<()> { + self.soft_reset()?; + + /* Soft reset to restore it to default values*/ + let chip_id = self.get_regs_u8(BME680_CHIP_ID_ADDR)?; + if chip_id == BME680_CHIP_ID { + self.calib = self.get_calib_data()?; + Ok(()) + } else { + Err(Bme680Error::DeviceNotFound) + } + } + + pub fn get_regs_u8(&mut self, reg_addr: u8) -> Result { + let mut buf = [0; 1]; + match self.i2c.read(reg_addr, &mut buf) { + Ok(()) => Ok(buf[0]), + Err(_) => Err(Bme680Error::CommunicationFailure), + } + } + + pub fn get_regs_i8(&mut self, reg_addr: u8) -> Result { + let mut buf = [0; 1]; + match self.i2c.read(reg_addr, &mut buf) { + Ok(()) => Ok(i8::try_from(buf[0]).expect("U8 overflow when reading register")), + Err(_) => Err(Bme680Error::CommunicationFailure), + } + } + + pub fn bme680_set_regs(&mut self, reg: &[(u8, u8)]) -> Result<()> { + if reg.is_empty() || reg.len() > (BME680_TMP_BUFFER_LENGTH / 2) as usize { + return Err(Bme680Error::InvalidLength); + } + + let mut tmp_buff = Vec::with_capacity(BME680_TMP_BUFFER_LENGTH); + + for (reg_addr, reg_data) in reg { + tmp_buff.push(reg_addr.to_owned()); + tmp_buff.push(reg_data.to_owned()); + } + + self.i2c + .write(self.dev_id, tmp_buff.as_slice()) + .map_err(|_| Bme680Error::CommunicationFailure) + } + + pub fn soft_reset(&mut self) -> Result<()> { + self.bme680_set_regs(&[(BME680_SOFT_RESET_ADDR, BME680_SOFT_RESET_CMD)])?; + self.delay.delay_ms(BME680_RESET_PERIOD); + Ok(()) + } + + // TODO replace parameter desired_settings with safe flags + pub fn bme680_set_sensor_settings( + &mut self, + desired_settings: DesiredSensorSettings, + gas_sett: Option, + ) -> Result<()> { + let mut reg_addr: u8; + + let mut reg = Vec::with_capacity(BME680_REG_BUFFER_LENGTH); + let intended_power_mode = self.power_mode; + + if desired_settings.contains(DesiredSensorSettings::GAS_MEAS_SEL) { + self.set_gas_config(gas_sett.unwrap())?; + } + + let power_mode = self.power_mode; + self.bme680_set_sensor_mode(power_mode)?; + + /* Selecting the filter */ + if desired_settings.contains(DesiredSensorSettings::FILTER_SEL) { + let tph_sett_filter = boundary_check(self.tph_sett.filter, 0, 7)?; + reg_addr = 0x75u8; + let mut data = self.get_regs_u8(reg_addr)?; + + // TODO duplicate check of condition ? + if desired_settings.contains(DesiredSensorSettings::FILTER_SEL) { + data = (data as (i32) & !0x1ci32 |tph_sett_filter as (i32) << 2i32 & 0x1ci32) + as (u8); + } + reg.push((reg_addr, data)); + } + + if desired_settings.contains(DesiredSensorSettings::HCNTRL_SEL) { + + let gas_sett_heatr_ctrl = boundary_check(self.gas_sett.heatr_ctrl, 0x0u8, 0x8u8)?; + reg_addr = 0x70u8; + let mut data = self.get_regs_u8(reg_addr)?; + data = (data as (i32) & !0x8i32 | gas_sett_heatr_ctrl as (i32) & 0x8) as (u8) ; + reg.push((reg_addr, data)); + } + + /* Selecting heater T,P oversampling for the sensor */ + if desired_settings + .contains(DesiredSensorSettings::OST_SEL | DesiredSensorSettings::OSP_SEL) + { + reg_addr = 0x74u8; + let mut data = self.get_regs_u8(reg_addr)?; + + if desired_settings.contains(DesiredSensorSettings::OST_SEL) { + let tph_sett_os_temp = boundary_check(self.tph_sett.os_temp, 0, 5)?; + data = (data as (i32) & !0xe0i32 | tph_sett_os_temp as (i32) << 5i32 & 0xe0i32) + as (u8); + } + + if desired_settings.contains(DesiredSensorSettings::OSP_SEL) { + let tph_sett_os_pres = self.tph_sett.os_temp.ok_or(Bme680Error::NulltPtr)?; + data = (data as (i32) & !0x1ci32 | tph_sett_os_pres as (i32) << 2i32 & 0x1ci32) + as (u8); + } + + reg.push((reg_addr, data)); + } + + /* Selecting humidity oversampling for the sensor */ + if desired_settings.contains(DesiredSensorSettings::OSH_SEL) { + let tph_sett_os_hum = boundary_check(self.tph_sett.os_hum, 0, 5)?; + reg_addr = 0x72u8; + let mut data = self.get_regs_u8(reg_addr)?; + data = (data as (i32) & !0x7i32 | tph_sett_os_hum as (i32) & 0x7i32) as (u8); + reg.push((reg_addr, data)); + } + + /* Selecting the runGas and NB conversion settings for the sensor */ + if desired_settings + .contains(DesiredSensorSettings::RUN_GAS_SEL | DesiredSensorSettings::NBCONV_SEL) + { + reg_addr = 0x71u8; + let mut data = self.get_regs_u8(reg_addr)?; + + if desired_settings.contains(DesiredSensorSettings::RUN_GAS_SEL) { + let gas_sett_run_gas = boundary_check(self.gas_sett.run_gas, 0, 1)?; + data = (data as (i32) & !0x10i32 | gas_sett_run_gas as (i32) << 4i32 & 0x10i32) + as (u8); + } + + if desired_settings.contains(DesiredSensorSettings::NBCONV_SEL) { + let gas_sett_nb_conv = boundary_check(self.gas_sett.nb_conv, 0, 10)?; + data = (data as (i32) & !0xfi32 | gas_sett_nb_conv as (i32) & 0xfi32) as (u8); + } + + reg.push((reg_addr, data)); + } + + self.bme680_set_regs(reg.as_slice())?; + + /* Restore previous intended power mode */ + self.power_mode = intended_power_mode; + Ok(()) + } + + // TODO replace desired_settings with proper flags type see lib.rs + pub fn get_sensor_settings(&mut self, desired_settings: u16) -> Result { + let reg_addr: u8 = 0x70u8; + let mut data_array: [u8; BME680_REG_BUFFER_LENGTH] = [0; BME680_REG_BUFFER_LENGTH]; + let mut sensor_settings: SensorSettings = Default::default(); + + self.i2c.read(reg_addr, &mut data_array).map_err(|_| Bme680Error::CommunicationFailure)?; + + if desired_settings & BME680_GAS_MEAS_SEL != 0 { + sensor_settings.gas_sett = self.get_gas_config()?; + } + + if desired_settings & BME680_FILTER_SEL != 0 { + sensor_settings.tph_sett.filter = + Some(((data_array[5usize] as (i32) & 0x1ci32) >> 2i32) as (u8)); + } + + if desired_settings & (BME680_OST_SEL | BME680_OSP_SEL) != 0 { + sensor_settings.tph_sett.os_temp = + Some(((data_array[4usize] as (i32) & 0xe0i32) >> 5i32) as (u8)); + sensor_settings.tph_sett.os_pres = + Some(((data_array[4usize] as (i32) & 0x1ci32) >> 2i32) as (u8)); + } + + if desired_settings & BME680_OSH_SEL != 0 { + sensor_settings.tph_sett.os_hum = Some((data_array[2usize] as (i32) & 0x7i32) as (u8)); + } + + if desired_settings & BME680_HCNTRL_SEL != 0 { + sensor_settings.gas_sett.heatr_ctrl = Some((data_array[0usize] as (i32) & 0x8i32) as (u8)); + } + + if desired_settings & (BME680_RUN_GAS_SEL | BME680_NBCONV_SEL) != 0 { + sensor_settings.gas_sett.nb_conv = Some((data_array[1usize] as (i32) & 0xfi32) as (u8)); + sensor_settings.gas_sett.run_gas = + Some(((data_array[1usize] as (i32) & 0x10i32) >> 4i32) as (u8)); + } + + Ok(sensor_settings) + } + + pub fn bme680_set_sensor_mode(&mut self, target_power_mode: PowerMode) -> Result<()> { + let mut tmp_pow_mode: u8; + let mut current_power_mode: PowerMode; + let reg_addr: u8 = 0x74u8; + + /* Call repeatedly until in sleep */ + loop { + tmp_pow_mode = self.get_regs_u8(BME680_CONF_T_P_MODE_ADDR)?; + + /* Put to sleep before changing mode */ + current_power_mode = PowerMode::from(tmp_pow_mode & BME680_MODE_MSK); + if current_power_mode != PowerMode::SleepMode { + /* Set to sleep*/ + tmp_pow_mode = tmp_pow_mode & !BME680_MODE_MSK; + let reg = vec!((reg_addr, tmp_pow_mode)); + self.bme680_set_regs(reg.as_slice())?; + self.delay.delay_ms(BME680_POLL_PERIOD_MS); + } else { + // TODO do while in Rust? + break; + } + } + + /* Already in sleep */ + if current_power_mode != PowerMode::SleepMode { + tmp_pow_mode = tmp_pow_mode & !BME680_MODE_MSK | target_power_mode.value(); + self.bme680_set_regs(&[(reg_addr, tmp_pow_mode)])?; + } + Ok(()) + } + + pub fn get_sensor_mode(&mut self) -> Result { + let regs = self.get_regs_u8(BME680_CONF_T_P_MODE_ADDR)?; + let mode = regs & BME680_MODE_MSK; + Ok(PowerMode::from(mode)) + } + + pub fn bme680_set_profile_dur(&mut self, tph_sett: TphSett, duration: u16) { + let os_to_meas_cycles: [u8; 6] = [0u8, 1u8, 2u8, 4u8, 8u8, 16u8]; + // TODO check if the following unwrap_ors do not change behaviour + let mut meas_cycles = os_to_meas_cycles[tph_sett.os_temp.unwrap_or(0) as (usize)] as (u32); + meas_cycles = + meas_cycles.wrapping_add(os_to_meas_cycles[tph_sett.os_pres.unwrap_or(0) as (usize)] as (u32)); + meas_cycles = + meas_cycles.wrapping_add(os_to_meas_cycles[tph_sett.os_hum.unwrap_or(0) as (usize)] as (u32)); + let mut tph_dur = meas_cycles.wrapping_mul(1963u32); + tph_dur = tph_dur.wrapping_add(477u32.wrapping_mul(4u32)); + tph_dur = tph_dur.wrapping_add(477u32.wrapping_mul(5u32)); + tph_dur = tph_dur.wrapping_add(500u32); + tph_dur = tph_dur.wrapping_div(1000u32); + tph_dur = tph_dur.wrapping_add(1u32); + self.gas_sett.heatr_dur = Some((duration as (i32) - tph_dur as (u16) as (i32)) as (u16)); + } + + pub fn get_profile_dur(&self, tph_sett: TphSett, gas_sett: GasSett) -> Result { + let os_to_meas_cycles: [u8; 6] = [0u8, 1u8, 2u8, 4u8, 8u8, 16u8]; + // TODO check if the following unwrap_ors do not change behaviour + let mut meas_cycles = os_to_meas_cycles[tph_sett.os_temp.unwrap_or(0) as (usize)] as (u32); + meas_cycles = + meas_cycles.wrapping_add(os_to_meas_cycles[tph_sett.os_pres.unwrap_or(0) as (usize)] as (u32)); + meas_cycles = + meas_cycles.wrapping_add(os_to_meas_cycles[tph_sett.os_hum.unwrap_or(0) as (usize)] as (u32)); + let mut tph_dur = meas_cycles.wrapping_mul(1963u32); + tph_dur = tph_dur.wrapping_add(477u32.wrapping_mul(4u32)); + tph_dur = tph_dur.wrapping_add(477u32.wrapping_mul(5u32)); + tph_dur = tph_dur.wrapping_add(500u32); + tph_dur = tph_dur.wrapping_div(1000u32); + tph_dur = tph_dur.wrapping_add(1u32); + let mut duration = tph_dur as (u16); + if gas_sett.run_gas.unwrap_or(0) != 0 { + duration = duration + gas_sett.heatr_dur.ok_or(Bme680Error::NulltPtr)?; + } + Ok(duration) + } + + /// @returns (FieldData, IsNewFields) + pub fn get_sensor_data(&mut self) -> Result<(FieldData, FieldDataState)> { + let field_data = self.read_field_data()?; + if field_data.status & BME680_NEW_DATA_MSK != 0 { + // new fields + Ok((field_data, FieldDataState::NewData)) + } else { + Ok((field_data, FieldDataState::NoNewData)) + } + } + + fn get_calib_data(&mut self) -> Result { + let mut calib: CalibData = Default::default(); + let mut coeff_array: [u8; BME680_COEFF_SIZE] = [0; BME680_COEFF_SIZE]; + + self.i2c.read( + BME680_COEFF_ADDR1, + &mut coeff_array, + ).map_err(|_| Bme680Error::CommunicationFailure)?; + + self.i2c.read( + BME680_COEFF_ADDR2, + &mut coeff_array, + ).map_err(|_| Bme680Error::CommunicationFailure)?; + + calib.par_t1 = (coeff_array[34usize] as (u16) as (i32) << 8i32 + | coeff_array[33usize] as (u16) as (i32)) as (u16); + calib.par_t2 = (coeff_array[2usize] as (u16) as (i32) << 8i32 + | coeff_array[1usize] as (u16) as (i32)) as (i16); + calib.par_t3 = coeff_array[3usize] as (i8); + calib.par_p1 = (coeff_array[6usize] as (u16) as (i32) << 8i32 + | coeff_array[5usize] as (u16) as (i32)) as (u16); + calib.par_p2 = (coeff_array[8usize] as (u16) as (i32) << 8i32 + | coeff_array[7usize] as (u16) as (i32)) as (i16); + calib.par_p3 = coeff_array[9usize] as (i8); + calib.par_p4 = (coeff_array[12usize] as (u16) as (i32) << 8i32 + | coeff_array[11usize] as (u16) as (i32)) as (i16); + calib.par_p5 = (coeff_array[14usize] as (u16) as (i32) << 8i32 + | coeff_array[13usize] as (u16) as (i32)) as (i16); + calib.par_p6 = coeff_array[16usize] as (i8); + calib.par_p7 = coeff_array[15usize] as (i8); + calib.par_p8 = (coeff_array[20usize] as (u16) as (i32) << 8i32 + | coeff_array[19usize] as (u16) as (i32)) as (i16); + calib.par_p9 = (coeff_array[22usize] as (u16) as (i32) << 8i32 + | coeff_array[21usize] as (u16) as (i32)) as (i16); + calib.par_p10 = coeff_array[23usize]; + calib.par_h1 = (coeff_array[27usize] as (u16) as (i32) << 4i32 + | coeff_array[26usize] as (i32) & 0xfi32) as (u16); + calib.par_h2 = (coeff_array[25usize] as (u16) as (i32) << 4i32 + | coeff_array[26usize] as (i32) >> 4i32) as (u16); + calib.par_h3 = coeff_array[28usize] as (i8); + calib.par_h4 = coeff_array[29usize] as (i8); + calib.par_h5 = coeff_array[30usize] as (i8); + calib.par_h6 = coeff_array[31usize]; + calib.par_h7 = coeff_array[32usize] as (i8); + calib.par_gh1 = coeff_array[37usize] as (i8); + calib.par_gh2 = (coeff_array[36usize] as (u16) as (i32) << 8i32 + | coeff_array[35usize] as (u16) as (i32)) as (i16); + calib.par_gh3 = coeff_array[38usize] as (i8); + + calib.res_heat_range = (self.get_regs_u8(BME680_ADDR_RES_HEAT_RANGE_ADDR)? & 0x30) / 16; + + calib.res_heat_val = self.get_regs_i8(BME680_ADDR_RES_HEAT_VAL_ADDR)?; + + calib.range_sw_err = (self.get_regs_u8(BME680_ADDR_RANGE_SW_ERR_ADDR)? & BME680_RSERROR_MSK) / 16; + + Ok(calib) + } + + fn set_gas_config(&mut self, gas_sett: GasSett) -> Result<()> { + let mut reg = Vec::with_capacity(2); + + if self.power_mode != PowerMode::ForcedMode { + return Err(Bme680Error::DefinePwrMode); + } + + // TODO check whether unwrap_or changes behaviour + reg.push((BME680_RES_HEAT0_ADDR, self.calc_heater_res(gas_sett.heatr_temp.unwrap_or(0)))); + reg.push((BME680_GAS_WAIT0_ADDR, self.calc_heater_dur(gas_sett.heatr_dur.unwrap_or(0)))); + + self.gas_sett.nb_conv = Some(0); + self.bme680_set_regs(reg.as_slice()) + } + + fn get_gas_config(&mut self) -> Result { + // TODO move both GasSett fields to new struct + let mut gas_sett: GasSett = Default::default(); + // TODO figure out if heat_temp and dur can be u8 + gas_sett.heatr_temp = Some(self.get_regs_u8(BME680_ADDR_SENS_CONF_START)? as u16); + gas_sett.heatr_dur = Some(self.get_regs_u8(BME680_ADDR_GAS_CONF_START)? as u16); + Ok(gas_sett) + } + + fn calc_heater_res(&self, temp: u16) -> u8 { + // cap temperature + let temp = if temp <= 400 { temp } else { 400 }; + + let var1 = self.amb_temp as (i32) * self.calib.par_gh3 as (i32) / 1000i32 * 256i32; + let var2 = (self.calib.par_gh1 as (i32) + 784i32) + * (((self.calib.par_gh2 as (i32) + 154009i32) * temp as (i32) * 5i32 / 100i32 + + 3276800i32) / 10i32); + let var3 = var1 + var2 / 2i32; + let var4 = var3 / (self.calib.res_heat_range as (i32) + 4i32); + let var5 = 131i32 * self.calib.res_heat_val as (i32) + 65536i32; + let heatr_res_x100 = (var4 / var5 - 250i32) * 34i32; + ((heatr_res_x100 + 50i32) / 100i32) as (u8) + } + + fn calc_heater_dur(&self, dur: u16) -> u8 { + let mut factor: u8 = 0u8; + let mut dur = dur; + let durval = + if dur as (i32) >= 0xfc0i32 { + 0xffu8 // Max duration + } else { + loop { + if !(dur as (i32) > 0x3fi32) { + break; + } + dur = (dur as (i32) / 4i32) as (u16); + factor = (factor as (i32) + 1i32) as (u8); + } + (dur as (i32) + factor as (i32) * 64i32) as (u8) + }; + durval + } + + fn calc_temperature(&mut self, temp_adc: u32) -> i16 { + let var1 = ((temp_adc as (i32) >> 3i32) - (self.calib.par_t1 as (i32) << 1i32)) as (isize); + let var2 = var1 * self.calib.par_t2 as (i32) as (isize) >> 11i32; + let var3 = (var1 >> 1i32) * (var1 >> 1i32) >> 12i32; + let var3 = var3 * (self.calib.par_t3 as (i32) << 4i32) as (isize) >> 14i32; + // TODO really assign here ? + self.calib.t_fine = (var2 + var3) as (i32); + let calc_temp = (self.calib.t_fine * 5i32 + 128i32 >> 8i32) as (i16); + calc_temp + } + + fn calc_pressure(&self, pres_adc: u32) -> u32 { + let mut var1 = (self.calib.t_fine >> 1i32) - 64000i32; + let mut var2 = ((var1 >> 2i32) * (var1 >> 2i32) >> 11i32) * self.calib.par_p6 as (i32) >> 2i32; + var2 = var2 + (var1 * self.calib.par_p5 as (i32) << 1i32); + var2 = (var2 >> 2i32) + (self.calib.par_p4 as (i32) << 16i32); + var1 = (((var1 >> 2i32) * (var1 >> 2i32) >> 13i32) * (self.calib.par_p3 as (i32) << 5i32) + >> 3i32) + (self.calib.par_p2 as (i32) * var1 >> 1i32); + var1 = var1 >> 18i32; + var1 = (32768i32 + var1) * self.calib.par_p1 as (i32) >> 15i32; + let mut pressure_comp = 1048576u32.wrapping_sub(pres_adc) as (i32); + pressure_comp = ((pressure_comp - (var2 >> 12i32)) as (u32)).wrapping_mul(3125u32) as (i32); + if pressure_comp >= 0x40000000i32 { + pressure_comp = ((pressure_comp as (u32)).wrapping_div(var1 as (u32)) << 1i32) as (i32); + } else { + pressure_comp = ((pressure_comp << 1i32) as (u32)).wrapping_div(var1 as (u32)) as (i32); + } + var1 = self.calib.par_p9 as (i32) + * ((pressure_comp >> 3i32) * (pressure_comp >> 3i32) >> 13i32) >> 12i32; + var2 = (pressure_comp >> 2i32) * self.calib.par_p8 as (i32) >> 13i32; + let var3 = (pressure_comp >> 8i32) * (pressure_comp >> 8i32) * (pressure_comp >> 8i32) + * self.calib.par_p10 as (i32) >> 17i32; + pressure_comp = + pressure_comp + (var1 + var2 + var3 + (self.calib.par_p7 as (i32) << 7i32) >> 4i32); + pressure_comp as (u32) + } + + fn calc_humidity(&self, hum_adc: u16) -> u32 { + let temp_scaled = self.calib.t_fine * 5i32 + 128i32 >> 8i32; + let var1 = hum_adc as (i32) - self.calib.par_h1 as (i32) * 16i32 + - (temp_scaled * self.calib.par_h3 as (i32) / 100i32 >> 1i32); + let var2 = self.calib.par_h2 as (i32) + * (temp_scaled * self.calib.par_h4 as (i32) / 100i32 + + (temp_scaled * (temp_scaled * self.calib.par_h5 as (i32) / 100i32) >> 6i32) + / 100i32 + (1i32 << 14i32)) >> 10i32; + let var3 = var1 * var2; + let var4 = self.calib.par_h6 as (i32) << 7i32; + let var4 = var4 + temp_scaled * self.calib.par_h7 as (i32) / 100i32 >> 4i32; + let var5 = (var3 >> 14i32) * (var3 >> 14i32) >> 10i32; + let var6 = var4 * var5 >> 1i32; + let mut calc_hum = (var3 + var6 >> 10i32) * 1000i32 >> 12i32; + if calc_hum > 100000i32 { + calc_hum = 100000i32; + } else if calc_hum < 0i32 { + calc_hum = 0i32; + } + calc_hum as (u32) + } + + fn calc_gas_resistance(&mut self, gas_res_adc: u16, gas_range: u8) -> u32 { + let lookup_table1: [u32; 16] = [ + 2147483647u32, + 2147483647u32, + 2147483647u32, + 2147483647u32, + 2147483647u32, + 2126008810u32, + 2147483647u32, + 2130303777u32, + 2147483647u32, + 2147483647u32, + 2143188679u32, + 2136746228u32, + 2147483647u32, + 2126008810u32, + 2147483647u32, + 2147483647u32, + ]; + let lookup_table2: [u32; 16] = [ + 4096000000u32, + 2048000000u32, + 1024000000u32, + 512000000u32, + 255744255u32, + 127110228u32, + 64000000u32, + 32258064u32, + 16016016u32, + 8000000u32, + 4000000u32, + 2000000u32, + 1, + 500000u32, + 250000u32, + 125000u32, + ]; + let var1 = (1340isize + 5isize * self.calib.range_sw_err as (isize)) + * lookup_table1[gas_range as (usize)] as (isize) >> 16i32; + let var2 = ((gas_res_adc as (isize) << 15i32) - 16777216isize + var1) as (usize); + let var3 = lookup_table2[gas_range as (usize)] as (isize) * var1 >> 9i32; + let calc_gas_res = ((var3 + (var2 as (isize) >> 1i32)) / var2 as (isize)) as (u32); + calc_gas_res + } + + fn read_field_data(&mut self) -> Result { + let mut buff = [0, BME680_FIELD_LENGTH]; + let mut data: FieldData = Default::default(); + let mut gas_range: u8; + let mut adc_temp: u32; + let mut adc_pres: u32; + let mut adc_hum: u16; + let mut adc_gas_res: u16; + let mut tries: u8 = 10u8; + + loop { + self.i2c.read(BME680_FIELD0_ADDR, &mut buff) + .map_err(|_| Bme680Error::CommunicationFailure)?; + data.status = buff[0] & BME680_NEW_DATA_MSK; + data.gas_index = buff[0] & BME680_GAS_INDEX_MSK;; + data.meas_index = buff[1]; + + adc_pres = (buff[2] as (u32)).wrapping_mul(4096) | (buff[3] as (u32)).wrapping_mul(16) + | (buff[4] as (u32)).wrapping_div(16); + adc_temp = (buff[5] as (u32)).wrapping_mul(4096) | (buff[6] as (u32)).wrapping_mul(16) + | (buff[7] as (u32)).wrapping_div(16); + adc_hum = ((buff[8] as (u32)).wrapping_mul(256) | buff[9] as (u32)) as (u16); + adc_gas_res = ((buff[13] as (u32)).wrapping_mul(4) + | (buff[14] as (u32)).wrapping_div(64)) as (u16); + gas_range = buff[14] & BME680_GAS_RANGE_MSK; + + data.status = data.status | buff[14] & BME680_GASM_VALID_MSK; + data.status = data.status | buff[14] & BME680_HEAT_STAB_MSK; + + if data.status & BME680_NEW_DATA_MSK != 0 { + data.temperature = self.calc_temperature(adc_temp); + data.pressure = self.calc_pressure(adc_pres); + data.humidity = self.calc_humidity(adc_hum); + data.gas_resistance = self.calc_gas_resistance(adc_gas_res, gas_range); + return Ok(data); + } + + self.delay.delay_ms(BME680_POLL_PERIOD_MS); + + tries = tries - 1; + if tries == 0 { + break; + } + } + Err(Bme680Error::NoNewData) + } +}