Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement transactional I2C interface and add example #44

Merged
merged 1 commit into from
Nov 14, 2020

Conversation

eldruin
Copy link
Member

@eldruin eldruin commented Jun 17, 2020

I implemented the transactional I2C interface from rust-embedded/embedded-hal#223 and added an example with a driver which does a combined Write/Read transaction.
This is based on previous work from #33 by @ryankurte, rust-embedded/rust-i2cdev#51 and is similar to #35.

@eldruin eldruin requested a review from a team as a code owner June 17, 2020 16:35
@rust-highfive
Copy link

r? @nastevens

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added S-waiting-on-review Status: Review is incomplete T-embedded-linux labels Jun 17, 2020
@nastevens nastevens assigned posborne and ryankurte and unassigned nastevens Jun 17, 2020
@nastevens
Copy link
Member

Sorry, I haven't really been involved in these changes. Adding @ryankurte and @posborne instead as I believe they have.

Cargo.toml Outdated Show resolved Hide resolved
@eldruin eldruin force-pushed the transactional-i2c branch from 7512dbc to 45d4873 Compare June 18, 2020 12:11
@eldruin eldruin force-pushed the transactional-i2c branch 2 times, most recently from b95b792 to 468b21a Compare November 5, 2020 15:28
@eldruin
Copy link
Member Author

eldruin commented Nov 5, 2020

@ryankurte Do you know why embedded_hal::blocking::i2c::transactional::Default ends up being imported here? That seems to be the cause for the conflicting implementation errors:

error[E0119]: conflicting implementations of trait `hal::prelude::_embedded_hal_blocking_i2c_Write` for type `I2cdev`:
   --> src/lib.rs:187:1
    |
