Report initial input pin value
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?
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.
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.
Any pin that is set to output is always reported as 0 in the
REPORT_DIGITAL_PINmessage.
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.
Any pin that is set to output is always reported as 0 in the
REPORT_DIGITAL_PINmessage.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.
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?
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.
Perhaps you can define an extra message type for the response of the "enable report" request.
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.