From 6e8c8efa760881a39894b206a32bd7ff554bef6d Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 27 May 2020 19:24:37 +0200 Subject: [PATCH 01/26] Fix adding dyn --- src/fmt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fmt.rs b/src/fmt.rs index 3f66c89f3..d9d0446c0 100644 --- a/src/fmt.rs +++ b/src/fmt.rs @@ -3,7 +3,7 @@ //! TODO write example of usage use core::fmt::{Result, Write}; -impl Write for ::serial::Write +impl Write for dyn (::serial::Write) where Word: From, { From 0c8f46681af3e062fea9f1ee19aa9fac42209775 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 27 May 2020 19:25:05 +0200 Subject: [PATCH 02/26] Remove #[deny(warnings)] --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 1a903081a..5e07ec736 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -683,7 +683,6 @@ //! ``` #![deny(missing_docs)] -#![deny(warnings)] #![no_std] #[macro_use] From 936fd16d4a222161fcc16b17b3f895367d91e8f6 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 27 May 2020 19:26:09 +0200 Subject: [PATCH 03/26] Deny warnings on CI --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index a7cc51a5f..be4e5a45d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,9 @@ language: rust +env: + global: + RUSTFLAGS='-D warnings' + matrix: include: - env: TARGET=x86_64-unknown-linux-gnu From 05ddb7553fc0594196ae4eb2268530ca7e00af34 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Thu, 28 May 2020 08:34:55 +0200 Subject: [PATCH 04/26] Update stm32f30x dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 239db690e..5df0c8ebc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ version = "1.0.2" version = "0.1.1" [dev-dependencies] -stm32f30x = "0.6.0" +stm32f30x = "0.8.0" futures = "0.1.17" [features] From 5708d979d8e0f7ea3bfaa4f07fea0a56d026817a Mon Sep 17 00:00:00 2001 From: Roma Sokolov Date: Sun, 12 May 2019 19:15:12 +0200 Subject: [PATCH 05/26] Provide v2_compat for ToggleableOutputPin fixes #137 --- src/digital/v2_compat.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/digital/v2_compat.rs b/src/digital/v2_compat.rs index 779c089d3..bb5bae8b5 100644 --- a/src/digital/v2_compat.rs +++ b/src/digital/v2_compat.rs @@ -39,6 +39,9 @@ where } } +#[cfg(feature = "unproven")] +#[allow(deprecated)] +impl v2::toggleable::Default for T where T: v1::toggleable::Default {} /// Implementation of fallible `v2::InputPin` for `v1::InputPin` digital traits #[cfg(feature = "unproven")] @@ -81,6 +84,20 @@ mod tests { } } + #[allow(deprecated)] + impl v1::StatefulOutputPin for OldOutputPinImpl { + fn is_set_low(&self) -> bool { + self.state == false + } + + fn is_set_high(&self) -> bool { + self.state == true + } + } + + #[allow(deprecated)] + impl v1::toggleable::Default for OldOutputPinImpl {} + struct NewOutputPinConsumer { _pin: T, } @@ -92,6 +109,25 @@ mod tests { } } + struct NewToggleablePinConsumer { + _pin: T, + } + + impl NewToggleablePinConsumer + where + T: v2::ToggleableOutputPin, + { + pub fn new(pin: T) -> NewToggleablePinConsumer { + NewToggleablePinConsumer { _pin: pin } + } + } + + #[test] + fn v2_v1_toggleable_implicit() { + let i = OldOutputPinImpl { state: false }; + let _c = NewToggleablePinConsumer::new(i); + } + #[test] fn v2_v1_output_implicit() { let i = OldOutputPinImpl{state: false}; From 45324110519eb61e26f810580092593294e47b20 Mon Sep 17 00:00:00 2001 From: Ryan Kurte Date: Sun, 12 May 2019 10:56:57 +1200 Subject: [PATCH 06/26] improved digital compatibility docs --- src/digital/v1_compat.rs | 40 ++++++++++++++++++++++++++++++++++++---- src/digital/v2_compat.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/digital/v1_compat.rs b/src/digital/v1_compat.rs index aed9aaf7a..7ac6f544d 100644 --- a/src/digital/v1_compat.rs +++ b/src/digital/v1_compat.rs @@ -1,7 +1,39 @@ -//! v1 compatibility wrapper -//! this module adds reverse support for v2 digital traits -//! v2 traits must be explicitly cast to the v1 version using `.into()`, -//! and will panic on internal errors +//! v1 compatibility wrappers +//! +//! this module provides wrappers to support use of v2 implementations with +//! v1 consumers. v2 traits must be explicitly cast to the v1 version using +//! `.into()`, and will panic on internal errors +//! +//! ``` +//! extern crate embedded_hal; +//! use embedded_hal::digital::{v1, v2, v1_compat::OldOutputPin}; +//! +//! struct NewOutputPinImpl {} +//! +//! impl v2::OutputPin for NewOutputPinImpl { +//! type Error = (); +//! fn set_low(&mut self) -> Result<(), Self::Error> { Ok(()) } +//! fn set_high(&mut self) -> Result<(), Self::Error>{ Ok(()) } +//! } +//! +//! struct OldOutputPinConsumer { +//! _pin: T, +//! } +//! +//! impl OldOutputPinConsumer +//! where T: v1::OutputPin { +//! pub fn new(pin: T) -> OldOutputPinConsumer { +//! OldOutputPinConsumer{ _pin: pin } +//! } +//! } +//! +//! fn main() { +//! let pin = NewOutputPinImpl{}; +//! let _consumer: OldOutputPinConsumer> = OldOutputPinConsumer::new(pin.into()); +//! } +//! ``` +//! + #[allow(deprecated)] use super::v1; diff --git a/src/digital/v2_compat.rs b/src/digital/v2_compat.rs index bb5bae8b5..f88d8d38a 100644 --- a/src/digital/v2_compat.rs +++ b/src/digital/v2_compat.rs @@ -1,5 +1,36 @@ //! v2 compatibility shims +//! //! this module adds implicit forward support to v1 digital traits +//! allowing v1 implementations to be directly used with v2 consumers. +//! +//! ``` +//! extern crate embedded_hal; +//! use embedded_hal::digital::{v1, v2}; +//! +//! struct OldOutputPinImpl { } +//! +//! impl v1::OutputPin for OldOutputPinImpl { +//! fn set_low(&mut self) { } +//! fn set_high(&mut self) { } +//! } +//! +//! struct NewOutputPinConsumer { +//! _pin: T, +//! } +//! +//! impl NewOutputPinConsumer +//! where T: v2::OutputPin { +//! pub fn new(pin: T) -> NewOutputPinConsumer { +//! NewOutputPinConsumer{ _pin: pin } +//! } +//! } +//! +//! fn main() { +//! let pin = OldOutputPinImpl{}; +//! let _consumer = NewOutputPinConsumer::new(pin); +//! } +//! ``` +//! #[allow(deprecated)] use super::v1; From b1046883289984a769c53d62e76c5dd0c226cda0 Mon Sep 17 00:00:00 2001 From: Ryan Kurte Date: Sun, 26 May 2019 11:48:07 +1200 Subject: [PATCH 07/26] added capitals --- src/digital/v1_compat.rs | 2 +- src/digital/v2_compat.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/digital/v1_compat.rs b/src/digital/v1_compat.rs index 7ac6f544d..9de6e93ee 100644 --- a/src/digital/v1_compat.rs +++ b/src/digital/v1_compat.rs @@ -1,6 +1,6 @@ //! v1 compatibility wrappers //! -//! this module provides wrappers to support use of v2 implementations with +//! This module provides wrappers to support use of v2 implementations with //! v1 consumers. v2 traits must be explicitly cast to the v1 version using //! `.into()`, and will panic on internal errors //! diff --git a/src/digital/v2_compat.rs b/src/digital/v2_compat.rs index f88d8d38a..c96fee8b3 100644 --- a/src/digital/v2_compat.rs +++ b/src/digital/v2_compat.rs @@ -1,6 +1,6 @@ //! v2 compatibility shims //! -//! this module adds implicit forward support to v1 digital traits +//! This module adds implicit forward support to v1 digital traits, //! allowing v1 implementations to be directly used with v2 consumers. //! //! ``` From 59f33ca1a13d7da3f55eaa59a0ae656e9d819108 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 10 Jun 2020 08:39:44 +0200 Subject: [PATCH 08/26] Fix using InputPin instead of OutputPin Taken from https://github.com/rust-embedded/embedded-hal/pull/199 --- src/digital/v1_compat.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/digital/v1_compat.rs b/src/digital/v1_compat.rs index 9de6e93ee..bb3430f58 100644 --- a/src/digital/v1_compat.rs +++ b/src/digital/v1_compat.rs @@ -1,38 +1,38 @@ //! v1 compatibility wrappers -//! +//! //! This module provides wrappers to support use of v2 implementations with -//! v1 consumers. v2 traits must be explicitly cast to the v1 version using +//! v1 consumers. v2 traits must be explicitly cast to the v1 version using //! `.into()`, and will panic on internal errors -//! +//! //! ``` //! extern crate embedded_hal; //! use embedded_hal::digital::{v1, v2, v1_compat::OldOutputPin}; -//! +//! //! struct NewOutputPinImpl {} -//! +//! //! impl v2::OutputPin for NewOutputPinImpl { //! type Error = (); //! fn set_low(&mut self) -> Result<(), Self::Error> { Ok(()) } //! fn set_high(&mut self) -> Result<(), Self::Error>{ Ok(()) } //! } -//! +//! //! struct OldOutputPinConsumer { //! _pin: T, //! } -//! -//! impl OldOutputPinConsumer +//! +//! impl OldOutputPinConsumer //! where T: v1::OutputPin { //! pub fn new(pin: T) -> OldOutputPinConsumer { //! OldOutputPinConsumer{ _pin: pin } //! } //! } -//! +//! //! fn main() { //! let pin = NewOutputPinImpl{}; //! let _consumer: OldOutputPinConsumer> = OldOutputPinConsumer::new(pin.into()); //! } //! ``` -//! +//! #[allow(deprecated)] @@ -92,7 +92,7 @@ where /// where errors will panic. #[cfg(feature = "unproven")] #[allow(deprecated)] -impl v1::StatefulOutputPin for OldOutputPin +impl v1::StatefulOutputPin for OldOutputPin where T: v2::StatefulOutputPin, E: core::fmt::Debug, @@ -116,7 +116,7 @@ pub struct OldInputPin { #[cfg(feature = "unproven")] impl OldInputPin where - T: v2::OutputPin, + T: v2::InputPin, E: core::fmt::Debug, { /// Create an `OldInputPin` wrapper around a `v2::InputPin`. @@ -191,8 +191,8 @@ mod tests { } #[allow(deprecated)] - impl OldOutputPinConsumer - where T: v1::OutputPin + impl OldOutputPinConsumer + where T: v1::OutputPin { pub fn new(pin: T) -> OldOutputPinConsumer { OldOutputPinConsumer{ _pin: pin } @@ -213,7 +213,7 @@ mod tests { assert_eq!(o.inner().state, true); o.set_low(); - assert_eq!(o.inner().state, false); + assert_eq!(o.inner().state, false); } #[test] @@ -252,8 +252,8 @@ mod tests { #[cfg(feature = "unproven")] #[allow(deprecated)] - impl OldInputPinConsumer - where T: v1::InputPin + impl OldInputPinConsumer + where T: v1::InputPin { pub fn new(pin: T) -> OldInputPinConsumer { OldInputPinConsumer{ _pin: pin } From 55461c3bf751a7f3961b543e6f2cfcd2e86ccb53 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 10 Jun 2020 08:40:14 +0200 Subject: [PATCH 09/26] Update changelog with text from #199 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d7261970..b0b7fcd37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +- Fix the input pin v2->v1 compatibility shim constructor, where `OldInputPin::new` + was incorrectly implemented for `v1::OutputPin` values. + ## [v0.2.3] - 2019-05-09 From 27ccfb2602e62688a4c4805d8849c6a95865b9c4 Mon Sep 17 00:00:00 2001 From: ryan kurte Date: Wed, 10 Jun 2020 14:08:57 +1200 Subject: [PATCH 10/26] Updated cargo version and changelog for release v0.2.4 --- CHANGELOG.md | 11 +++++++++++ Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0b7fcd37..878436ac5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed + +## [v0.2.4] - 2020-06-10 + +### Added + + +### Changed + +- Fix for `dyn` traits in fmt.rs +- Remove `#![deny(warnings)]`, now imposed y CI +- Updates stm32f30x from 0.6.0 to 0.8.0 - Fix the input pin v2->v1 compatibility shim constructor, where `OldInputPin::new` was incorrectly implemented for `v1::OutputPin` values. diff --git a/Cargo.toml b/Cargo.toml index 5df0c8ebc..1caf2e767 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT OR Apache-2.0" name = "embedded-hal" readme = "README.md" repository = "https://github.com/japaric/embedded-hal" -version = "0.2.3" +version = "0.2.4" [dependencies.void] default-features = false From 689b2db345e2e9946b1598e85311a413eb8fb7f5 Mon Sep 17 00:00:00 2001 From: Ryan Date: Wed, 17 Jun 2020 19:49:00 +1200 Subject: [PATCH 11/26] Updated changelog Fixed links, Removed empty section --- CHANGELOG.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 878436ac5..8ef9757c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,9 +15,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [v0.2.4] - 2020-06-10 -### Added - - ### Changed - Fix for `dyn` traits in fmt.rs @@ -27,7 +24,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). was incorrectly implemented for `v1::OutputPin` values. -## [v0.2.3] - 2019-05-09 +## [v0.2.3] - 2019-05-17 ### Added - A new version of the digital `OutputPin`, `StatefulOutputPin`, `ToggleableOutputPin` @@ -112,8 +109,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). Initial release -[Unreleased]: https://github.com/japaric/embedded-hal/compare/v0.2.1...HEAD -[v0.2.1]: https://github.com/japaric/embedded-hal/compare/v0.2.0...v0.2.1 -[v0.2.0]: https://github.com/japaric/embedded-hal/compare/v0.1.2...v0.2.0 -[v0.1.2]: https://github.com/japaric/embedded-hal/compare/v0.1.1...v0.1.2 -[v0.1.1]: https://github.com/japaric/embedded-hal/compare/v0.1.0...v0.1.1 +[Unreleased]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.4...HEAD +[v0.2.4]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.3...v0.2.4 +[v0.2.3]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.2...v0.2.3 +[v0.2.2]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.1...v0.2.2 +[v0.2.1]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.0...v0.2.1 +[v0.2.0]: https://github.com/rust-embedded/embedded-hal/compare/v0.1.2...v0.2.0 +[v0.1.2]: https://github.com/rust-embedded/embedded-hal/compare/v0.1.1...v0.1.2 +[v0.1.1]: https://github.com/rust-embedded/embedded-hal/compare/v0.1.0...v0.1.1 From f3c191e6728eafb68d7804000acf6d5a806e1a69 Mon Sep 17 00:00:00 2001 From: Ryan Date: Wed, 17 Jun 2020 19:49:36 +1200 Subject: [PATCH 12/26] Fix dates --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ef9757c3..c543a64e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed -## [v0.2.4] - 2020-06-10 +## [v0.2.4] - 2020-06-17 ### Changed @@ -24,7 +24,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). was incorrectly implemented for `v1::OutputPin` values. -## [v0.2.3] - 2019-05-17 +## [v0.2.3] - 2019-05-09 ### Added - A new version of the digital `OutputPin`, `StatefulOutputPin`, `ToggleableOutputPin` From 98ab776106c7bfe14af8862240fa53793308f513 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 28 Apr 2021 07:02:25 +0200 Subject: [PATCH 13/26] Adapt to new Pin interface --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5e07ec736..be6c954b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -439,8 +439,8 @@ //! //! // Event loop //! loop { -//! Pin::new(&mut blinky).resume(); -//! Pin::new(&mut loopback).resume(); +//! Pin::new(&mut blinky).resume(()); +//! Pin::new(&mut loopback).resume(()); //! # break; //! } //! } From 0711f6e8b5afb6270e9431dc32e05543c8e47fa8 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 28 Apr 2021 07:03:08 +0200 Subject: [PATCH 14/26] Backport moving CI to github actions --- .github/bors.toml | 8 +++++- .github/workflows/ci.yml | 48 +++++++++++++++++++++++++++++++++ .github/workflows/clippy.yml | 20 ++++++++++++++ .github/workflows/rustfmt.yml | 22 +++++++++++++++ .github/workflows/test.yml | 29 ++++++++++++++++++++ .travis.yml | 50 ----------------------------------- ci/after_success.sh | 20 -------------- ci/install.sh | 9 ------- ci/script.sh | 12 --------- 9 files changed, 126 insertions(+), 92 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/clippy.yml create mode 100644 .github/workflows/rustfmt.yml create mode 100644 .github/workflows/test.yml delete mode 100644 .travis.yml delete mode 100644 ci/after_success.sh delete mode 100644 ci/install.sh delete mode 100644 ci/script.sh diff --git a/.github/bors.toml b/.github/bors.toml index ca42be0a5..c646f2461 100644 --- a/.github/bors.toml +++ b/.github/bors.toml @@ -1,4 +1,10 @@ block_labels = ["needs-decision"] delete_merged_branches = true required_approvals = 1 -status = ["continuous-integration/travis-ci/push"] +status = [ + "ci-linux (stable, x86_64-unknown-linux-gnu)", + "ci-linux (stable, thumbv6m-none-eabi)", + "ci-linux (stable, thumbv7m-none-eabi)", + "ci-linux (1.31.0, x86_64-unknown-linux-gnu)", + "fmt", +] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..1df8088de --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,48 @@ +on: + push: + branches: [ staging, trying, master ] + pull_request: + +name: Continuous integration + +env: + RUSTFLAGS: '--deny warnings' + +jobs: + ci-linux: + runs-on: ubuntu-latest + strategy: + matrix: + # All generated code should be running on stable now + rust: [stable] + + # The default target we're compiling on and for + TARGET: [x86_64-unknown-linux-gnu, thumbv6m-none-eabi, thumbv7m-none-eabi] + + include: + - rust: 1.31.0 + TARGET: x86_64-unknown-linux-gnu + + # Test nightly but don't fail + - rust: nightly + experimental: true + TARGET: x86_64-unknown-linux-gnu + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + target: ${{ matrix.TARGET }} + override: true + - uses: actions-rs/cargo@v1 + with: + command: check + args: --target=${{ matrix.TARGET }} + + - uses: actions-rs/cargo@v1 + with: + command: check + args: --target=${{ matrix.TARGET }} --features unproven + diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml new file mode 100644 index 000000000..adc3a6ed1 --- /dev/null +++ b/.github/workflows/clippy.yml @@ -0,0 +1,20 @@ +on: + push: + branches: [ staging, trying, master ] + pull_request: + +name: Clippy check +jobs: + clippy_check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: clippy + - uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/rustfmt.yml b/.github/workflows/rustfmt.yml new file mode 100644 index 000000000..80439edbd --- /dev/null +++ b/.github/workflows/rustfmt.yml @@ -0,0 +1,22 @@ +on: + push: + branches: [ staging, trying, master ] + pull_request: + +name: Code formatting check + +jobs: + fmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: rustfmt + - uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..ff46d17df --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,29 @@ +on: + push: + branches: [ staging, trying, master ] + pull_request: + +name: Test Suite + +env: + RUSTFLAGS: '--deny warnings' + +jobs: + ci-linux: + runs-on: ubuntu-latest + strategy: + matrix: + rust: [nightly] + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + target: ${{ matrix.TARGET }} + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: --features unproven diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index be4e5a45d..000000000 --- a/.travis.yml +++ /dev/null @@ -1,50 +0,0 @@ -language: rust - -env: - global: - RUSTFLAGS='-D warnings' - -matrix: - include: - - env: TARGET=x86_64-unknown-linux-gnu - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - - env: TARGET=thumbv6m-none-eabi - rust: beta - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - - env: TARGET=thumbv7m-none-eabi - rust: beta - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - - - env: TARGET=x86_64-unknown-linux-gnu - rust: nightly - if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master) - -before_install: set -e - -install: - - bash ci/install.sh - -script: - - bash ci/script.sh - -after_script: set +e - -after_success: - - bash ci/after_success.sh - -cache: cargo -before_cache: - # Travis can't cache files that are not readable by "others" - - chmod -R a+r $HOME/.cargo - -branches: - only: - - master - - staging - - trying - -notifications: - email: - on_success: never diff --git a/ci/after_success.sh b/ci/after_success.sh deleted file mode 100644 index c44255907..000000000 --- a/ci/after_success.sh +++ /dev/null @@ -1,20 +0,0 @@ -set -euxo pipefail - -main() { - cargo doc --target $TARGET - - mkdir ghp-import - - curl -Ls https://github.com/davisp/ghp-import/archive/master.tar.gz | \ - tar --strip-components 1 -C ghp-import -xz - - ./ghp-import/ghp_import.py target/$TARGET/doc - - set +x - git push -fq https://$GH_TOKEN@github.com/$TRAVIS_REPO_SLUG.git gh-pages && \ - echo OK -} - -if [ "$TRAVIS_EVENT_TYPE" == "push" ] && [ "$TRAVIS_BRANCH" == "master" ]; then - main -fi diff --git a/ci/install.sh b/ci/install.sh deleted file mode 100644 index 3c4192119..000000000 --- a/ci/install.sh +++ /dev/null @@ -1,9 +0,0 @@ -set -euxo pipefail - -main() { - if [ $TARGET != x86_64-unknown-linux-gnu ]; then - rustup target add $TARGET - fi -} - -main diff --git a/ci/script.sh b/ci/script.sh deleted file mode 100644 index 12c05e27b..000000000 --- a/ci/script.sh +++ /dev/null @@ -1,12 +0,0 @@ -set -euxo pipefail - -main() { - cargo check --target $TARGET - cargo check --target $TARGET --features unproven - - if [ $TRAVIS_RUST_VERSION = nightly ]; then - cargo test --target $TARGET --features unproven - fi -} - -main From c48b2a3a14830ba3f6af9e8779faba4a276cc017 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 28 Apr 2021 07:06:22 +0200 Subject: [PATCH 15/26] Code formatting --- src/blocking/i2c.rs | 2 +- src/digital/mod.rs | 10 +++-- src/digital/v1_compat.rs | 82 ++++++++++++++++++++++------------------ src/digital/v2.rs | 2 +- src/digital/v2_compat.rs | 80 ++++++++++++++++++++------------------- src/fmt.rs | 5 ++- src/spi.rs | 2 +- src/timer.rs | 2 +- src/watchdog.rs | 14 +++---- 9 files changed, 107 insertions(+), 92 deletions(-) diff --git a/src/blocking/i2c.rs b/src/blocking/i2c.rs index 1c654f770..57192cac8 100644 --- a/src/blocking/i2c.rs +++ b/src/blocking/i2c.rs @@ -124,6 +124,6 @@ pub trait WriteIterRead { bytes: B, buffer: &mut [u8], ) -> Result<(), Self::Error> - where + where B: IntoIterator; } diff --git a/src/digital/mod.rs b/src/digital/mod.rs index 4e67f9851..5e1848f02 100644 --- a/src/digital/mod.rs +++ b/src/digital/mod.rs @@ -1,11 +1,14 @@ //! Digital I/O //! -//! +//! //! // Deprecated / infallible traits -#[deprecated(since = "0.2.2", note = "Deprecated because the methods cannot return errors. \ - Users should use the traits in digital::v2.")] +#[deprecated( + since = "0.2.2", + note = "Deprecated because the methods cannot return errors. \ + Users should use the traits in digital::v2." +)] pub mod v1; // New / fallible traits @@ -22,4 +25,3 @@ pub mod v2_compat; // Re-export old traits so this isn't a breaking change #[allow(deprecated)] pub use self::v1::*; - diff --git a/src/digital/v1_compat.rs b/src/digital/v1_compat.rs index bb3430f58..83a9ffce7 100644 --- a/src/digital/v1_compat.rs +++ b/src/digital/v1_compat.rs @@ -34,7 +34,6 @@ //! ``` //! - #[allow(deprecated)] use super::v1; use super::v2; @@ -44,14 +43,14 @@ pub struct OldOutputPin { pin: T, } -impl OldOutputPin +impl OldOutputPin where - T: v2::OutputPin, + T: v2::OutputPin, E: core::fmt::Debug, { /// Create a new OldOutputPin wrapper around a `v2::OutputPin` pub fn new(pin: T) -> Self { - Self{pin} + Self { pin } } /// Fetch a reference to the inner `v2::OutputPin` impl @@ -61,22 +60,22 @@ where } } -impl From for OldOutputPin +impl From for OldOutputPin where - T: v2::OutputPin, + T: v2::OutputPin, E: core::fmt::Debug, { fn from(pin: T) -> Self { - OldOutputPin{pin} + OldOutputPin { pin } } } /// Implementation of `v1::OutputPin` trait for fallible `v2::OutputPin` output pins /// where errors will panic. #[allow(deprecated)] -impl v1::OutputPin for OldOutputPin +impl v1::OutputPin for OldOutputPin where - T: v2::OutputPin, + T: v2::OutputPin, E: core::fmt::Debug, { fn set_low(&mut self) { @@ -92,9 +91,9 @@ where /// where errors will panic. #[cfg(feature = "unproven")] #[allow(deprecated)] -impl v1::StatefulOutputPin for OldOutputPin +impl v1::StatefulOutputPin for OldOutputPin where - T: v2::StatefulOutputPin, + T: v2::StatefulOutputPin, E: core::fmt::Debug, { fn is_set_low(&self) -> bool { @@ -114,26 +113,25 @@ pub struct OldInputPin { } #[cfg(feature = "unproven")] -impl OldInputPin +impl OldInputPin where - T: v2::InputPin, + T: v2::InputPin, E: core::fmt::Debug, { /// Create an `OldInputPin` wrapper around a `v2::InputPin`. pub fn new(pin: T) -> Self { - Self{pin} + Self { pin } } - } #[cfg(feature = "unproven")] -impl From for OldInputPin +impl From for OldInputPin where - T: v2::InputPin, + T: v2::InputPin, E: core::fmt::Debug, { fn from(pin: T) -> Self { - OldInputPin{pin} + OldInputPin { pin } } } @@ -141,9 +139,9 @@ where /// where errors will panic. #[cfg(feature = "unproven")] #[allow(deprecated)] -impl v1::InputPin for OldInputPin +impl v1::InputPin for OldInputPin where - T: v2::InputPin, + T: v2::InputPin, E: core::fmt::Debug, { fn is_low(&self) -> bool { @@ -169,7 +167,7 @@ mod tests { #[derive(Clone)] struct NewOutputPinImpl { state: bool, - res: Result<(), ()> + res: Result<(), ()>, } impl v2::OutputPin for NewOutputPinImpl { @@ -179,7 +177,7 @@ mod tests { self.state = false; self.res } - fn set_high(&mut self) -> Result<(), Self::Error>{ + fn set_high(&mut self) -> Result<(), Self::Error> { self.state = true; self.res } @@ -191,23 +189,31 @@ mod tests { } #[allow(deprecated)] - impl OldOutputPinConsumer - where T: v1::OutputPin + impl OldOutputPinConsumer + where + T: v1::OutputPin, { pub fn new(pin: T) -> OldOutputPinConsumer { - OldOutputPinConsumer{ _pin: pin } + OldOutputPinConsumer { _pin: pin } } } #[test] fn v1_v2_output_explicit() { - let i = NewOutputPinImpl{state: false, res: Ok(())}; + let i = NewOutputPinImpl { + state: false, + res: Ok(()), + }; let _c: OldOutputPinConsumer> = OldOutputPinConsumer::new(i.into()); } #[test] fn v1_v2_output_state() { - let mut o: OldOutputPin<_> = NewOutputPinImpl{state: false, res: Ok(())}.into(); + let mut o: OldOutputPin<_> = NewOutputPinImpl { + state: false, + res: Ok(()), + } + .into(); o.set_high(); assert_eq!(o.inner().state, true); @@ -219,7 +225,11 @@ mod tests { #[test] #[should_panic] fn v1_v2_output_panic() { - let mut o: OldOutputPin<_> = NewOutputPinImpl{state: false, res: Err(())}.into(); + let mut o: OldOutputPin<_> = NewOutputPinImpl { + state: false, + res: Err(()), + } + .into(); o.set_high(); } @@ -239,7 +249,7 @@ mod tests { fn is_low(&self) -> Result { self.state.map(|v| v == false) } - fn is_high(&self) -> Result{ + fn is_high(&self) -> Result { self.state.map(|v| v == true) } } @@ -252,25 +262,26 @@ mod tests { #[cfg(feature = "unproven")] #[allow(deprecated)] - impl OldInputPinConsumer - where T: v1::InputPin + impl OldInputPinConsumer + where + T: v1::InputPin, { pub fn new(pin: T) -> OldInputPinConsumer { - OldInputPinConsumer{ _pin: pin } + OldInputPinConsumer { _pin: pin } } } #[cfg(feature = "unproven")] #[test] fn v1_v2_input_explicit() { - let i = NewInputPinImpl{state: Ok(false)}; + let i = NewInputPinImpl { state: Ok(false) }; let _c: OldInputPinConsumer> = OldInputPinConsumer::new(i.into()); } #[cfg(feature = "unproven")] #[test] fn v1_v2_input_state() { - let i: OldInputPin<_> = NewInputPinImpl{state: Ok(false)}.into(); + let i: OldInputPin<_> = NewInputPinImpl { state: Ok(false) }.into(); assert_eq!(i.is_low(), true); assert_eq!(i.is_high(), false); @@ -280,9 +291,8 @@ mod tests { #[test] #[should_panic] fn v1_v2_input_panic() { - let i: OldInputPin<_> = NewInputPinImpl{state: Err(())}.into(); + let i: OldInputPin<_> = NewInputPinImpl { state: Err(()) }.into(); i.is_low(); } - } diff --git a/src/digital/v2.rs b/src/digital/v2.rs index 748807225..d539606fb 100644 --- a/src/digital/v2.rs +++ b/src/digital/v2.rs @@ -24,7 +24,7 @@ pub trait OutputPin { /// /// *This trait is available if embedded-hal is built with the `"unproven"` feature.* #[cfg(feature = "unproven")] -pub trait StatefulOutputPin : OutputPin { +pub trait StatefulOutputPin: OutputPin { /// Is the pin in drive high mode? /// /// *NOTE* this does *not* read the electrical state of the pin diff --git a/src/digital/v2_compat.rs b/src/digital/v2_compat.rs index c96fee8b3..9c87271c8 100644 --- a/src/digital/v2_compat.rs +++ b/src/digital/v2_compat.rs @@ -1,36 +1,36 @@ //! v2 compatibility shims -//! +//! //! This module adds implicit forward support to v1 digital traits, //! allowing v1 implementations to be directly used with v2 consumers. -//! +//! //! ``` //! extern crate embedded_hal; //! use embedded_hal::digital::{v1, v2}; -//! +//! //! struct OldOutputPinImpl { } -//! +//! //! impl v1::OutputPin for OldOutputPinImpl { //! fn set_low(&mut self) { } //! fn set_high(&mut self) { } //! } -//! +//! //! struct NewOutputPinConsumer { //! _pin: T, //! } -//! -//! impl NewOutputPinConsumer +//! +//! impl NewOutputPinConsumer //! where T: v2::OutputPin { //! pub fn new(pin: T) -> NewOutputPinConsumer { //! NewOutputPinConsumer{ _pin: pin } //! } //! } -//! +//! //! fn main() { //! let pin = OldOutputPinImpl{}; //! let _consumer = NewOutputPinConsumer::new(pin); //! } //! ``` -//! +//! #[allow(deprecated)] use super::v1; @@ -38,7 +38,7 @@ use super::v2; /// Implementation of fallible `v2::OutputPin` for `v1::OutputPin` traits #[allow(deprecated)] -impl v2::OutputPin for T +impl v2::OutputPin for T where T: v1::OutputPin, { @@ -50,14 +50,14 @@ where } fn set_high(&mut self) -> Result<(), Self::Error> { - Ok(self.set_high()) - } + Ok(self.set_high()) + } } /// Implementation of fallible `v2::StatefulOutputPin` for `v1::StatefulOutputPin` digital traits #[cfg(feature = "unproven")] #[allow(deprecated)] -impl v2::StatefulOutputPin for T +impl v2::StatefulOutputPin for T where T: v1::StatefulOutputPin + v1::OutputPin, { @@ -65,9 +65,9 @@ where Ok(self.is_set_low()) } - fn is_set_high(&self) -> Result { - Ok(self.is_set_high()) - } + fn is_set_high(&self) -> Result { + Ok(self.is_set_high()) + } } #[cfg(feature = "unproven")] @@ -77,9 +77,9 @@ impl v2::toggleable::Default for T where T: v1::toggleable::Default {} /// Implementation of fallible `v2::InputPin` for `v1::InputPin` digital traits #[cfg(feature = "unproven")] #[allow(deprecated)] -impl v2::InputPin for T +impl v2::InputPin for T where - T: v1::InputPin + T: v1::InputPin, { // TODO: update to ! when never_type is stabilized type Error = (); @@ -88,9 +88,9 @@ where Ok(self.is_low()) } - fn is_high(&self) -> Result { - Ok(self.is_high()) - } + fn is_high(&self) -> Result { + Ok(self.is_high()) + } } #[cfg(test)] @@ -101,8 +101,8 @@ mod tests { use crate::digital::v2; #[allow(deprecated)] - struct OldOutputPinImpl { - state: bool + struct OldOutputPinImpl { + state: bool, } #[allow(deprecated)] @@ -133,10 +133,12 @@ mod tests { _pin: T, } - impl NewOutputPinConsumer - where T: v2::OutputPin { + impl NewOutputPinConsumer + where + T: v2::OutputPin, + { pub fn new(pin: T) -> NewOutputPinConsumer { - NewOutputPinConsumer{ _pin: pin } + NewOutputPinConsumer { _pin: pin } } } @@ -161,14 +163,14 @@ mod tests { #[test] fn v2_v1_output_implicit() { - let i = OldOutputPinImpl{state: false}; + let i = OldOutputPinImpl { state: false }; let _c = NewOutputPinConsumer::new(i); } #[test] fn v2_v1_output_state() { - let mut o = OldOutputPinImpl{state: false}; - + let mut o = OldOutputPinImpl { state: false }; + v2::OutputPin::set_high(&mut o).unwrap(); assert_eq!(o.state, true); @@ -178,8 +180,8 @@ mod tests { #[cfg(feature = "unproven")] #[allow(deprecated)] - struct OldInputPinImpl { - state: bool + struct OldInputPinImpl { + state: bool, } #[cfg(feature = "unproven")] @@ -199,26 +201,28 @@ mod tests { } #[cfg(feature = "unproven")] - impl NewInputPinConsumer - where T: v2::InputPin { + impl NewInputPinConsumer + where + T: v2::InputPin, + { pub fn new(pin: T) -> NewInputPinConsumer { - NewInputPinConsumer{ _pin: pin } + NewInputPinConsumer { _pin: pin } } } #[cfg(feature = "unproven")] #[test] fn v2_v1_input_implicit() { - let i = OldInputPinImpl{state: false}; + let i = OldInputPinImpl { state: false }; let _c = NewInputPinConsumer::new(i); } #[cfg(feature = "unproven")] #[test] fn v2_v1_input_state() { - let mut i = OldInputPinImpl{state: false}; - + let mut i = OldInputPinImpl { state: false }; + assert_eq!(v2::InputPin::is_high(&mut i).unwrap(), false); assert_eq!(v2::InputPin::is_low(&mut i).unwrap(), true); } -} \ No newline at end of file +} diff --git a/src/fmt.rs b/src/fmt.rs index d9d0446c0..33041a84f 100644 --- a/src/fmt.rs +++ b/src/fmt.rs @@ -3,12 +3,13 @@ //! TODO write example of usage use core::fmt::{Result, Write}; -impl Write for dyn (::serial::Write) +impl Write for dyn (::serial::Write) where Word: From, { fn write_str(&mut self, s: &str) -> Result { - let _ = s.as_bytes() + let _ = s + .as_bytes() .into_iter() .map(|c| block!(self.write(Word::from(*c)))) .last(); diff --git a/src/spi.rs b/src/spi.rs index b91e6d68b..20d8538cd 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -75,4 +75,4 @@ pub const MODE_2: Mode = Mode { pub const MODE_3: Mode = Mode { polarity: Polarity::IdleHigh, phase: Phase::CaptureOnSecondTransition, -}; \ No newline at end of file +}; diff --git a/src/timer.rs b/src/timer.rs index 74cf088f3..08ba27606 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -81,7 +81,7 @@ pub trait CountDown { pub trait Periodic {} /// Trait for cancelable countdowns. -pub trait Cancel : CountDown { +pub trait Cancel: CountDown { /// Error returned when a countdown can't be canceled. type Error; diff --git a/src/watchdog.rs b/src/watchdog.rs index ee8cefc32..41e76f6ba 100644 --- a/src/watchdog.rs +++ b/src/watchdog.rs @@ -1,7 +1,5 @@ //! Traits for interactions with a processors watchdog timer. - - /// Feeds an existing watchdog to ensure the processor isn't reset. Sometimes /// commonly referred to as "kicking" or "refreshing". #[cfg(feature = "unproven")] @@ -11,19 +9,19 @@ pub trait Watchdog { fn feed(&mut self); } - -/// Enables A watchdog timer to reset the processor if software is frozen or +/// Enables A watchdog timer to reset the processor if software is frozen or /// stalled. #[cfg(feature = "unproven")] pub trait WatchdogEnable { /// Unit of time used by the watchdog type Time; - /// Starts the watchdog with a given period, typically once this is done - /// the watchdog needs to be kicked periodically or the processor is reset. - fn start(&mut self, period: T) where T: Into; + /// Starts the watchdog with a given period, typically once this is done + /// the watchdog needs to be kicked periodically or the processor is reset. + fn start(&mut self, period: T) + where + T: Into; } - /// Disables a running watchdog timer so the processor won't be reset. #[cfg(feature = "unproven")] pub trait WatchdogDisable { From 4df0da2575345a5d6bba046795b61141f2c36b93 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 28 Apr 2021 07:18:33 +0200 Subject: [PATCH 16/26] Update codeowners to current team --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c9a13ab0f..fcca011ea 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @rust-embedded/hal @ilya-epifanov @thejpster +* @rust-embedded/hal From cb03917306d67bb6c84e39820478484f75689625 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Fri, 2 Oct 2020 11:32:52 +0200 Subject: [PATCH 17/26] Use nb version 0.1.3 for compatibility with nb 1.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1caf2e767..f3b17bd57 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ default-features = false version = "1.0.2" [dependencies.nb] -version = "0.1.1" +version = "0.1.3" [dev-dependencies] stm32f30x = "0.8.0" From 6b4b15da54e1dc3eb61364f2a5e8f68686335d82 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 28 Apr 2021 10:56:38 +0200 Subject: [PATCH 18/26] Update repository URL --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f3b17bd57..c74f49aa9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ keywords = ["hal", "IO"] license = "MIT OR Apache-2.0" name = "embedded-hal" readme = "README.md" -repository = "https://github.com/japaric/embedded-hal" +repository = "https://github.com/rust-embedded/embedded-hal" version = "0.2.4" [dependencies.void] From 0950d0ca682e4793dc74d77876c7afd5f5cbaeb4 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 28 Apr 2021 10:58:19 +0200 Subject: [PATCH 19/26] Prepare 0.2.5 release --- CHANGELOG.md | 9 ++++++++- Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c543a64e8..21310a4c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed +## [v0.2.5] - 2021-04-28 + +### Changed + +- Updated `nb` dependency to version `0.1.3` to ensure compatibility with `nb` version `1.0`. + ## [v0.2.4] - 2020-06-17 @@ -109,7 +115,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). Initial release -[Unreleased]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.4...HEAD +[Unreleased]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.5...v0.2.x +[v0.2.5]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.4...v0.2.5 [v0.2.4]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.3...v0.2.4 [v0.2.3]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.2...v0.2.3 [v0.2.2]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.1...v0.2.2 diff --git a/Cargo.toml b/Cargo.toml index c74f49aa9..2921daf73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT OR Apache-2.0" name = "embedded-hal" readme = "README.md" repository = "https://github.com/rust-embedded/embedded-hal" -version = "0.2.4" +version = "0.2.5" [dependencies.void] default-features = false From 77b262dfaf03742bf4edf69d536d1adb6d0a3be9 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 31 Jul 2021 08:07:24 +0300 Subject: [PATCH 20/26] backport i2c --- src/blocking/i2c.rs | 206 ++++++++++++++++++++++++++++++++++++++++---- src/lib.rs | 4 + 2 files changed, 191 insertions(+), 19 deletions(-) diff --git a/src/blocking/i2c.rs b/src/blocking/i2c.rs index 57192cac8..60bb1538d 100644 --- a/src/blocking/i2c.rs +++ b/src/blocking/i2c.rs @@ -1,12 +1,122 @@ //! Blocking I2C API //! -//! Slave addresses used by this API are 7-bit I2C addresses ranging from 0 to 127. +//! This API supports 7-bit and 10-bit addresses. Traits feature an `AddressMode` +//! marker type parameter. Two implementation of the `AddressMode` exist: +//! `SevenBitAddress` and `TenBitAddress`. //! -//! Operations on 10-bit slave addresses are not supported by the API yet (but applications might -//! be able to emulate some operations). +//! Through this marker types it is possible to implement each address mode for +//! the traits independently in `embedded-hal` implementations and device drivers +//! can depend only on the mode that they support. +//! +//! Additionally, the I2C 10-bit address mode has been developed to be fully +//! backwards compatible with the 7-bit address mode. This allows for a +//! software-emulated 10-bit addressing implementation if the address mode +//! is not supported by the hardware. +//! +//! Since 7-bit addressing is the mode of the majority of I2C devices, +//! `SevenBitAddress` has been set as default mode and thus can be omitted if desired. +//! +//! ## Examples +//! +//! ### `embedded-hal` implementation for an MCU +//! Here is an example of an embedded-hal implementation of the `Write` trait +//! for both modes: +//! ``` +//! # use embedded_hal::blocking::i2c::{SevenBitAddress, TenBitAddress, Write}; +//! /// I2C0 hardware peripheral which supports both 7-bit and 10-bit addressing. +//! pub struct I2c0; +//! +//! impl Write for I2c0 +//! { +//! # type Error = (); +//! # +//! fn write(&mut self, addr: u8, output: &[u8]) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! } +//! +//! impl Write for I2c0 +//! { +//! # type Error = (); +//! # +//! fn write(&mut self, addr: u16, output: &[u8]) -> Result<(), Self::Error> { +//! // ... +//! # Ok(()) +//! } +//! } +//! ``` +//! +//! ### Device driver compatible only with 7-bit addresses +//! +//! For demonstration purposes the address mode parameter has been omitted in this example. +//! +//! ``` +//! # use embedded_hal::blocking::i2c::WriteRead; +//! const ADDR: u8 = 0x15; +//! # const TEMP_REGISTER: u8 = 0x1; +//! pub struct TemperatureSensorDriver { +//! i2c: I2C, +//! } +//! +//! impl TemperatureSensorDriver +//! where +//! I2C: WriteRead, +//! { +//! pub fn read_temperature(&mut self) -> Result { +//! let mut temp = [0]; +//! self.i2c +//! .write_read(ADDR, &[TEMP_REGISTER], &mut temp) +//! .and(Ok(temp[0])) +//! } +//! } +//! ``` +//! +//! ### Device driver compatible only with 10-bit addresses +//! +//! ``` +//! # use embedded_hal::blocking::i2c::{TenBitAddress, WriteRead}; +//! const ADDR: u16 = 0x158; +//! # const TEMP_REGISTER: u8 = 0x1; +//! pub struct TemperatureSensorDriver { +//! i2c: I2C, +//! } +//! +//! impl TemperatureSensorDriver +//! where +//! I2C: WriteRead, +//! { +//! pub fn read_temperature(&mut self) -> Result { +//! let mut temp = [0]; +//! self.i2c +//! .write_read(ADDR, &[TEMP_REGISTER], &mut temp) +//! .and(Ok(temp[0])) +//! } +//! } +//! ``` + +use crate::private; + +impl private::Sealed for SevenBitAddress {} +impl private::Sealed for TenBitAddress {} + +/// Address mode (7-bit / 10-bit) +/// +/// Note: This trait is sealed and should not be implemented outside of this crate. +pub trait AddressMode: private::Sealed {} + +/// 7-bit address mode type +pub type SevenBitAddress = u8; + +/// 10-bit address mode type +pub type TenBitAddress = u16; + +impl AddressMode for SevenBitAddress {} + +impl AddressMode for TenBitAddress {} /// Blocking read -pub trait Read { +pub trait Read { /// Error type type Error; @@ -28,15 +138,15 @@ pub trait Read { /// - `MAK` = master acknowledge /// - `NMAK` = master no acknowledge /// - `SP` = stop condition - fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error>; + fn read(&mut self, address: A, buffer: &mut [u8]) -> Result<(), Self::Error>; } /// Blocking write -pub trait Write { +pub trait Write { /// Error type type Error; - /// Sends bytes to slave with address `addr` + /// Writes bytes to slave with address `address` /// /// # I2C Events (contract) /// @@ -52,31 +162,30 @@ pub trait Write { /// - `SAK` = slave acknowledge /// - `Bi` = ith byte of data /// - `SP` = stop condition - fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error>; + fn write(&mut self, address: A, bytes: &[u8]) -> Result<(), Self::Error>; } /// Blocking write (iterator version) -#[cfg(feature = "unproven")] -pub trait WriteIter { +pub trait WriteIter { /// Error type type Error; - /// Sends bytes to slave with address `addr` + /// Writes bytes to slave with address `address` /// /// # I2C Events (contract) /// /// Same as `Write` - fn write(&mut self, addr: u8, bytes: B) -> Result<(), Self::Error> + fn write(&mut self, address: A, bytes: B) -> Result<(), Self::Error> where B: IntoIterator; } /// Blocking write + read -pub trait WriteRead { +pub trait WriteRead { /// Error type type Error; - /// Sends bytes to slave with address `addr` and then reads enough bytes to fill `buffer` *in a + /// Writes bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a /// single transaction* /// /// # I2C Events (contract) @@ -100,19 +209,18 @@ pub trait WriteRead { /// - `SP` = stop condition fn write_read( &mut self, - address: u8, + address: A, bytes: &[u8], buffer: &mut [u8], ) -> Result<(), Self::Error>; } /// Blocking write (iterator version) + read -#[cfg(feature = "unproven")] -pub trait WriteIterRead { +pub trait WriteIterRead { /// Error type type Error; - /// Sends bytes to slave with address `addr` and then reads enough bytes to fill `buffer` *in a + /// Writes bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a /// single transaction* /// /// # I2C Events (contract) @@ -120,10 +228,70 @@ pub trait WriteIterRead { /// Same as the `WriteRead` trait fn write_iter_read( &mut self, - address: u8, + address: A, bytes: B, buffer: &mut [u8], ) -> Result<(), Self::Error> where B: IntoIterator; } + +/// Transactional I2C operation. +/// +/// Several operations can be combined as part of a transaction. +#[derive(Debug, PartialEq)] +pub enum Operation<'a> { + /// Read data into the provided buffer + Read(&'a mut [u8]), + /// Write data from the provided buffer + Write(&'a [u8]), +} + +/// Transactional I2C interface. +/// +/// This allows combining operations within an I2C transaction. +pub trait Transactional { + /// Error type + type Error; + + /// Execute the provided operations on the I2C bus. + /// + /// Transaction contract: + /// - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate. + /// - Data from adjacent operations of the same type are sent after each other without an SP or SR. + /// - Between adjacent operations of a different type an SR and SAD+R/W is sent. + /// - After executing the last operation an SP is sent automatically. + /// - If the last operation is a `Read` the master does not send an acknowledge for the last byte. + /// + /// - `ST` = start condition + /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 to indicate writing + /// - `SR` = repeated start condition + /// - `SP` = stop condition + fn exec<'a>(&mut self, address: A, operations: &mut [Operation<'a>]) + -> Result<(), Self::Error>; +} + +/// Transactional I2C interface (iterator version). +/// +/// This allows combining operation within an I2C transaction. +pub trait TransactionalIter { + /// Error type + type Error; + + /// Execute the provided operations on the I2C bus (iterator version). + /// + /// Transaction contract: + /// - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate. + /// - Data from adjacent operations of the same type are sent after each other without an SP or SR. + /// - Between adjacent operations of a different type an SR and SAD+R/W is sent. + /// - After executing the last operation an SP is sent automatically. + /// - If the last operation is a `Read` the master does not send an acknowledge for the last byte. + /// + /// - `ST` = start condition + /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 to indicate writing + /// - `SR` = repeated start condition + /// - `SP` = stop condition + fn exec_iter<'a, O>(&mut self, address: A, operations: O) -> Result<(), Self::Error> + where + O: IntoIterator>; +} diff --git a/src/lib.rs b/src/lib.rs index be6c954b0..e5db66af1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -992,3 +992,7 @@ pub enum Direction { /// 1, 2, 3 Upcounting, } + +mod private { + pub trait Sealed {} +} From 1ef9f26b3ea025c07418325d953c821ef1eaff54 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 31 Jul 2021 08:37:30 +0300 Subject: [PATCH 21/26] backport digital --- src/digital/v2.rs | 78 ++++++++++++++++++++++++++++++++++++++++ src/digital/v2_compat.rs | 6 ++++ 2 files changed, 84 insertions(+) diff --git a/src/digital/v2.rs b/src/digital/v2.rs index d539606fb..81fd67cbb 100644 --- a/src/digital/v2.rs +++ b/src/digital/v2.rs @@ -2,6 +2,46 @@ //! //! Version 2 / fallible traits. Infallible implementations should set Error to `!`. +use core::{convert::From, ops::Not}; + +/// Digital output pin state +/// +/// Conversion from `bool` and logical negation are also implemented +/// for this type. +/// ```rust +/// # use embedded_hal::digital::v2::PinState; +/// let state = PinState::from(false); +/// assert_eq!(state, PinState::Low); +/// assert_eq!(!state, PinState::High); +/// ``` +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum PinState { + /// Low pin state + Low, + /// High pin state + High, +} + +impl From for PinState { + fn from(value: bool) -> Self { + match value { + false => PinState::Low, + true => PinState::High, + } + } +} + +impl Not for PinState { + type Output = PinState; + + fn not(self) -> Self::Output { + match self { + PinState::High => PinState::Low, + PinState::Low => PinState::High, + } + } +} + /// Single digital push-pull output pin pub trait OutputPin { /// Error type @@ -18,6 +58,17 @@ pub trait OutputPin { /// *NOTE* the actual electrical state of the pin may not actually be high, e.g. due to external /// electrical sources fn set_high(&mut self) -> Result<(), Self::Error>; + + /// Drives the pin high or low depending on the provided value + /// + /// *NOTE* the actual electrical state of the pin may not actually be high or low, e.g. due to external + /// electrical sources + fn set_state(&mut self, state: PinState) -> Result<(), Self::Error> { + match state { + PinState::Low => self.set_low(), + PinState::High => self.set_high(), + } + } } /// Push-pull output pin that can read its output state @@ -136,3 +187,30 @@ pub trait InputPin { /// Is the input pin low? fn is_low(&self) -> Result; } + +/// Single pin that can switch from input to output mode, and vice-versa. +/// +/// Example use (assumes the `Error` type is the same for the `IoPin`, +/// `InputPin`, and `OutputPin`): +/// +/// *This trait is available if embedded-hal is built with the `"unproven"` feature.* +#[cfg(feature = "unproven")] +pub trait IoPin +where + TInput: InputPin + IoPin, + TOutput: OutputPin + IoPin, +{ + /// Error type. + type Error; + + /// Tries to convert this pin to input mode. + /// + /// If the pin is already in input mode, this method should succeed. + fn into_input_pin(self) -> Result; + + /// Tries to convert this pin to output mode with the given initial state. + /// + /// If the pin is already in the requested state, this method should + /// succeed. + fn into_output_pin(self, state: PinState) -> Result; +} diff --git a/src/digital/v2_compat.rs b/src/digital/v2_compat.rs index 9c87271c8..929f413dd 100644 --- a/src/digital/v2_compat.rs +++ b/src/digital/v2_compat.rs @@ -116,6 +116,7 @@ mod tests { } #[allow(deprecated)] + #[cfg(feature = "unproven")] impl v1::StatefulOutputPin for OldOutputPinImpl { fn is_set_low(&self) -> bool { self.state == false @@ -127,6 +128,7 @@ mod tests { } #[allow(deprecated)] + #[cfg(feature = "unproven")] impl v1::toggleable::Default for OldOutputPinImpl {} struct NewOutputPinConsumer { @@ -142,10 +144,12 @@ mod tests { } } + #[cfg(feature = "unproven")] struct NewToggleablePinConsumer { _pin: T, } + #[cfg(feature = "unproven")] impl NewToggleablePinConsumer where T: v2::ToggleableOutputPin, @@ -156,6 +160,7 @@ mod tests { } #[test] + #[cfg(feature = "unproven")] fn v2_v1_toggleable_implicit() { let i = OldOutputPinImpl { state: false }; let _c = NewToggleablePinConsumer::new(i); @@ -212,6 +217,7 @@ mod tests { #[cfg(feature = "unproven")] #[test] + #[cfg(feature = "unproven")] fn v2_v1_input_implicit() { let i = OldInputPinImpl { state: false }; let _c = NewInputPinConsumer::new(i); From d84543f13a327f8339e71ade34cca94930589d77 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 31 Jul 2021 10:32:12 +0300 Subject: [PATCH 22/26] backport spi::Transactional --- src/blocking/spi.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/blocking/spi.rs b/src/blocking/spi.rs index 84e48029f..76623e290 100644 --- a/src/blocking/spi.rs +++ b/src/blocking/spi.rs @@ -104,3 +104,24 @@ pub mod write_iter { } } } + +/// Operation for transactional SPI trait +/// +/// This allows composition of SPI operations into a single bus transaction +#[derive(Debug, PartialEq)] +pub enum Operation<'a, W: 'static> { + /// Write data from the provided buffer, discarding read data + Write(&'a [W]), + /// Write data out while reading data into the provided buffer + Transfer(&'a mut [W]), +} + +/// Transactional trait allows multiple actions to be executed +/// as part of a single SPI transaction +pub trait Transactional { + /// Associated error type + type Error; + + /// Execute the provided transactions + fn exec<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error>; +} From 769b933390219de9329a680ab837ec03b6e91477 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 1 Aug 2021 11:14:36 +0300 Subject: [PATCH 23/26] update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21310a4c9..103f51115 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- `Transactional` SPI interface for executing groups of SPI transactions. +- `Transactional` I2C interface for executing groups of I2C transactions. +- 10-bit addressing mode for I2C traits. +- `set_state` method for `OutputPin` using an input `PinState` value. +- `IoPin` trait for pins that can change between being inputs or outputs + dynamically. ### Changed From 33642078881e953907a301f8e8dd74c8766038ec Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Tue, 3 Aug 2021 20:14:00 +0200 Subject: [PATCH 24/26] Prepare 0.2.6 release --- CHANGELOG.md | 8 ++++++-- Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 103f51115..be9e7a095 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.2.6] - 2021-08-03 + ### Added +Backported non-breaking changes from the upcoming 1.0 release: + - `Transactional` SPI interface for executing groups of SPI transactions. - `Transactional` I2C interface for executing groups of I2C transactions. - 10-bit addressing mode for I2C traits. @@ -16,7 +20,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `IoPin` trait for pins that can change between being inputs or outputs dynamically. -### Changed ## [v0.2.5] - 2021-04-28 @@ -121,7 +124,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). Initial release -[Unreleased]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.5...v0.2.x +[Unreleased]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.6...v0.2.x +[v0.2.6]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.5...v0.2.6 [v0.2.5]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.4...v0.2.5 [v0.2.4]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.3...v0.2.4 [v0.2.3]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.2...v0.2.3 diff --git a/Cargo.toml b/Cargo.toml index 2921daf73..a60ac4971 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT OR Apache-2.0" name = "embedded-hal" readme = "README.md" repository = "https://github.com/rust-embedded/embedded-hal" -version = "0.2.5" +version = "0.2.6" [dependencies.void] default-features = false From 8281dd37e741c353f865d71947b435433c0119d9 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 31 Oct 2021 11:35:19 +0300 Subject: [PATCH 25/26] backport CAN --- CHANGELOG.md | 2 + src/blocking/can.rs | 17 +++++ src/blocking/mod.rs | 1 + src/can/id.rs | 160 ++++++++++++++++++++++++++++++++++++++++++++ src/can/mod.rs | 123 ++++++++++++++++++++++++++++++++++ src/can/nb.rs | 28 ++++++++ src/lib.rs | 1 + 7 files changed, 332 insertions(+) create mode 100644 src/blocking/can.rs create mode 100644 src/can/id.rs create mode 100644 src/can/mod.rs create mode 100644 src/can/nb.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index be9e7a095..ca5f6a2a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Backport CAN interface from the upcoming 1.0 release. + ## [v0.2.6] - 2021-08-03 ### Added diff --git a/src/blocking/can.rs b/src/blocking/can.rs new file mode 100644 index 000000000..b13885abe --- /dev/null +++ b/src/blocking/can.rs @@ -0,0 +1,17 @@ +//! Blocking CAN API + +/// A blocking CAN interface that is able to transmit and receive frames. +pub trait Can { + /// Associated frame type. + type Frame: crate::can::Frame; + + /// Associated error type. + type Error: crate::can::Error; + + /// Puts a frame in the transmit buffer. Blocks until space is available in + /// the transmit buffer. + fn transmit(&mut self, frame: &Self::Frame) -> Result<(), Self::Error>; + + /// Blocks until a frame was received or an error occured. + fn receive(&mut self) -> Result; +} diff --git a/src/blocking/mod.rs b/src/blocking/mod.rs index 3a050f6d2..e3c132826 100644 --- a/src/blocking/mod.rs +++ b/src/blocking/mod.rs @@ -4,6 +4,7 @@ //! traits. To save boilerplate when that's the case a `Default` marker trait may be provided. //! Implementing that marker trait will opt in your type into a blanket implementation. +pub mod can; pub mod delay; pub mod i2c; pub mod rng; diff --git a/src/can/id.rs b/src/can/id.rs new file mode 100644 index 000000000..811baa5f1 --- /dev/null +++ b/src/can/id.rs @@ -0,0 +1,160 @@ +//! CAN Identifiers. + +/// Standard 11-bit CAN Identifier (`0..=0x7FF`). +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct StandardId(u16); + +impl StandardId { + /// CAN ID `0`, the highest priority. + pub const ZERO: Self = StandardId(0); + + /// CAN ID `0x7FF`, the lowest priority. + pub const MAX: Self = StandardId(0x7FF); + + /// Tries to create a `StandardId` from a raw 16-bit integer. + /// + /// This will return `None` if `raw` is out of range of an 11-bit integer (`> 0x7FF`). + #[inline] + pub fn new(raw: u16) -> Option { + if raw <= 0x7FF { + Some(StandardId(raw)) + } else { + None + } + } + + /// Creates a new `StandardId` without checking if it is inside the valid range. + /// + /// # Safety + /// Using this method can create an invalid ID and is thus marked as unsafe. + #[inline] + pub const unsafe fn new_unchecked(raw: u16) -> Self { + StandardId(raw) + } + + /// Returns this CAN Identifier as a raw 16-bit integer. + #[inline] + pub fn as_raw(&self) -> u16 { + self.0 + } +} + +/// Extended 29-bit CAN Identifier (`0..=1FFF_FFFF`). +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct ExtendedId(u32); + +impl ExtendedId { + /// CAN ID `0`, the highest priority. + pub const ZERO: Self = ExtendedId(0); + + /// CAN ID `0x1FFFFFFF`, the lowest priority. + pub const MAX: Self = ExtendedId(0x1FFF_FFFF); + + /// Tries to create a `ExtendedId` from a raw 32-bit integer. + /// + /// This will return `None` if `raw` is out of range of an 29-bit integer (`> 0x1FFF_FFFF`). + #[inline] + pub fn new(raw: u32) -> Option { + if raw <= 0x1FFF_FFFF { + Some(ExtendedId(raw)) + } else { + None + } + } + + /// Creates a new `ExtendedId` without checking if it is inside the valid range. + /// + /// # Safety + /// Using this method can create an invalid ID and is thus marked as unsafe. + #[inline] + pub const unsafe fn new_unchecked(raw: u32) -> Self { + ExtendedId(raw) + } + + /// Returns this CAN Identifier as a raw 32-bit integer. + #[inline] + pub fn as_raw(&self) -> u32 { + self.0 + } + + /// Returns the Base ID part of this extended identifier. + pub fn standard_id(&self) -> StandardId { + // ID-28 to ID-18 + StandardId((self.0 >> 18) as u16) + } +} + +/// A CAN Identifier (standard or extended). +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum Id { + /// Standard 11-bit Identifier (`0..=0x7FF`). + Standard(StandardId), + + /// Extended 29-bit Identifier (`0..=0x1FFF_FFFF`). + Extended(ExtendedId), +} + +impl From for Id { + #[inline] + fn from(id: StandardId) -> Self { + Id::Standard(id) + } +} + +impl From for Id { + #[inline] + fn from(id: ExtendedId) -> Self { + Id::Extended(id) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn standard_id_new() { + assert_eq!( + StandardId::new(StandardId::MAX.as_raw()), + Some(StandardId::MAX) + ); + } + + #[test] + fn standard_id_new_out_of_range() { + assert_eq!(StandardId::new(StandardId::MAX.as_raw() + 1), None); + } + + #[test] + fn standard_id_new_unchecked_out_of_range() { + let id = StandardId::MAX.as_raw() + 1; + assert_eq!(unsafe { StandardId::new_unchecked(id) }, StandardId(id)); + } + + #[test] + fn extended_id_new() { + assert_eq!( + ExtendedId::new(ExtendedId::MAX.as_raw()), + Some(ExtendedId::MAX) + ); + } + + #[test] + fn extended_id_new_out_of_range() { + assert_eq!(ExtendedId::new(ExtendedId::MAX.as_raw() + 1), None); + } + + #[test] + fn extended_id_new_unchecked_out_of_range() { + let id = ExtendedId::MAX.as_raw() + 1; + assert_eq!(unsafe { ExtendedId::new_unchecked(id) }, ExtendedId(id)); + } + + #[test] + fn get_standard_id_from_extended_id() { + assert_eq!( + Some(ExtendedId::MAX.standard_id()), + StandardId::new((ExtendedId::MAX.0 >> 18) as u16) + ); + } +} diff --git a/src/can/mod.rs b/src/can/mod.rs new file mode 100644 index 000000000..c12e40a7f --- /dev/null +++ b/src/can/mod.rs @@ -0,0 +1,123 @@ +//! Controller Area Network + +pub mod nb; + +mod id; + +pub use self::id::*; +pub use self::nb::*; + +/// A CAN2.0 Frame +pub trait Frame: Sized { + /// Creates a new frame. + /// + /// This will return `None` if the data slice is too long. + fn new(id: impl Into, data: &[u8]) -> Option; + + /// Creates a new remote frame (RTR bit set). + /// + /// This will return `None` if the data length code (DLC) is not valid. + fn new_remote(id: impl Into, dlc: usize) -> Option; + + /// Returns true if this frame is a extended frame. + fn is_extended(&self) -> bool; + + /// Returns true if this frame is a standard frame. + fn is_standard(&self) -> bool { + !self.is_extended() + } + + /// Returns true if this frame is a remote frame. + fn is_remote_frame(&self) -> bool; + + /// Returns true if this frame is a data frame. + fn is_data_frame(&self) -> bool { + !self.is_remote_frame() + } + + /// Returns the frame identifier. + fn id(&self) -> Id; + + /// Returns the data length code (DLC) which is in the range 0..8. + /// + /// For data frames the DLC value always matches the length of the data. + /// Remote frames do not carry any data, yet the DLC can be greater than 0. + fn dlc(&self) -> usize; + + /// Returns the frame data (0..8 bytes in length). + fn data(&self) -> &[u8]; +} + +/// CAN error +pub trait Error: core::fmt::Debug { + /// Convert error to a generic CAN error kind + /// + /// By using this method, CAN errors freely defined by HAL implementations + /// can be converted to a set of generic serial errors upon which generic + /// code can act. + fn kind(&self) -> ErrorKind; +} + +/// CAN error kind +/// +/// This represents a common set of CAN operation errors. HAL implementations are +/// free to define more specific or additional error types. However, by providing +/// a mapping to these common CAN errors, generic code can still react to them. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum ErrorKind { + /// The peripheral receive buffer was overrun. + Overrun, + + // MAC sublayer errors + /// A bit error is detected at that bit time when the bit value that is + /// monitored differs from the bit value sent. + Bit, + + /// A stuff error is detected at the bit time of the sixth consecutive + /// equal bit level in a frame field that shall be coded by the method + /// of bit stuffing. + Stuff, + + /// Calculated CRC sequence does not equal the received one. + Crc, + + /// A form error shall be detected when a fixed-form bit field contains + /// one or more illegal bits. + Form, + + /// An ACK error shall be detected by a transmitter whenever it does not + /// monitor a dominant bit during the ACK slot. + Acknowledge, + + /// A different error occurred. The original error may contain more information. + Other, +} + +impl Error for ErrorKind { + fn kind(&self) -> ErrorKind { + *self + } +} + +impl core::fmt::Display for ErrorKind { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + ErrorKind::Overrun => write!(f, "The peripheral receive buffer was overrun"), + ErrorKind::Bit => write!( + f, + "Bit value that is monitored differs from the bit value sent" + ), + ErrorKind::Stuff => write!(f, "Sixth consecutive equal bits detected"), + ErrorKind::Crc => write!(f, "Calculated CRC sequence does not equal the received one"), + ErrorKind::Form => write!( + f, + "A fixed-form bit field contains one or more illegal bits" + ), + ErrorKind::Acknowledge => write!(f, "Transmitted frame was not acknowledged"), + ErrorKind::Other => write!( + f, + "A different error occurred. The original error may contain more information" + ), + } + } +} diff --git a/src/can/nb.rs b/src/can/nb.rs new file mode 100644 index 000000000..2ab6050a5 --- /dev/null +++ b/src/can/nb.rs @@ -0,0 +1,28 @@ +//! Non-blocking CAN API + +/// A CAN interface that is able to transmit and receive frames. +pub trait Can { + /// Associated frame type. + type Frame: crate::can::Frame; + + /// Associated error type. + type Error: crate::can::Error; + + /// Puts a frame in the transmit buffer to be sent on the bus. + /// + /// If the transmit buffer is full, this function will try to replace a pending + /// lower priority frame and return the frame that was replaced. + /// Returns `Err(WouldBlock)` if the transmit buffer is full and no frame can be + /// replaced. + /// + /// # Notes for implementers + /// + /// * Frames of equal identifier shall be transmited in FIFO fashion when more + /// than one transmit buffer is available. + /// * When replacing pending frames make sure the frame is not in the process of + /// being send to the bus. + fn transmit(&mut self, frame: &Self::Frame) -> nb::Result, Self::Error>; + + /// Returns a received frame if available. + fn receive(&mut self) -> nb::Result; +} diff --git a/src/lib.rs b/src/lib.rs index e5db66af1..f0289b2f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -691,6 +691,7 @@ extern crate void; pub mod adc; pub mod blocking; +pub mod can; pub mod digital; pub mod fmt; pub mod prelude; From 08c2b886391bbfcddd9928c426c265692c4c0dc3 Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Wed, 9 Feb 2022 09:37:39 +0100 Subject: [PATCH 26/26] Prepare 0.2.7 release --- CHANGELOG.md | 7 ++++++- Cargo.toml | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca5f6a2a5..7fc2bbecc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.2.7] - 2022-02-09 + +### Added + - Backport CAN interface from the upcoming 1.0 release. ## [v0.2.6] - 2021-08-03 @@ -126,7 +130,8 @@ Backported non-breaking changes from the upcoming 1.0 release: Initial release -[Unreleased]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.6...v0.2.x +[Unreleased]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.7...v0.2.x +[v0.2.7]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.6...v0.2.7 [v0.2.6]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.5...v0.2.6 [v0.2.5]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.4...v0.2.5 [v0.2.4]: https://github.com/rust-embedded/embedded-hal/compare/v0.2.3...v0.2.4 diff --git a/Cargo.toml b/Cargo.toml index a60ac4971..8b9249410 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [package] authors = [ + "The Embedded HAL Team ", "Jorge Aparicio ", "Jonathan 'theJPster' Pallant " ] @@ -11,7 +12,7 @@ license = "MIT OR Apache-2.0" name = "embedded-hal" readme = "README.md" repository = "https://github.com/rust-embedded/embedded-hal" -version = "0.2.6" +version = "0.2.7" [dependencies.void] default-features = false