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

machine: modify UART and USB CDC ACM Read() to be blocking #3984

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from

Conversation

xudongzheng
Copy link
Contributor

Using a callback for receiving serial data eliminates the need for polling.

So far I've only modified the files for RP2040 as that's what I'm testing on. If this PR is in the right direction, I will modify type UART struct for the other boards as well.

@xudongzheng xudongzheng changed the title machine: add callback for UART and USB CDC ACM machine: implement callback for UART and USB CDC ACM Nov 4, 2023
@xudongzheng xudongzheng marked this pull request as ready for review November 6, 2023 14:54
Copy link
Member

@sago35 sago35 left a comment

Choose a reason for hiding this comment

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

LGTM

@deadprogram
Copy link
Member

The only change I would like to propose is to name this rxHandler instead. Great work @xudongzheng

Copy link
Member

@aykevl aykevl left a comment

Choose a reason for hiding this comment

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

Using a callback for receiving serial data eliminates the need for polling.

Is that the only reason? Because handling things inside an interrupt is a pretty big hammer. If this is the only reason, a much better approach would be to make methods like ReadByte blocking (to avoid polling).

Also, this is a new API so should be added here: https://tinygo.org/docs/reference/machine/#uart

Comment on lines 103 to 105
func (uart *UART) SetRXCallback(cb func(byte) bool) {
uart.rxCallback = cb
}
Copy link
Member

Choose a reason for hiding this comment

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

This needs documentation that includes the following:

  • it is an interrupt (not just a regular callback)
  • it should describe what the return value is

See for example:

// SetInterrupt sets an interrupt to be executed when a particular pin changes
// state. The pin should already be configured as an input, including a pull up
// or down if no external pull is provided.
//
// This call will replace a previously set callback on this pin. You can pass a
// nil func to unset the pin change interrupt. If you do so, the change
// parameter is ignored and can be set to any value (such as 0).
func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error {

@xudongzheng
Copy link
Contributor Author

xudongzheng commented Nov 10, 2023

Is that the only reason? Because handling things inside an interrupt is a pretty big hammer. If this is the only reason, a much better approach would be to make methods like ReadByte blocking (to avoid polling).

Thanks for the suggestion. Please see the latest commit fe186e9, which implements blocking Read() on both RP2040 UART and USB CDC ACM. If this implementation is preferred, I will go ahead and make the change for other boards as well, and also get rid of the RX callback code.

I opted to change the Read() behavior without changing the ReadByte() behavior since the error return value becomes meaningless if ReadByte() becomes blocking. However I can change ReadByte() along with the function return value if that's preferred.

@sago35
Copy link
Member

sago35 commented Nov 11, 2023

@xudongzheng
I believe the related PR and Issue are as follows.

#2739
#2597
#2625
#2625

The essence of this PR is to make the Read() functions for UART and USBCDC more aligned with the expected Go io.Reader interface. In other words, we want to ensure that it does not return a value where n == 0 and err == nil. This will enable standard Go functions like fmt.Scanf to work smoothly.

In that case, I believe it should be implemented without using a channel. Additionally, this change will break compatibility with TinyGo. Documentation is also necessary for this, and it needs to be reviewed carefully.

Of course, it might also be an option to define a struct like UARTxxxx instead of UART to maintain compatibility.

https://pkg.go.dev/io#Reader
Implementations of Read are discouraged from returning a zero byte count with a nil error, except when len(p) == 0.
Callers should treat a return of 0 and nil as indicating that nothing happened; in particular it does not indicate EOF.

@xudongzheng
Copy link
Contributor Author

xudongzheng commented Nov 11, 2023

In that case, I believe it should be implemented without using a channel.

I don't quite see how this would be implemented without channels. For that reason, I initially opted for adding a callback rather than changing the Read() behavior - anyone who wants blocking reads can easily add a channel and write a wrapper to make reads block.

I think the overhead of channel should be pretty low, and it should be one or two at most since there won't be that many serial ports. Performance-wise, it works well enough as I was able to receive about 400KB/s on RP2040 over USB CDC ACM.

Additionally, this change will break compatibility with TinyGo. Documentation is also necessary for this, and it needs to be reviewed carefully.

I agree, though I would like a bit more clarity on the implementation direction before I start working on the documentation.

@xudongzheng xudongzheng changed the title machine: implement callback for UART and USB CDC ACM machine: modify UART and USB CDC ACM Read() to be blocking Nov 16, 2023
@xudongzheng xudongzheng changed the base branch from release to dev November 16, 2023 05:37
@xudongzheng xudongzheng force-pushed the uart-cb-pr branch 2 times, most recently from 008029b to 64da725 Compare December 4, 2023 13:02
@lePereT
Copy link

lePereT commented Mar 3, 2024

Hi! Is there any progress on merging this PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants