MrYsLab / pymata-aio

This is the second generation PyMata client.
https://github.com/MrYsLab/pymata-aio/wiki
GNU Affero General Public License v3.0
155 stars 51 forks source link

Port manipulation with digital_write unclear #46

Closed dmyersturnbull closed 7 years ago

dmyersturnbull commented 7 years ago

I'm trying to write to multiple output pins simultaneously by port manipulation. It seems that pymata_core.digital_write can do this, but I'm not sure how to use it. The documentation says "Set the specified pin to the specified value" even though it's clear from digital_pin_write that it can write multiple pins. I'd be happy to commit a documentation change if the developers can tell me how to use this :)

MrYsLab commented 7 years ago

@dmyersturnbull The reason for the port manipulation in pymata is that the Arduino Firmata code requires the client to specify the port. The digital write code hides the concepts of ports from the user so they can simply use pin numbers as they would for standard Arduino programming.

Are discrete pin writes too slow for your application?

I suppose a new method could be created to allow a user to specify a port number and a pin mask. Is this what you are looking for? I am assuming that you understand that if you wish to simultaneously write to pins not on the same port, this is not possible.

dmyersturnbull commented 7 years ago

@MrYsLab Thanks for the quick reply.

Are discrete pin writes too slow for your application?

Yes. More specifically, need want to ensure that two events happen simultaneously.

I tried to write functions for the port configuration specific to my board turn_digital_pins_on and turn_digital_pins_off that would each take a list of pin numbers, and a function set_digital_pins that would accept a bitmask or list of values for each pin.

I struggled to write these after seeing the logic in digital_write — for example, what is the DIGITAL_MESSAGE constant, and why is DIGITAL_OUTPUT_PORT_PINS set to 16 0s?

I'd also like to be able to set a callback that would get the value of multiple digital input pins simultaneously.

MrYsLab commented 7 years ago

@dmyersturnbull Welcome to my world ;-).

The way firmata works, is that there are standard commands or messages. In private_constants.py, the digital message is defined. This is dictated by the firmata spec.

# messages from firmata
DIGITAL_MESSAGE = 0x90  # send or receive data for a digital pin

The same DIGITAL_MESSAGE is used both by pymata to tell the Arduino to set pin values, and when a digital pin value changes, the Arduino sends back a DIGITAL_MESSAGE as well. Now to be even more confusing, the port number of the pin that is effected (either setting or reporting) is added to the DIGITAL_MESSAGE command.

DIGITAL_OUTPUT_PORT_PINS is a 16 bit value because that is what Firmata is expecting in the message. It is kind of odd, since the Firmata code proceeds to cast it as a byte. If you are setting a pin to high, its associated bit should be a 1 and if you are clearing the pin, then it is set to a zero. All of the existing pins for a port must be copied over with their current states, since Firmata loop through the value and set each pin to that state. So if you want to manage pins via port, you would have to retain the current state information, manipulate the pins you wish to change and then send the updated value back to the Arduino.

For digital inputs, I believe that if you set callbacks for each pin when you configure them (you should be able to associate all the pins with a single callback function), I think you will be notified for each pin change within the port as pymata goes through the loop processing the port data. This is the digital_message method on line 1407 of pymata_core.py. But here you are not getting a single callback per port, but a callback per pin.

Please let me know if any of this is unclear or if you have any other questions.

MrYsLab commented 7 years ago

@dmyersturnbull I am going to close this issue. If it needs to be reopened, please let me know and I will do so.