This exception doesn't seem right to me:
Is this a mistake, or is it my understanding that needs correction?
I鈥檓 not sure the exact issue you鈥檝e encountered. Could you provide an example? Basically, this code checks and if the pin is an output, it throws to state you鈥檙e reading a output pin. You can only read input pins.
You can only read input pins.
Yes, that's the issue. Why can you only read input pins? I've never used a microcontroller or any other embedded device where reading an output pin was not permitted. What's the justification for it?
To illustrate a use case, one may want to read the output pin when the program first starts in order to update their UI with the output's last state. Initializing the pin to a default value may violate the software's requirements.
I'm not sure that all drivers would be able to support this. For example, the RaspberryPi driver operates with registers in the memory directly, and there are different bits in memory that are used for the value depending if you are in Input vs Output mode, and I would really doubt that the Input bit will be updated when the pin is set to output and the value is changed.
there are different bits in memory that are used for the value depending if you are in Input vs Output mode, and I would really doubt that the Input bit will be updated when the pin is set to output and the value is changed.
I would expect the driver to return the value of the Output bit if it is in Output mode.
That is not how the Output bits work on the RPi driver unfortunately. There are two registers that are used to control an output pin's value in the RPi:
The way this works internally, is that if you want to set the pin value to low then you flip a bit of the GPCLR register, and when you want to set it high then you flip a bit on the GPSET register, and by modifying one register, the other one won't be modified. What this means, is that only internally does the raspberry pi knows which was the register that was last modified in that bit, which would tell it whether the value is high or low. There is now way that by reading those registers one would be able to tell whether the value is high or low.
Doesn't GPLEV give you the state of the output pin?
Only when it is set to Input, it won'd do it the pin is set to Output
Weird! So be it.
I just tested with pigpio and it works fine. Even if I set the state using C# and close the program, I can read the state of the output pin (that was set in the C# program) in C using the pigpio library.
Re-opening because I think it would be valuable to see how pigpio achieves this and implement something similar.
@buyaa-n PTAL
Seems sometimes its really needed to read a value from output pin, and according to Wikipedia
GPIO capabilities may include:[2]
- GPIO pins can be configured to be input or output[4]
- GPIO pins can be enabled/disabled
- Input values are readable (typically high or low)
- Output values are writable/readable
And i have read output pin using SysFs, Libgpiod and Raspberry driver, all worked correctly (i. e. after writing high i read hig, after writing low read low). So i think we should enable reading output pin for controller level and if any driver specific pin not supporting that operation throw the error on driver level.
Please let me know if you have any other idea cc @joshfree @joperezr @krwq
I think in many cases reading an output pin may be by accident and therefore a bug.
I personally haven't had any case where I'd need that but if I see specific scenario where this is useful I'm open to change this behavior
If we decide to change this behavior we should investigate if reading not open pins should also be considered a bug because developer might want to check if the pin is input or output.
Starting to look at the I2C protocol I believe without fixing this implementing software implementation might be hard as it seems to be using that fact for communication - i.e. clock stretching where master sets clock to 1 but slave can pull it low until it is ready to write so master despite controlling the clock should check if value is set to what it is supposed to be. Given that I believe we should fix this and make sure we don't try to cache the value.
I am pretty sure we need to enable reading output pin. @joshfree suggested to add ReadWrite mode instead of making output mode readable, maybe we should name that mode InputOutput so that it follow .Net IO file reading design (Read, Write, ReadWrite mode). I like that idea, if user need to read from output pin they could choose InputOutput (or OutputInput) mode instead of only Output mode. What you think about that
I think it would be nice to have the ability to read the value of an output. I've had a few cases using I/O Expanders where I have to read the value from device (using I2C or SPI) or store the last value written in order to not affect other respective pin bits when writing.
maybe we should name that mode InputOutput
I haven't thought in detail, but this might get a little complex. What happens if/when we add other types of outputs (#135)? Would we have to include InputOutputPullUp, InputPullDownOutput, InputOutputOpenDrain, etc.?
Would we have to include InputOutputPullUp, InputPullDownOutput, InputOutputOpenDrain, etc.
The point of this change is to make Output pin readable, no need make any change to Input pins. (InputPullDown, InputPullUp)
But from the issue #135 i see there could be 4 more output modes (OutputOpenDrain, OtputOpenDrainPullUp, OutputOpenCollector, OutputOpenCollectorPullDown). Not sure if they also need to be readable, if they are then yes its become more complicated, might be better just make Output pins readable instead of new InputOutput mode, maybe we need discuss it in API review
I think the PinMode can be flags - perhaps something along these lines:
that should allow you to compose whatever mode you want (we would need to figure out better names for enum flags and decide if we want all combinations or only basic options which user composes into effective option)
At first i liked idea of using flags, its good to use flags if we use all combinations but in this case not all flag could produce valid combination (like no combination Output+Pull Up). We just need to make output pins readable, not opposite (input pins shouldn't be writable).
We might just make all output modes readable (for now we have only output mode OutputOpenDrain, OtputOpenDrainPullUp, OutputOpenCollector, OutputOpenCollectorPullDown might added later)
Flagging as up-for-grabs so that people can submit PRs for this.
I wonder that why "OpenPin" resets PinMode and PinPower,it seems that the API do too much things which made it difficult to develop.By the way, some case need to get PinPower when the program is going to start up.It's a good way to refer to "WiringPi" because many IOT programs base on it.
We did that because in Linux, we have different drivers that will be used depending on which hardware are you running on, and some would do this behavior as default, so we decided that for consistency, we should have all drivers do the same, so the ones that didn't by default were changed so that the Pinmode and value gets reset.