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

Report initial input pin value #134

Open
nandlab opened this issue Jan 3, 2022 · 8 comments
Open

Report initial input pin value #134

nandlab opened this issue Jan 3, 2022 · 8 comments

Comments

@nandlab
Copy link

nandlab commented Jan 3, 2022

Thanks for your incredible work developing the firmata protocol!
I have forked the C++ firmata client implementation from dimitry-ishenko-cpp to adjust a few things: https://github.com/NANDLAB/firmata.
Here's the issue I had with his library: dimitry-ishenko-cpp/firmata#14

I have a set of pins, which I configure as PULLUP. I would like to know their initial value after setting the PULLUP input mode. How can I do this with firmata in general?

That's how I would set the pin (let's say pin 1) to pullup:

0  set digital pin mode (0xF4) (MIDI Undefined)
1  pin number 1
2  mode PULLUP (11)

Here's what I found in the documentation about setting digital reporting:

Toggle digital port reporting by port (second nibble of byte 0), eg 0xD1 is port 1 is pins 8 to 15

0  toggle digital port reporting (0xD0-0xDF) (MIDI Aftertouch)
1  disable(0) / enable(non-zero)

As of Firmata 2.4.0, upon enabling a digital port, the port value should be reported to the client
application.

If I understand it correctly, if I set pin 1 to pullup and then enable digital reporting for port 0, the firmata server would respond with the value of port 0, where I could extract the value of pin 1.

But what happens if digital reporting is already enabled for port 0, and I additionally set pin 2 to pullup? Will the value of port 0 be reported again, so that I can get the value of pin 2? Is this defined in the protocol?

@pgrawehr
Copy link
Contributor

pgrawehr commented Jan 6, 2022

It really appears that this is not properly defined, and at least in ConfigurableFirmata I can't currently see that changing the reporting parameters forces sending out the current state. I will need to investigate this further.

@pgrawehr
Copy link
Contributor

pgrawehr commented Jan 6, 2022

Let's clarify this: Firmata always sends a DIGITAL_MESSAGE (0x90) as a reply to a REPORT_DIGITAL_PIN (0xD0) message. That means when you enable/disable reporting for a specific pin, you always get the current value of that pin (rather the port) reported back immediately. If you change the pin mode, this does not happen explicitly, but usually implicitly. That means that if changing the mode to pull-up changes the value, you will be notified, otherwise not.

Any pin that is set to output is always reported as 0 in the REPORT_DIGITAL_PIN message. So if that pin now changes to INPUT or INPUT_PULLUP, you would get a message if its input value is 1, or no message if it in fact is 0. So if you cache the last values you received from the REPORT_DIGITAL_PIN message(s) you should always have the correct values in your buffer.

@nandlab
Copy link
Author

nandlab commented Jan 7, 2022

Any pin that is set to output is always reported as 0 in the REPORT_DIGITAL_PIN message.

Do you mean digital I/O message (0x90) here? Where is this behavior defined in the protocol?

So if that pin now changes to INPUT or INPUT_PULLUP, you would get a message if its input value is 1, or no message if it in fact is 0.

I need a callback for the event that the input pin value becomes known. So, with this approach, I would have to set a timer after I set the pin mode to INPUT. When it times out, and no "input value is 1" message has been received, the input pin is assumed to have value 0. Is this correct? Which duration should the timer have?

Is there maybe a way to get informed about the input value explicitly? What happens if reporting is already enabled for a port (with 0xD0) and you enable it again, would it force sending out the port value again? Then you could enable port reporting every time after you set a pin to input, wait for the port value response, where you check the pin value bit.

@pgrawehr
Copy link
Contributor

pgrawehr commented Jan 7, 2022

Any pin that is set to output is always reported as 0 in the REPORT_DIGITAL_PIN message.

Do you mean digital I/O message (0x90) here? Where is this behavior defined in the protocol?

Yes, of course. The namings are a bit confusing here. This doesn't seem to be described explicitly in the protocol, but I checked the implementation and that's what appears to be the behavior.

So if that pin now changes to INPUT or INPUT_PULLUP, you would get a message if its input value is 1, or no message if it in fact is 0.

I need a callback for the event that the input pin value becomes known. So, with this approach, I would have to set a timer after I set the pin mode to INPUT. When it times out, and no "input value is 1" message has been received, the input pin is assumed to have value 0. Is this correct? Which duration should the timer have?

Is there maybe a way to get informed about the input value explicitly? What happens if reporting is already enabled for a port (with 0xD0) and you enable it again, would it force sending out the port value again? Then you could enable port reporting every time after you set a pin to input, wait for the port value response, where you check the pin value bit.

Yes, that works. You can send a enable reporting message to force it to reply with the current state.

@nandlab
Copy link
Author

nandlab commented Jan 7, 2022

Yes, that works. You can send a enable reporting message to force it to reply with the current state.

I think there could be another problem (race condition). Is there a way to distinguish between "digital I/O message" as a response to enabling reporting, and a "digital I/O message" that is sent because of a pin value change? If a pin value change happens exactly when you "set a new input pin and enable port reporting", the arduino would sent a "digital I/O message", where the new input pin value is not set yet.

How do I handle this case?

@pgrawehr
Copy link
Contributor

pgrawehr commented Jan 7, 2022

You are right, this is a potential race condition. I can't think of a good solution for this problem either. You'll probably have to wait a short time whether there's any other update coming.

@nandlab
Copy link
Author

nandlab commented Jan 9, 2022

Perhaps you can define an extra message type for the response of the "enable report" request.

@pgrawehr
Copy link
Contributor

Perhaps you can define an extra message type for the response of the "enable report" request.

I thought about this, but it's difficult, because these are very basic messages and any change there has the risk of breaking other clients. The proposed REPORT_DIGITAL_PIN (#68 (comment)) could be used here, but this needs some further thought.

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

No branches or pull requests

2 participants