protocol icon indicating copy to clipboard operation
protocol copied to clipboard

Report initial input pin value

Open nandlab opened this issue 3 years ago • 8 comments

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?

nandlab avatar Jan 03 '22 22:01 nandlab

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 avatar Jan 06 '22 07:01 pgrawehr

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.

pgrawehr avatar Jan 06 '22 20:01 pgrawehr

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.

nandlab avatar Jan 07 '22 12:01 nandlab

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.

pgrawehr avatar Jan 07 '22 12:01 pgrawehr

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?

nandlab avatar Jan 07 '22 12:01 nandlab

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.

pgrawehr avatar Jan 07 '22 13:01 pgrawehr

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

nandlab avatar Jan 09 '22 18:01 nandlab

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 (https://github.com/firmata/protocol/issues/68#issuecomment-257105540) could be used here, but this needs some further thought.

pgrawehr avatar Jan 10 '22 07:01 pgrawehr