diff --git a/CHANGELOG.md b/CHANGELOG.md index 81f3e0d..a3a54bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,24 +1,41 @@ # Unreleased + **Breaking changes!** -- Update to embedded-hal v1.0.0 rc2 + +- Updated to embedded-hal v1.0 +- Added `destroy()` functions to expander impls which allows driver users to retrieve the I2C bus and interrupt pin +- Fixed some documentation examples + typos + +## Migration + +As a general migration guideline to embedded-hal v1 consult the [migration guide](https://github.com/rust-embedded/embedded-hal/blob/master/docs/migrating-from-0.2-to-1.0.md) + +For users of PCA9535 most things should work out of the box. Only change required is that due to the `InputPin` trait now taking `&mut self` you need to modify the interrupt pin provided to the cached expander struct to be mutable. +In cases you have previously used [shared-bus](https://crates.io/crates/shared-bus) for I2C bus sharing it is now recommended to switch to [embedded-hal-bus](https://crates.io/crates/embedded-hal-bus) instead. # 1.2.0 + **Breaking changes!** + - Updated to embedded hal 1.0.0-alpha.9 (@MajorArkwolf) - Removed IOPin (currently not supported in embedded hal 1.0.0-alpha.9, will be readded once it is supported again) (@MajorArkwolf) Thanks to @MajorArkwolf :) # 1.1.0 + - Added `Debug` trait implementation for all types which are accessible by the library user - Added `Clone` and `Copy` trait implementation for `Polarity` enum - Internal code cleanup # 1.0.0 + **Breaking changes!** + - Refactored error types and generics. The whole error handling is now simpler and should make more sense in general, as underlying embedded-hal errors are directly passed to the `ExpanderError` enum. Due to those changes certain types need an additional generic for I2C interface. Generics have been refactored as well so some generics are not on the same position like they used to be. Migrating to 1.0 should be relatively simple by adding those missing generics or rearranging them. - Added `std::error::Error` trait implementation for `ExpanderError`. This is automatically enabled by using the crates `std` feature. The change should allow for easier error handling with existing std solutions and libraries. - Updated crate to rust 2021 edition # 0.1.0 + - moved the special implementation of writes to any polarity register to the Expander Trait implementation instead of overwriting StandardExpanderInterface Trait functions diff --git a/Cargo.lock b/Cargo.lock index 1bce43d..d71bbef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "bitflags" version = "1.3.2" @@ -14,6 +20,25 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "critical-section" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "embedded-hal" version = "0.2.7" @@ -26,29 +51,113 @@ dependencies = [ [[package]] name = "embedded-hal" -version = "1.0.0-rc.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e57ec6ad0bc8eb967cf9c9f144177f5e8f2f6f02dad0b8b683f9f05f6b22def" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "embedded-hal-bus" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57b4e6ede84339ebdb418cd986e6320a34b017cdf99b5cc3efceec6450b06886" +dependencies = [ + "critical-section", + "embedded-hal 1.0.0", +] [[package]] name = "embedded-hal-nb" -version = "1.0.0-rc.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c4325112d63ff5991e2841960a1320516c33ff7237e924eaab0772b1123703" +checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605" dependencies = [ - "embedded-hal 1.0.0-rc.2", - "nb 1.0.0", + "embedded-hal 1.0.0", + "nb 1.1.0", ] [[package]] -name = "instant" -version = "0.1.12" +name = "futures" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ - "cfg-if", + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", ] +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + [[package]] name = "lazy_static" version = "1.4.0" @@ -57,136 +166,135 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.112" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "lock_api" -version = "0.4.5" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ + "autocfg", "scopeguard", ] +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + [[package]] name = "nb" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" dependencies = [ - "nb 1.0.0", + "nb 1.1.0", ] [[package]] name = "nb" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" [[package]] name = "once_cell" -version = "1.16.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "parking_lot" -version = "0.11.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ - "instant", "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", - "instant", "libc", "redox_syscall", "smallvec", - "winapi", + "windows-targets 0.48.5", ] [[package]] name = "pca9535" version = "1.2.0" dependencies = [ - "embedded-hal 1.0.0-rc.2", - "lazy_static", + "embedded-hal 1.0.0", + "embedded-hal-bus", + "once_cell", "pca9535", "rppal", "serial_test", - "shared-bus", ] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "pin-project-lite" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "pin-utils" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" -version = "1.0.34" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.10" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.2.10" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags", ] [[package]] name = "rppal" -version = "0.16.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23aff72e177b0e0b0e0801bbe9f41de2abafd396dfb69af9c602ffba8c2091b3" +checksum = "1dc171bbe325b04172e18d917c58c2cf1fb5adfd9ffabb1d6b3d62ba4c1c1331" dependencies = [ "embedded-hal 0.2.7", - "embedded-hal 1.0.0-rc.2", + "embedded-hal 1.0.0", "embedded-hal-nb", "libc", "nb 0.1.3", @@ -194,91 +302,77 @@ dependencies = [ "void", ] -[[package]] -name = "rustversion" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" - [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serial_test" -version = "0.6.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bcc41d18f7a1d50525d080fd3e953be87c4f9f1a974f3c21798ca00d54ec15" +checksum = "953ad9342b3aaca7cb43c45c097dd008d4907070394bd0751a0aa8817e5a018d" dependencies = [ + "dashmap", + "futures", "lazy_static", + "log", "parking_lot", "serial_test_derive", ] [[package]] name = "serial_test_derive" -version = "0.6.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2881bccd7d60fb32dfa3d7b3136385312f8ad75e2674aab2852867a09790cae8" +checksum = "b93fb4adc70021ac1b47f7d45e8cc4169baaa7ea58483bc5b721d19a26202212" dependencies = [ - "proc-macro-error", "proc-macro2", "quote", - "rustversion", "syn", ] [[package]] -name = "shared-bus" -version = "0.3.1" -source = "git+https://github.com/TeyKey1/shared-bus.git?rev=87af545#87af5451a39a3e138a831f845b9dcc408a78e9eb" +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ - "embedded-hal 0.2.7", - "embedded-hal 1.0.0-rc.2", - "nb 1.0.0", - "once_cell", + "autocfg", ] [[package]] name = "smallvec" -version = "1.7.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "spin_sleep" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cafa7900db085f4354dbc7025e25d7a839a14360ea13b5fc4fd717f2d3b23134" +checksum = "368a978649eaf70006b082e79c832bd72556ac1393eaf564d686e919dca2347f" dependencies = [ - "once_cell", - "winapi", + "windows-sys", ] [[package]] name = "syn" -version = "1.0.82" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] -name = "unicode-xid" -version = "0.2.2" +name = "unicode-ident" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "void" @@ -287,23 +381,124 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] -name = "winapi" -version = "0.3.9" +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows_x86_64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/Cargo.toml b/Cargo.toml index f8fa24a..7e91fde 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,11 +14,11 @@ license = "MIT" std = [] [dependencies] -hal = { version = "=1.0.0-rc.2", package = "embedded-hal" } +hal = { version = "1.0", package = "embedded-hal" } [dev-dependencies] -lazy_static = "1.4" pca9535 = { path = ".", features = ["std"] } -rppal = { version = "0.16.0", features = ["hal"] } -serial_test = "0.6" -shared-bus = { git = "https://github.com/TeyKey1/shared-bus.git", rev="87af545", features = ["std", "eh-alpha"] } +once_cell = "1.19" +rppal = { version = "0.17", features = ["hal"] } +serial_test = "3.0" +embedded-hal-bus = { version = "0.1", features = ["std"] } diff --git a/src/expander/cached.rs b/src/expander/cached.rs index df3b879..3a65f10 100644 --- a/src/expander/cached.rs +++ b/src/expander/cached.rs @@ -37,14 +37,14 @@ where /// Creates a new cached PCA9535 instance. /// /// # Cached registers - /// The init_defaults argument assumes the default values for all the registers of the device if set to `true` (Default register condition after device startup, see the device's documentation for more information). - /// In that case no bus transaction is created to verify if this is actually the case on the device. Only use this option if you have not made any transactions with the device before creating this expander struct, + /// The init_defaults argument assumes the default values for all the device registers if set to `true` (Default register condition after device startup; see the device's documentation for more information). + /// In that case, no bus transaction is created to verify if this is actually the case on the device. Only use this option if you have not made any transactions with the device before creating this expander struct, /// otherwise you might encounter unexpected behavior of the device! /// - /// If the device was used before calling this function and should keep its state you should set init_defaults to `false`. This triggers a bus transaction to read out all the devices' registers and caches the received values. + /// If the device was used before calling this function and should keep its state, you should set init_defaults to `false`. This triggers a bus transaction to read out all the devices' registers and caches the received values. /// /// # Panics - /// If given device hardware address is outside of the permittable range of `32-39`. + /// If the given device hardware address is outside the permittable range of `32-39`. pub fn new( i2c: I2C, address: u8, @@ -74,7 +74,12 @@ where Ok(expander) } - /// Initializes the device's cache by reading out all the required registers of the device. + /// Destroys the expander struct, returning the contained I2C and interrupt pin + pub fn destroy(self) -> (I2C, IP) { + (self.i2c, self.interrupt_pin) + } + + /// Initializes the device's cache by reading out all the required device registers. fn init_cache(expander: &mut Self) -> Result<(), ExpanderError> { let mut buf: [u8; 2] = [0x00, 0x00]; @@ -150,12 +155,12 @@ where I2C: I2c, E: Debug, { - /// Writes one byte to given register + /// Writes one byte to the given register /// - /// Only use this function if you really have to. The crate provides simpler ways of interacting with the device for most usecases. + /// Only use this function if you really have to. For most use cases, the crate provides simpler ways of interacting with the device. /// /// # Cached - /// If the bus write succeeds the written data is cached to avoid the need for bus traffic upon reading the written register. + /// If the bus write succeeds, the written data is cached to avoid the need for bus traffic upon reading the written register. fn write_byte(&mut self, register: Register, data: u8) -> Result<(), ExpanderError> { self.i2c .write(self.address, &[register as u8, data]) @@ -182,12 +187,13 @@ where Ok(()) } - /// Reads one byte of given register + /// Reads one byte of the given register /// - /// Only use this function if you really have to. The crate provides simpler ways of interacting with the device for most usecases. + /// Only use this function if you really have to. For most use cases, the crate provides simpler ways of interacting with the device. /// /// # Cached - /// This function only creates bus traffic in case the provided interrupt pin is held at a `low` voltage level at the time of the function call and the provided register is an input register. In that case the data is being read from the device, as the devices interrupt output indicates a data change. Otherwise the cached value is returned without causing any bus traffic. + /// This function only creates bus traffic if the provided interrupt pin is held at a `low` voltage level at the time of the function call and the provided register is an input register. + /// In that case, the data is being read from the device, as the device's interrupt output indicates a data change. Otherwise the cached value is returned without causing any bus traffic. fn read_byte(&mut self, register: Register, buffer: &mut u8) -> Result<(), ExpanderError> { if self.interrupt_pin.is_low().unwrap() && register.is_input() { let mut buf = [0u8]; @@ -206,15 +212,15 @@ where Ok(()) } - /// Writes one halfword to given register + /// Writes one half-word to the given register /// - /// Only use this function if you really have to. The crate provides simpler ways of interacting with the device for most usecases. + /// Only use this function if you really have to. For most use cases, the crate provides simpler ways of interacting with the device. /// /// # Register pairs - /// please see [`Register`] for more information about the register pairs and how they affect the halfword read and write functions. + /// Please see [`Register`] for more information about the register pairs and how they affect the half-word read and write functions. /// /// # Cached - /// If the bus write succeeds the written data is cached to avoid the need for bus traffic upon reading the written register. + /// If the bus write succeeds, the written data is cached to avoid the need for bus traffic upon reading the written register. fn write_halfword(&mut self, register: Register, data: u16) -> Result<(), ExpanderError> { self.i2c .write( @@ -256,17 +262,17 @@ where Ok(()) } - /// Reads one halfword of given register + /// Reads one half-word of the given register /// - /// Only use this function if you really have to. The crate provides simpler ways of interacting with the device for most usecases. + /// Only use this function if you really have to. For most use cases, the crate provides simpler ways of interacting with the device. /// /// # Register pairs - /// please see [`Register`] for more information about the register pairs and how they affect the halfword read and write functions. + /// Please see [`Register`] for more information about the register pairs and how they affect the half-word read and write functions. /// /// # Cached /// This function only creates bus traffic in case the provided interrupt pin is held at a `low` voltage level at the time of the function call and the provided - /// register is an input register. In that case the data is being read from the device, as the devices interrupt output indicates a data change. - /// Otherwise the cached value is returned without causing any bus traffic. + /// register is an input register. In that case, the data is being read from the device, as the device's interrupt output indicates a data change. + /// Otherwise, the cached value is returned without causing any bus traffic. fn read_halfword( &mut self, register: Register, diff --git a/src/expander/immediate.rs b/src/expander/immediate.rs index 6e8a607..efb7786 100644 --- a/src/expander/immediate.rs +++ b/src/expander/immediate.rs @@ -23,12 +23,17 @@ where /// Creates a new immediate PCA9535 instance. /// /// # Panics - /// If given device hardware address is outside of the permittable range of `32-39`. + /// If the given device hardware address is outside the permittable range of `32-39`. pub fn new(i2c: I2C, address: u8) -> Self { assert!(address > 31 && address < 40); Self { address, i2c } } + + /// Destroys the expander struct, returning the contained I2C + pub fn destroy(self) -> I2C { + self.i2c + } } impl Expander for Pca9535Immediate @@ -36,18 +41,18 @@ where E: Debug, I2C: I2c, { - /// Writes one byte to given register + /// Writes one byte to the given register /// - /// Only use this function if you really have to. The crate provides simpler ways of interacting with the device for most usecases. + /// Only use this function if you really have to. For most use cases, the crate provides simpler ways of interacting with the device. fn write_byte(&mut self, register: Register, data: u8) -> Result<(), ExpanderError> { self.i2c .write(self.address, &[register as u8, data]) .map_err(ExpanderError::WriteError) } - /// Reads one byte of given register + /// Reads one byte of the given register /// - /// Only use this function if you really have to. The crate provides simpler ways of interacting with the device for most usecases. + /// Only use this function if you really have to. For most use cases, the crate provides simpler ways of interacting with the device. fn read_byte(&mut self, register: Register, buffer: &mut u8) -> Result<(), ExpanderError> { let mut buf = [0_u8]; @@ -60,12 +65,12 @@ where Ok(()) } - /// Writes one halfword to given register + /// Writes one halfword to the given register /// - /// Only use this function if you really have to. The crate provides simpler ways of interacting with the device for most usecases. + /// Only use this function if you really have to. For most use cases, the crate provides simpler ways of interacting with the device. /// /// # Register pairs - /// please see [`Register`] for more information about the register pairs and how they affect the halfword read and write functions. + /// Please see [`Register`] for more information about the register pairs and how they affect the half-word read and write functions. fn write_halfword(&mut self, register: Register, data: u16) -> Result<(), ExpanderError> { self.i2c .write( @@ -75,12 +80,12 @@ where .map_err(ExpanderError::WriteError) } - /// Reads one halfword of given register + /// Reads one halfword of the given register /// - /// Only use this function if you really have to. The crate provides simpler ways of interacting with the device for most usecases. + /// Only use this function if you really have to. For most use cases, the crate provides simpler ways of interacting with the device. /// /// # Register pairs - /// please see [`Register`] for more information about the register pairs and how they affect the halfword read and write functions. + /// Please see [`Register`] for more information about the register pairs and how they affect the half-word read and write functions. fn read_halfword( &mut self, register: Register, diff --git a/src/expander/mod.rs b/src/expander/mod.rs index 66bbf69..21ab398 100644 --- a/src/expander/mod.rs +++ b/src/expander/mod.rs @@ -38,7 +38,7 @@ where ) -> Result<(), ExpanderError<::Error>>; } -/// Trait for IO expanders which use some synchronization primitive for the writes and reads. This implementation makes the expander sync and usable accross threads etc. +/// Trait for IO expanders which use some synchronization primitive for the writes and reads. This implementation makes the expander sync and usable accross threads. pub trait SyncExpander where I2C: I2c, diff --git a/src/expander/standard.rs b/src/expander/standard.rs index 7e3d335..f12d238 100644 --- a/src/expander/standard.rs +++ b/src/expander/standard.rs @@ -1,4 +1,4 @@ -//! Implements the standard interface for all types implementing [`Expander`] trait. +//! Implements the standard interface for all types implementing the [`Expander`] trait. use core::fmt::Debug; use hal::i2c::I2c; @@ -8,7 +8,7 @@ use super::{Expander, ExpanderError, GPIOBank, Register}; /// Standard expander interface not using [`hal`]. /// /// This interface does not track the state of the pins! Therefore, the user needs to ensure the pins are in input or output configuration before -/// proceeding to call functions related to input or output pins. Otherwise the results of those functions might not cause the expected behavior of the device. +/// proceeding to call functions related to input or output pins. Otherwise, the results of those functions might not cause the expected behavior of the device. pub trait StandardExpanderInterface: Expander where E: Debug, @@ -48,7 +48,7 @@ where self.write_byte(register, reg_val & !(0x01 << pin)) } - /// Checks if input state of given pin is `high`. This function works with pins configured as inputs as well as outputs. + /// Checks if the input state of the given pin is `high`. This function works with pins configured as inputs as well as outputs. /// /// The function result does not necessarily represent the logic level of the applied voltage at the given pin but the value inside the input register of the device. /// Which is `1` or `0` Depending on the current polarity inversion configuration of the pin. @@ -73,7 +73,7 @@ where } } - /// Checks if input state of given pin is `low`. This function works with pins configured as inputs as well as outputs. + /// Checks if the input state of the given pin is `low`. This function works with pins configured as inputs as well as outputs. /// /// The function result does not necessarily represent the logic level of the applied voltage at the given pin but the value inside the input register of the device. /// Which is `1` or `0` Depending on the current polarity inversion configuration of the pin. @@ -117,7 +117,7 @@ where self.write_byte(register, reg_val | (0x01 << pin)) } - /// Configures given pin as output. + /// Configures the given pin as output. /// /// # Panics /// The function will panic if the provided pin is not in the allowed range of 0-7 @@ -159,7 +159,7 @@ where /// Sets the input polarity of the given pin to normal. /// - /// A logic high voltage applied at an input pin results in a `1` written to the devices input register and thus being registered as `high` by the driver. + /// A logic high voltage applied at an input pin results in a `1` written to the device's input register, thus being registered as `high` by the driver. /// /// # Panics /// The function will panic if the provided pin is not in the allowed range of 0-7 @@ -180,14 +180,14 @@ where /// Sets the input polarity of all pins to inverted. /// - /// A logic high voltage applied at an input pin results in a `0` written to the devices input register and thus being registered as `low` by the driver. + /// A logic high voltage applied at an input pin results in a `0` written to the device's input register, thus being registered as `low` by the driver. fn inverse_polarity(&mut self) -> Result<(), ExpanderError> { self.write_halfword(Register::PolarityInversionPort0, 0xFFFF_u16) } /// Sets the input polarity of all pins to normal. /// - /// A logic high voltage applied at an input pin results in a `1` written to the devices input register and thus being registered as `high` by the driver. + /// A logic high voltage applied at an input pin results in a `1` written to the device's input register, thus being registered as `high` by the driver. fn normal_polarity(&mut self) -> Result<(), ExpanderError> { self.write_halfword(Register::PolarityInversionPort0, 0x0_u16) } diff --git a/src/lib.rs b/src/lib.rs index 656a8b6..9494b50 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,20 +2,19 @@ PCA9535 driver using embedded-hal ## Device -The PCA9535 and PCA9535C are 16Bit IO-Expanders using the I2C/SMBus interface. The devices operate at a voltage level of 2.3-5.5V +The PCA9535 and PCA9535C are 16-bit IO-Expanders using the I2C/SMBus interface. The devices operate at a voltage level of 2.3-5.5V ### GPIO The expander provides two 5V tolerant GPIO banks with eight pins. Each pin is configurable separately as either input or output and additionally allows for polarity inversion. -The open drain interrupt output of the device indicates a change if any of the input states differs from the state of the input port register. +The open-drain interrupt output of the device indicates a change if any of the input states differs from the state of the input port register. -On initialization all pins are configured as high impedance inputs. The PCA9535 features totem pole IOs while the PCA9535C IOs are open-drain. +On initialization, all pins are configured as high-impedance inputs. The PCA9535 features totem pole IOs, while the PCA9535C IOs are open-drain. ### I2C The device uses 7Bit addressing and allows the hardware configuration of the first 3 address bits, allowing for up to 8 expanders on the same bus. ## General info -The library uses the blocking I2C embedded-hal traits. Each implementation of [`Expander`] owns the provided I2C instance, -if multiple device access to the bus is required the user has to provide the code to make it work. -No synchronization is done inside the library. For this purpose it is recommended to use crates like [shared-bus](https://crates.io/crates/shared-bus) +The library uses the blocking I2C embedded-hal traits. Each implementation of [`Expander`] owns the provided I2C instance. +If multiple drivers/devices need access to the same I2C bus, sharing the bus using crates like [embedded-hal-bus](https://crates.io/crates/embedded-hal-bus) is recommended. # Usage This library can be used in multiple ways depending on the use case and needs. @@ -24,34 +23,51 @@ This library can be used in multiple ways depending on the use case and needs. The device has two possible configurations on how i2c bus traffic is handled: ### Immediate -The immediate expander interface [`Pca9535Immediate`] issues a i2c bus transaction on each function call a state change of the expander. +The immediate expander interface [`Pca9535Immediate`] issues an i2c bus transaction on each function call, which changes the state of the expander. It does not make use of the open drain interrupt output of the device to reduce bus traffic and does not hold any state on the device registers. -```ignore +```no_run +use rppal::i2c::I2c; use pca9535::Pca9535Immediate; +let i2c = I2c::new().unwrap(); +let address = 32; + let expander = Pca9535Immediate::new(i2c, address); ``` ### Cached -The cached expander interface [`Pca9535Cached`] stores the state of the devices registers internally in order to reduce the i2c bus traffic as much as much as possible. +The cached expander interface [`Pca9535Cached`] stores the state of the device registers internally to reduce the i2c bus traffic as much as possible. It relies on the open drain interrupt pin of the device to detect any changes to the registers. Thus, the use of this hardware pin is mandatory for this interface. -```ignore +```no_run +use rppal::i2c::I2c; +use rppal::gpio::Gpio; use pca9535::Pca9535Cached; -let expander_interrupt_pin = ...; //A HAL GPIO Input pin which is connected to the interrupt pin of the IO Expander +let gpio = Gpio::new().unwrap(); +//A HAL GPIO Input pin which is connected to the interrupt pin of the IO Expander +let expander_interrupt_pin = gpio.get(0).unwrap().into_input(); + +let i2c = I2c::new().unwrap(); +let address = 32; + let expander = Pca9535Cached::new(i2c, address, expander_interrupt_pin, true); // create cached expander and initialize cache to defaults ``` ## Usage types -Once the operation type has been determined there are two ways of interacting with the IO expander: +Once the operation type has been determined, there are two ways of interacting with the IO expander: ### Standard Expander Interface Every [`Expander`] implements the [`StandardExpanderInterface`]. This interface offers various functions to interact with the expander. -Those functions do not hold any state of wether the pins are currently configured as inputs or outputs. The user needs to ensure that the pins are in the desired configuration -before calling other functions in order to get valid and expected results. -```ignore +Those functions do not hold any state of whether the pins are currently configured as inputs or outputs. The user needs to ensure that the pins are in the desired configuration +before calling other functions to get valid and expected results. +```no_run +use rppal::i2c::I2c; use pca9535::GPIOBank; use pca9535::StandardExpanderInterface; +use pca9535::Pca9535Immediate; -let mut expander = ...; //Either Immediate or Cached expander +let i2c = I2c::new().unwrap(); +let address = 32; + +let mut expander = Pca9535Immediate::new(i2c, address); //Either Immediate or Cached expander expander.pin_into_output(GPIOBank::Bank0, 3).unwrap(); expander.pin_set_high(GPIOBank::Bank0, 3).unwrap(); @@ -60,36 +76,52 @@ expander.pin_set_high(GPIOBank::Bank0, 3).unwrap(); ### Expander HAL Pins This interface offers the possibility to use the GPIO of the IO expander as [`hal`] pins, either to use for other [`hal`] librariers or just as a standardized way to handle GPIOs. As this is a special interface which is sync and can be used across multiple threads etc. the operation types need to be wrapped into an [`IoExpander`] type. -```ignore -use pca9535::IoExpander; +```no_run use std::sync::Mutex; +use rppal::i2c::I2c; +use pca9535::IoExpander; +use pca9535::Pca9535Immediate; + +let i2c = I2c::new().unwrap(); +let address = 32; -let expander = ...; //Either Immediate or Cached expander +let mut expander = Pca9535Immediate::new(i2c, address); //Either Immediate or Cached expander -let io_expander = IoExpander, _> = IoExpander::new(expander); // Wrapped expander in std environment using Mutex as ExpanderMutex +let io_expander: IoExpander<_, _, Mutex<_>> = IoExpander::new(expander); // Wrapped expander in std environment using Mutex as ExpanderMutex ``` -By using this wrapper, the expander gets automatically wrapped into an [`ExpanderMutex`] which ensures exclusive access to the expander and makes it [`Sync`]. -Currently ExpanderMutex is only implemented for `std` environment. You can activate this implementation by enabling the "std" feature of this crate. For other architectures on bare metal etc. -the ExpanderMutex trait can be implemented on any type which ensures exclusive access to the contained data. Once this is done the expander can be wrapped inside a IoExpander as described previously +Using this wrapper, the expander gets automatically wrapped into an [`ExpanderMutex`], which ensures exclusive access to the expander and makes it [`Sync`]. +Currently, ExpanderMutex is only implemented for the `std` environment. You can activate this implementation by enabling the "std" feature of this crate. For other architectures on bare metal, etc. +The ExpanderMutex trait can be implemented on any type, which ensures exclusive access to the contained data. Once this is done, the expander can be wrapped inside an IoExpander as described previously using the newly implemented ExpanderMutex trait. -Now it is possible to generate either [`ExpanderInputPin`] or [`ExpanderOutputPin`] and manipulate the IO expander through those pins. +Now, it is possible to generate either [`ExpanderInputPin`] or [`ExpanderOutputPin`] and manipulate the IO expander through those pins. They implement all the standard [`hal`] traits on GPIO pins and could theoretically also be used in other libraries requiring hal GPIO pins. -```ignore +```no_run +use std::sync::Mutex; +use rppal::i2c::I2c; +use hal::digital::{InputPin, OutputPin}; +use pca9535::IoExpander; +use pca9535::Pca9535Immediate; use pca9535::{ExpanderInputPin, ExpanderOutputPin}; use pca9535::GPIOBank::{Bank0, Bank1}; use pca9535::PinState; -let io_expander = ...; // Wrapped expander +let i2c = I2c::new().unwrap(); +let address = 32; + +let mut expander = Pca9535Immediate::new(i2c, address); + +let io_expander: IoExpander<_, _, Mutex<_>> = IoExpander::new(expander); let mut expander_pin_1_5 = ExpanderInputPin::new(&io_expander, Bank1, 5).unwrap(); let mut expander_pin_0_2 = ExpanderOutputPin::new(&io_expander, Bank0, 2, PinState::Low).unwrap(); expander_pin_0_2.set_high(); -expander_pin_1_5.into_output_pin(PinState::Low); +let is_high = expander_pin_1_5.is_high(); // and so on... ``` */ +#![forbid(unsafe_code)] #![cfg_attr(not(feature = "std"), no_std)] pub mod expander; @@ -113,8 +145,8 @@ pub use pin::ExpanderOutputPin; /// The enum represents the command byte values used to access the corresponding registers. /// /// # Register pairs -/// The registers of the device are all 8 bit and act as four register pairs. Therefore, writing a halfword to a register results in the 8 least significant bits -/// being written to the provided register, while the 8 most significant bits will be automatically written to the other register of the pair. +/// The device's registers are all 8-bit and act as four register pairs. Therefore, writing a half-word to a register results in the eight least significant bits +/// being written to the provided register, while the eight most significant bits will be automatically written to the other register of the pair. /// /// **Pairs** /// 1) InputPort0 and InputPort1 @@ -123,27 +155,47 @@ pub use pin::ExpanderOutputPin; /// 4) ConfigurationPort0 and ConfigurationPort1 /// /// Example code -/// ```ignore -/// expander.write_halfword(OutputPort0, 0x4A07 as u16).unwrap(); +/// ```no_run +/// # use rppal::i2c::I2c; +/// # use pca9535::Pca9535Immediate; +/// # use pca9535::Expander; +/// # use pca9535::Register; +/// # +/// # let i2c = I2c::new().unwrap(); +/// # let address = 32; +/// # +/// # let mut expander = Pca9535Immediate::new(i2c, address); +/// # +/// expander.write_halfword(Register::OutputPort0, 0x4A07 as u16).unwrap(); /// /// let mut output_bank0: u8 = 0x00; /// let mut output_bank1: u8 = 0x00; /// -/// expander.read_byte(OutputPort0, &mut output_bank0).unwrap(); -/// expander.read_byte(OutputPort1, &mut output_bank1).unwrap(); +/// expander.read_byte(Register::OutputPort0, &mut output_bank0).unwrap(); +/// expander.read_byte(Register::OutputPort1, &mut output_bank1).unwrap(); /// /// assert_eq!(output_bank0, 0x4A as u8); /// assert_eq!(output_bank1, 0x07 as u8); /// ``` /// Or -/// ```ignore -/// expander.write_halfword(OutputPort1, 0x4A07 as u16).unwrap(); +/// ```no_run +/// # use rppal::i2c::I2c; +/// # use pca9535::Pca9535Immediate; +/// # use pca9535::Expander; +/// # use pca9535::Register; +/// # +/// # let i2c = I2c::new().unwrap(); +/// # let address = 32; +/// # +/// # let mut expander = Pca9535Immediate::new(i2c, address); +/// # +/// expander.write_halfword(Register::OutputPort1, 0x4A07 as u16).unwrap(); /// /// let mut output_bank0: u8 = 0x00; /// let mut output_bank1: u8 = 0x00; /// -/// expander.read_byte(OutputPort0, &mut output_bank0).unwrap(); -/// expander.read_byte(OutputPort1, &mut output_bank1).unwrap(); +/// expander.read_byte(Register::OutputPort0, &mut output_bank0).unwrap(); +/// expander.read_byte(Register::OutputPort1, &mut output_bank1).unwrap(); /// /// assert_eq!(output_bank0, 0x07 as u8); /// assert_eq!(output_bank1, 0x4A as u8); diff --git a/src/mutex.rs b/src/mutex.rs index 31b2545..34f3385 100644 --- a/src/mutex.rs +++ b/src/mutex.rs @@ -1,8 +1,8 @@ //! Contains the ExpanderMutex Trait to use an Expander accross threads. -/// Each type that can implement this trait can be used as synchronization type for the [`crate::IoExpander`] which in turn is used to generate the [`hal`] pins. Due to this trait the pins are sync and can be used across threads etc. +/// Each type that can implement this trait can be used as a synchronization type for the [`crate::IoExpander`], which in turn is utilized to generate the [`hal`] pins. Due to this trait, the pins are synced and can be used across threads. /// -/// This trait can be implemented on all kinds of types which ensure exclusive access to the contained data. For `std` environments this trait is already implemented. It can be enabled by enabling the "std" feature of this library. +/// This trait can be implemented on all kinds of types, which ensure exclusive access to the contained data. For `std` environments, this trait is already implemented. It can be enabled by enabling the "std" feature of this library. pub trait ExpanderMutex where Ex: Send, diff --git a/src/pin.rs b/src/pin.rs index 54f7f5e..27ff866 100644 --- a/src/pin.rs +++ b/src/pin.rs @@ -167,7 +167,7 @@ where E: Debug, I2C: I2c, { - fn is_high(&self) -> Result { + fn is_high(&mut self) -> Result { let register = match self.bank { GPIOBank::Bank0 => Register::InputPort0, GPIOBank::Bank1 => Register::InputPort1, @@ -183,7 +183,7 @@ where } } - fn is_low(&self) -> Result { + fn is_low(&mut self) -> Result { let register = match self.bank { GPIOBank::Bank0 => Register::InputPort0, GPIOBank::Bank1 => Register::InputPort1, diff --git a/tests/README.md b/tests/README.md index c458fe0..b12a6c8 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,6 +1,6 @@ # Testing PCA9535 Library -The tests in this directory are integration tests which are performed by a Raspberry Pi connected to a PCA9535 IO Expander device. +The tests in this directory are integration tests, which are performed by a Raspberry Pi connected to a PCA9535 IO Expander device. ## Test organization @@ -10,9 +10,11 @@ The [cached](./cached.rs) contains all tests for cached expanders. It contains t The same applies for the [immediate](./immediate.rs) expander tests. ## Developing and running tests + If you develop the tests on a different operating system than the Raspberry Pi you can verify your test code by using the custom commands `cargo checktests` or `cargo clippytests` To run the tests on the Raspberry Pi you can use the standard `cargo test` command. ## Wiring -For more information on how to wire the Raspberry Pi and the PCA9535 for testing, please refer to the [schematics](./Schematics/pca9535_testbench) \ No newline at end of file + +For more information on how to wire the Raspberry Pi and the PCA9535 for testing, please refer to the [schematics](./Schematics/pca9535_testbench) diff --git a/tests/cached.rs b/tests/cached.rs index a664bc2..8cbae68 100644 --- a/tests/cached.rs +++ b/tests/cached.rs @@ -1,31 +1,37 @@ mod common; -use common::{ShareableI2c, ADDR, I2C_BUS}; +use common::{ShareableI2c, ADDR, I2C_MUTEX}; -use lazy_static::lazy_static; +use once_cell::sync::Lazy; +use embedded_hal_bus::i2c::MutexDevice; use rppal::gpio::{Gpio, InputPin}; use serial_test::serial; use std::sync::Mutex; use pca9535::{Expander, Pca9535Cached, Register}; -pub type CachedExpander = Pca9535Cached; +use crate::common::ShareableInputPin; -lazy_static! { - static ref INTERRUPT_PIN: InputPin = { - let gpio = Gpio::new().unwrap(); +pub type CachedExpander = Pca9535Cached>; - gpio.get(6).unwrap().into_input() - }; - static ref EXPANDER: Mutex = { - let i2c_bus = *I2C_BUS.lock().unwrap(); - let expander = - Pca9535Cached::new(i2c_bus.acquire_i2c(), ADDR, &*INTERRUPT_PIN, false).unwrap(); +static INTERRUPT_PIN: Lazy> = Lazy::new(|| { + let gpio = Gpio::new().unwrap(); - Mutex::new(expander) - }; -} + Mutex::new(gpio.get(6).unwrap().into_input()) +}); + +static EXPANDER: Lazy> = Lazy::new(|| { + let expander = Pca9535Cached::new( + MutexDevice::new(&I2C_MUTEX), + ADDR, + ShareableInputPin::new(&INTERRUPT_PIN), + false, + ) + .unwrap(); + + Mutex::new(expander) +}); #[test] #[serial(cached_std)] @@ -208,11 +214,12 @@ mod standard { #[cfg(test)] mod pin { - use super::common::{Pca9535GPIO, ShareableI2c, ADDR, I2C_BUS, RPI_GPIO}; + use super::common::{Pca9535GPIO, ShareableI2c, ShareableInputPin, ADDR, I2C_MUTEX, RPI_GPIO}; use super::{CachedExpander, INTERRUPT_PIN}; - use lazy_static::lazy_static; + use embedded_hal_bus::i2c::MutexDevice; + use once_cell::sync::Lazy; use serial_test::serial; use std::sync::Mutex; @@ -229,33 +236,36 @@ mod pin { >, >; - lazy_static! { - static ref IO_EXPANDER: IoExpander> = { - let i2c_bus = *I2C_BUS.lock().unwrap(); - let expander = - Pca9535Cached::new(i2c_bus.acquire_i2c(), ADDR, &*INTERRUPT_PIN, false).unwrap(); + static IO_EXPANDER: Lazy>> = + Lazy::new(|| { + let expander = Pca9535Cached::new( + MutexDevice::new(&I2C_MUTEX), + ADDR, + ShareableInputPin::new(&INTERRUPT_PIN), + false, + ) + .unwrap(); IoExpander::new(expander) + }); + static PCA9535_GPIO: Lazy = Lazy::new(|| { + let pca9535_gpio = Pca9535GPIO { + _in0_3: ExpanderInputPin::new(&*IO_EXPANDER, GPIOBank::Bank0, 3).unwrap(), + in0_4: ExpanderInputPin::new(&*IO_EXPANDER, GPIOBank::Bank0, 4).unwrap(), + _out0_7: ExpanderOutputPin::new(&*IO_EXPANDER, GPIOBank::Bank0, 7, PinState::High) + .unwrap(), + out1_5: ExpanderOutputPin::new(&*IO_EXPANDER, GPIOBank::Bank1, 5, PinState::Low) + .unwrap(), }; - static ref PCA9535_GPIO: Pca9535Gpio = { - let pca9535_gpio = Pca9535GPIO { - _in0_3: ExpanderInputPin::new(&*IO_EXPANDER, GPIOBank::Bank0, 3).unwrap(), - in0_4: ExpanderInputPin::new(&*IO_EXPANDER, GPIOBank::Bank0, 4).unwrap(), - _out0_7: ExpanderOutputPin::new(&*IO_EXPANDER, GPIOBank::Bank0, 7, PinState::High) - .unwrap(), - out1_5: ExpanderOutputPin::new(&*IO_EXPANDER, GPIOBank::Bank1, 5, PinState::Low) - .unwrap(), - }; - - Mutex::new(pca9535_gpio) - }; - } + + Mutex::new(pca9535_gpio) + }); #[test] #[serial(cached_pin)] fn input_pin_is_high() { let rpi_gpio = &mut *RPI_GPIO.lock().unwrap(); - let pca9535_gpio = PCA9535_GPIO.lock().unwrap(); + let mut pca9535_gpio = PCA9535_GPIO.lock().unwrap(); rpi_gpio.out0_4.set_high(); @@ -266,7 +276,7 @@ mod pin { #[serial(cached_pin)] fn input_pin_is_low() { let rpi_gpio = &mut *RPI_GPIO.lock().unwrap(); - let pca9535_gpio = PCA9535_GPIO.lock().unwrap(); + let mut pca9535_gpio = PCA9535_GPIO.lock().unwrap(); rpi_gpio.out0_4.set_low(); diff --git a/tests/common/mod.rs b/tests/common/mod.rs index eb3215c..fcaac71 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,8 +1,9 @@ -use hal::i2c::I2c as HalI2c; -use lazy_static::lazy_static; -use shared_bus::{BusManager, I2cProxy}; use std::sync::Mutex; +use embedded_hal_bus::i2c::MutexDevice; +use hal::digital::{ErrorType as HalErrorType, InputPin as HalInputPin}; +use hal::i2c::I2c as HalI2c; +use once_cell::sync::Lazy; use pca9535::expander::SyncExpander; use pca9535::{ExpanderInputPin, ExpanderOutputPin}; use rppal::gpio::{Gpio, InputPin, OutputPin}; @@ -10,35 +11,28 @@ use rppal::i2c::I2c; pub const ADDR: u8 = 33; //I2C address of IO Expander -pub type ShareableI2c = I2cProxy<'static, Mutex>; +pub type ShareableI2c = MutexDevice<'static, I2c>; -lazy_static! { - pub static ref I2C_BUS: Mutex<&'static BusManager>> = { - let i2c = I2c::new().unwrap(); - let i2c_bus: &'static _ = shared_bus::new_std!(I2c = i2c).unwrap(); +pub static I2C_MUTEX: Lazy> = Lazy::new(|| Mutex::new(I2c::new().unwrap())); +pub static RPI_GPIO: Lazy> = Lazy::new(|| { + let gpio = Gpio::new().unwrap(); - Mutex::new(i2c_bus) + let rpi_gpio = RpiGPIO { + in0_3: gpio.get(10).unwrap().into_input(), + out0_4: gpio.get(22).unwrap().into_output_low(), + out0_7: gpio.get(4).unwrap().into_output_low(), + in1_5: gpio.get(25).unwrap().into_input(), + out1_0: gpio.get(14).unwrap().into_output_low(), + out1_1: gpio.get(15).unwrap().into_output_low(), + _out1_2: gpio.get(18).unwrap().into_output_low(), + _out1_3: gpio.get(23).unwrap().into_output_low(), + _in1_4: gpio.get(24).unwrap().into_input(), + in1_6: gpio.get(8).unwrap().into_input(), + _in1_7: gpio.get(7).unwrap().into_input(), }; - pub static ref RPI_GPIO: Mutex = { - let gpio = Gpio::new().unwrap(); - - let rpi_gpio = RpiGPIO { - in0_3: gpio.get(10).unwrap().into_input(), - out0_4: gpio.get(22).unwrap().into_output_low(), - out0_7: gpio.get(4).unwrap().into_output_low(), - in1_5: gpio.get(25).unwrap().into_input(), - out1_0: gpio.get(14).unwrap().into_output_low(), - out1_1: gpio.get(15).unwrap().into_output_low(), - _out1_2: gpio.get(18).unwrap().into_output_low(), - _out1_3: gpio.get(23).unwrap().into_output_low(), - _in1_4: gpio.get(24).unwrap().into_input(), - in1_6: gpio.get(8).unwrap().into_input(), - _in1_7: gpio.get(7).unwrap().into_input(), - }; - Mutex::new(rpi_gpio) - }; -} + Mutex::new(rpi_gpio) +}); pub struct RpiGPIO { pub in0_3: InputPin, @@ -64,3 +58,34 @@ where pub _out0_7: ExpanderOutputPin<'a, I2C, T>, pub out1_5: ExpanderOutputPin<'a, I2C, T>, } + +/// embedded-hal [`HalInputPin`] which is shareable across threads using a [`Mutex`] +pub struct ShareableInputPin<'a, T> { + pin: &'a Mutex, +} + +impl<'a, T> ShareableInputPin<'a, T> { + pub fn new(pin: &'a Mutex) -> Self { + Self { pin } + } +} + +impl<'a, T> HalInputPin for ShareableInputPin<'a, T> +where + T: HalInputPin, +{ + fn is_high(&mut self) -> Result { + self.pin.lock().unwrap().is_high() + } + + fn is_low(&mut self) -> Result { + self.pin.lock().unwrap().is_low() + } +} + +impl<'a, T> HalErrorType for ShareableInputPin<'a, T> +where + T: HalInputPin, +{ + type Error = T::Error; +} diff --git a/tests/immediate.rs b/tests/immediate.rs index 8d4895b..e2f9d59 100644 --- a/tests/immediate.rs +++ b/tests/immediate.rs @@ -1,22 +1,20 @@ mod common; -use common::{ShareableI2c, ADDR, I2C_BUS}; +use common::{ShareableI2c, ADDR, I2C_MUTEX}; -use lazy_static::lazy_static; +use embedded_hal_bus::i2c::MutexDevice; +use once_cell::sync::Lazy; use std::sync::Mutex; use pca9535::{Expander, Pca9535Immediate, Register}; pub type ImmediateExpander = Pca9535Immediate; -lazy_static! { - static ref EXPANDER: Mutex = { - let i2c_bus = *I2C_BUS.lock().unwrap(); - let expander = Pca9535Immediate::new(i2c_bus.acquire_i2c(), ADDR); +static EXPANDER: Lazy> = Lazy::new(|| { + let expander = Pca9535Immediate::new(MutexDevice::new(&I2C_MUTEX), ADDR); - Mutex::new(expander) - }; -} + Mutex::new(expander) +}); #[test] fn read_write_byte() { @@ -191,10 +189,11 @@ mod standard { #[cfg(test)] mod pin { - use super::common::{Pca9535GPIO, ShareableI2c, ADDR, I2C_BUS, RPI_GPIO}; + use super::common::{Pca9535GPIO, ShareableI2c, ADDR, I2C_MUTEX, RPI_GPIO}; use super::ImmediateExpander; - use lazy_static::lazy_static; + use embedded_hal_bus::i2c::MutexDevice; + use once_cell::sync::Lazy; use serial_test::serial; use std::sync::Mutex; @@ -211,32 +210,31 @@ mod pin { >, >; - lazy_static! { - static ref IO_EXPANDER: IoExpander> = { - let i2c_bus = *I2C_BUS.lock().unwrap(); - let expander = Pca9535Immediate::new(i2c_bus.acquire_i2c(), ADDR); - - IoExpander::new(expander) - }; - static ref PCA9535_GPIO: Pca9535Gpio = { - let pca9535_gpio = Pca9535GPIO { - _in0_3: ExpanderInputPin::new(&*IO_EXPANDER, GPIOBank::Bank0, 3).unwrap(), - in0_4: ExpanderInputPin::new(&*IO_EXPANDER, GPIOBank::Bank0, 4).unwrap(), - _out0_7: ExpanderOutputPin::new(&*IO_EXPANDER, GPIOBank::Bank0, 7, PinState::High) - .unwrap(), - out1_5: ExpanderOutputPin::new(&*IO_EXPANDER, GPIOBank::Bank1, 5, PinState::Low) - .unwrap(), - }; - - Mutex::new(pca9535_gpio) + static IO_EXPANDER: Lazy< + IoExpander>, + > = Lazy::new(|| { + let expander = Pca9535Immediate::new(MutexDevice::new(&I2C_MUTEX), ADDR); + + IoExpander::new(expander) + }); + static PCA9535_GPIO: Lazy = Lazy::new(|| { + let pca9535_gpio = Pca9535GPIO { + _in0_3: ExpanderInputPin::new(&*IO_EXPANDER, GPIOBank::Bank0, 3).unwrap(), + in0_4: ExpanderInputPin::new(&*IO_EXPANDER, GPIOBank::Bank0, 4).unwrap(), + _out0_7: ExpanderOutputPin::new(&*IO_EXPANDER, GPIOBank::Bank0, 7, PinState::High) + .unwrap(), + out1_5: ExpanderOutputPin::new(&*IO_EXPANDER, GPIOBank::Bank1, 5, PinState::Low) + .unwrap(), }; - } + + Mutex::new(pca9535_gpio) + }); #[test] #[serial(immediate_pin)] fn input_pin_is_high() { let rpi_gpio = &mut *RPI_GPIO.lock().unwrap(); - let pca9535_gpio = PCA9535_GPIO.lock().unwrap(); + let mut pca9535_gpio = PCA9535_GPIO.lock().unwrap(); rpi_gpio.out0_4.set_high(); @@ -247,7 +245,7 @@ mod pin { #[serial(immediate_pin)] fn input_pin_is_low() { let rpi_gpio = &mut *RPI_GPIO.lock().unwrap(); - let pca9535_gpio = PCA9535_GPIO.lock().unwrap(); + let mut pca9535_gpio = PCA9535_GPIO.lock().unwrap(); rpi_gpio.out0_4.set_low();