-
Notifications
You must be signed in to change notification settings - Fork 60
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 FullDuplex for Spi #122
base: master
Are you sure you want to change the base?
Conversation
Looks like it's not working, will push a correct version later :) |
Not 100% sure it's the best way to implement, but as far as I could test, it works (tested with ws2812-spi and a 10 leds chain). |
src/spi.rs
Outdated
fn send(&mut self, byte: u8) -> nb::Result<(), Error> { | ||
self.check_send()?; | ||
self.send_u8(byte); | ||
self.check_send().ok(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you discarding the result of the check_send the second time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've simply reused the code from the write
that does the same thing. You are right that it should raise any error instead of discarding it. Maybe this is also true in write
(same file) ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, we should check the datasheet to see if the status register needs to be read after writing the data to the data register.
I believe that the propose of this construct is to check the status of errors such as Overrun, etc. so I propose that we should implement method check_errors
that only checks for the errors and then propagate its result using the ? operator.
What do you think, @therealprof ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a good idea. If you think it's worth implementing, I can do it :) If you have other idea (eg. refactoring), I would be happy to help.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a good plan, we might want to be careful about which errors we propagate and which ones we drop but we can look at that later when we have the check_errors
function I guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'll draft something and add it here :)
d9a3f0b
to
f890bcc
Compare
I've tried to implement the |
match self.check_errors() { | ||
Ok(_) => Ok(()), | ||
Err(e) => Err(nb::Error::Other(e)), | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't this be written more obviously as:
match self.check_errors() { | |
Ok(_) => Ok(()), | |
Err(e) => Err(nb::Error::Other(e)), | |
} | |
self.check_errors().map_err(|e| nb::Error::Other(e)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought of that, but it seems you can only use it to change the error, not the Result
type wrapping everything (Result
vs nb::Result
here). I get this:
rror[E0308]: mismatched types
--> src/spi.rs:482:9
|
475 | fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
| --------------------- expected `core::result::Result<(), nb::Error<spi::Error>>` because of return type
...
482 | self.check_errors().map_err(|e| Err(nb::Error::Other(e)))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `nb::Error`, found enum `core::result::Result`
But maybe I'm not doing something correctly ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, my bad. Cut'n'pasto. Of course it needs to be (corrected above, too):
self.check_errors().map_err(|e| nb::Error::Other(e))
map_err()
automatically wraps the value returned from the closure in an Err
, cf. here: https://doc.rust-lang.org/src/core/result.rs.html#592
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that the map_err
isn't needed at all. Check for example the check_send
method, where check_errors
is called directly with the ?
operator. There might be an automatic Into trait implementation for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It works with ?
yes (and I was surprised), but not if using the statement for returning (ie. without ?
). I'll fix the map_err
except if you have something better in mind ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that the
map_err
isn't needed at all. Check for example thecheck_send
method, wherecheck_errors
is called directly with the?
operator. There might be an automatic Into trait implementation for it.
Depends on the signature. If we're replying the right Result
type then we can just use it directly. Indeed we can also use ?
if we have proper conversion implementations available, however IIRC using ?
as the last operation in a function is frowned upon and linted by clippy. ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, sorry, I missed that it was the last command in function. LGTM then with map_err
.
Thanks for the help ! |
Has anyone had a chance to test those changes in real life yet? |
I guess I could hookup a nRF24L01, capture some exchanges with analyzer to provide some better test if nobody can test this with an easier setup ? I don't have anything else (except for the ws2812 I'm using that motivated this change) |
Sorry, I forgot to think this through. I don't have anything to test besides this ws2812 setup as all my F0 are soldered on my keyboards, so there's no way I can monitor sck and miso pins... |
If you design a test scenario, I have a lot of hardware to test on. |
Sorry, I forgot to think this through. I don't have anything to test besides this ws2812 setup as all my F0 are soldered on my keyboards, so there's no way I can monitor sck and miso pins...
back on this... I was hoping I could find some f0, but found none :/. |
Sure, no problem. I believe that I have the NRF so there should be no problems. I believe that the peripheral on F4 is similar, so that you can debug on it and then send it to me to try out on the F0. |
even better, I have some brand new f4 here! |
check_errors only checks for Overrun, CRC error and ModeFault flags. Signed-off-by: Marc Poulhiès <[email protected]>
Hi. What is the status on this? Can I help in any way? |
@easybe Seems dormant to me. If you can test it, we can certainly get it merged. |
OK, I should be able to do that. |
Sorry, still haven't anything to test, but am using the code daily in a keyboard without any issue, so should be OK. Thanks Ezra if you can help with the testing.
|
db4b2ce
to
68b434a
Compare
This is a very simple impl for FullDuplex. The Transfer impl could be removed in favor of the default that is available by the availability of FullDuplex.