187 | impl hal::blocking::i2c::Write for I2cdev {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: conflicting implementation in crate `embedded_hal`:
            - impl<E, S> hal::prelude::_embedded_hal_blocking_i2c_Write for S
              where <S as hal::prelude::_embedded_hal_blocking_i2c_Transactional>::Error == E, S: hal::blocking::i2c::transactional::Default<E>, S: hal::prelude::_embedded_hal_blocking_i2c_Transactional;
    = note: downstream crates may implement trait `hal::blocking::i2c::transactional::Default<_>` for type `I2cdev`

@ryankurte
Copy link
Contributor

ryankurte commented Nov 5, 2020

ahh, yeah whoops i should have caught that over on e-h. i believe it's because the trait bounds are different for Write (over address and errror) and Default (only over error), which gives the compiler nightmares.

you should be able to fix this in e-h by also binding the AddressMode across the default impl (as is done in spi::transactional::Default for exactly the same reason), so it becomes pub trait Default<AddressMode, Error> {} and is used in all the impls and where clauses.

lmk how that goes / if you get stuck lmk and i can provide more guidance.

@eldruin eldruin force-pushed the transactional-i2c branch 2 times, most recently from 4fe086e to 23fa418 Compare November 6, 2020 08:53
@eldruin
Copy link
Member Author

eldruin commented Nov 6, 2020

Ah, thank you! I added address mode support to the transactional traits over at rust-embedded/embedded-hal#260.
However, the conflicting implementation error is still there. It disappears if I remove the explicit implementations of i2c::Read, i2c::Write and i2c::WriteRead, of course, but the point of the default implementation inside the i2c::transactional module was to make it optional for HALs to use it or not.
I still do not understand how the default implementation is being pulled in for I2cdev.

error[E0119]: conflicting implementations of trait `hal::prelude::_embedded_hal_blocking_i2c_Write` for type `I2cdev`:
   --> src/lib.rs:187:1
    |
187 | impl hal::blocking::i2c::Write for I2cdev {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: conflicting implementation in crate `embedded_hal`:
            - impl<A, E, S> hal::prelude::_embedded_hal_blocking_i2c_Write<A> for S
              where <S as hal::prelude::_embedded_hal_blocking_i2c_Transactional<A>>::Error == E, A: hal::blocking::i2c::AddressMode, S: hal::blocking::i2c::transactional::Default<A, E>, S: hal::prelude::_embedded_hal_blocking_i2c_Transactional<A>;
    = note: downstream crates may implement trait `hal::blocking::i2c::transactional::Default<u8, _>` for type `I2cdev`

@ryankurte
Copy link
Contributor

ohh right, went back and looked and you've also gotta drop the error bound from the default type to that the transactional::Default trait, i believe this is required so there is no possibility of it existing over a foreign type.

sorry i missed that from the last advice, the following patch to e-h works for me.

diff --git a/src/blocking/i2c.rs b/src/blocking/i2c.rs
index 087d208..27b2092 100644
--- a/src/blocking/i2c.rs
+++ b/src/blocking/i2c.rs
@@ -334,12 +334,12 @@ pub mod transactional {
 
     /// Default implementation of `blocking::i2c::Write`, `blocking::i2c::Read` and
     /// `blocking::i2c::WriteRead` traits for `blocking::i2c::Transactional` implementers.
-    pub trait Default<A: AddressMode, E>: Transactional<A, Error = E> {}
+    pub trait Default<A: AddressMode>: Transactional<A> {}
 
-    impl<A, E, S> Write<A> for S
+    impl<A: 'static , E, S> Write<A> for S
     where
         A: AddressMode,
-        S: self::Default<A, E> + Transactional<A, Error = E>,
+        S: self::Default<A> + Transactional<A, Error = E>,
     {
         type Error = E;
 
@@ -351,7 +351,7 @@ pub mod transactional {
     impl<A, E, S> Read<A> for S
     where
         A: AddressMode,
-        S: self::Default<A, E> + Transactional<A, Error = E>,
+        S: self::Default<A> + Transactional<A, Error = E>,
     {
         type Error = E;
 
@@ -363,7 +363,7 @@ pub mod transactional {
     impl<A, E, S> WriteRead<A> for S
     where
         A: AddressMode,
-        S: self::Default<A, E> + Transactional<A, Error = E>,
+        S: self::Default<A> + Transactional<A, Error = E>,
     {
         type Error = E;

@eldruin
Copy link
Member Author

eldruin commented Nov 9, 2020

@ryankurte Interesting. That works, thank you!
I still do not understand why it is a problem if nobody imported transactional::Default, though.

i believe this is required so there is no possibility of it existing over a foreign type.

Could you elaborate or refer me to some docs about this?

bors bot added a commit to rust-embedded/embedded-hal that referenced this pull request Nov 9, 2020
260: Transactional I2C address modes r=ryankurte a=eldruin

The transactional I2C traits did not support multiple address modes.
Thanks to @ryankurte for noticing this at rust-embedded/linux-embedded-hal#44

Co-authored-by: Diego Barrios Romero <[email protected]>
@ryankurte
Copy link
Contributor

Could you elaborate or refer me to some docs about this?

my thinking was that Address is sealed but Error is not, so you could plausibly create a new Error type somewhere else then try to impl Default over this, but, in digging into this more i have only confused myself further 😢 might have to chalk it up to experience painfully earned.

are we happy with / ready to land this then?

@eldruin
Copy link
Member Author

eldruin commented Nov 11, 2020

Yes, I am happy with the code itself as-is. However, to merge this we would need to make a new alpha release of embedded-hal and remove the patch to my branch.

bors bot added a commit to rust-embedded/embedded-hal that referenced this pull request Nov 12, 2020
261: Embedded-hal 1.0.0-alpha.4 release r=ryankurte a=eldruin

Once we have a new alpha release we can move forward with merging rust-embedded/linux-embedded-hal#44 
I also added the `html_root_url`, which is annoying but necessary according to the Rust API guidelines.

Co-authored-by: Diego Barrios Romero <[email protected]>
@eldruin
Copy link
Member Author

eldruin commented Nov 12, 2020

I have updated this to use embedded-hal 1.0.0-alpha.4 and is now ready to merge.

Copy link
Contributor

@ryankurte ryankurte left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

bors r+

bors bot added a commit that referenced this pull request Nov 12, 2020
44: Implement transactional I2C interface and add example r=ryankurte a=eldruin

I implemented the transactional I2C interface from rust-embedded/embedded-hal#223 and added an example with a driver which does a combined Write/Read transaction.
This is based on previous work from #33 by @ryankurte, rust-embedded/rust-i2cdev#51 and is similar to #35.

Co-authored-by: Diego Barrios Romero <[email protected]>
@bors
Copy link
Contributor

bors bot commented Nov 12, 2020

Timed out.

@eldruin
Copy link
Member Author

eldruin commented Nov 13, 2020

Bors timed out again.

@ryankurte
Copy link
Contributor

yeeeah, we really need to do #51 like all the other e-h repos

@eldruin
Copy link
Member Author

eldruin commented Nov 14, 2020

Hmm, but in this case Travis is not the problem. It is bors the one that timed out. Or am I missing something else?

@ryankurte
Copy link
Contributor

i might be misunderstanding but i thought the bors timeouts were usually because travis doesn't schedule / execute the job quickly enough (because the ewg burns through hours)

bors retry

@bors
Copy link
Contributor

bors bot commented Nov 14, 2020

Build succeeded:

@bors bors bot merged commit dfc0434 into rust-embedded:master Nov 14, 2020
@eldruin
Copy link
Member Author

eldruin commented Nov 15, 2020

Ah, I see. That sounds possible. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Review is incomplete T-embedded-linux
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants