kurbatov / firmata4j

Firmata client written in Java.
MIT License
87 stars 45 forks source link

How to use I2C for read and write with and without registers? #17

Closed mattjlewis closed 7 years ago

mattjlewis commented 7 years ago

I'm trying to integrate your library into my platform agnostic Device I/O library (diozero). I have basic digital in / out as well as PWM working, however, I'm struggling with I2C support. I cannot see how to implement I2C read / write with and without slave I2C addresses. Code is in GitHub.

kurbatov commented 7 years ago

You can do that using tell(...), ask(...) and subscribe(...) methods of I2CDevice.

There is an ideological mismatch between diozero and firmata4j. I assume that diozero tends to provide synchronous blocking API. It is compatible with asynchronous non-blocking API of firmata4j only when you write a buffer to I2C device. When you're trying to read, firmata4j does not block until data from the device is available but gives control back right away. firmata4j requires to subscribe a listener which receives and processes the data.

One way you can turn asynchronous call to synchronous is creating a future (java.util.concurrent.Future) and subscribing anonymous listener that completes the future. Then the method read just returns when future is done.

Another way I see is subscribing I2CListener that collects received data to internal buffer of diozero's FirmataI2CDevice. Then I2CDevice.startReceivingUpdates(...) should be invoked in order to receive data continously. This way when you try to read the method returns data from the buffer.

I guess the best approach depends on a particular device you work with.

You can see example of working with I2C device using firmata4j API in OLED display driver that firmata4j provides.

mattjlewis commented 7 years ago

Thanks for the swift response. I'm still a little confused unfortunately - the SSD1306 example only does writes unfortunately. What if I wanted to read a specific register - how would I achieve that with firmata4j? the code in the ask method appears to increment the register address:

        byte reg = (byte) register.getAndIncrement();
        register.compareAndSet(256, 1);
kurbatov commented 7 years ago

I'm afraid there is no way right now. Reading from specific register is not implemented.

I would appreciate if you add that feature into I2CDevice interface and make a pull request.

mattjlewis commented 7 years ago

Ok, I've committed changes for register-specific I2C reads https://github.com/mattjlewis/firmata4jI've done some basic tests using a BME280 humidity / temperature sensor which appeared to work as expected.My diozero wrapper code that uses firmata4j: https://github.com/mattjlewis/diozero/tree/master/diozero-provider-firmata Do you want to double-check my changes?

Nice library by the way, worked perfectly for PWM, digital in/out as well as analog in. Regards,Matt

On Wednesday, 22 February 2017, 17:25, Oleg Kurbatov <notifications@github.com> wrote:

I'm afraid there is no way right now. Reading from specific register is not implemented.I would appreciate if you add that feature into I2CDevice interface and make a pull request.— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

kurbatov commented 7 years ago

Hi Matthew,

I have read through the commit you made and it looks fine for me. Could you please make a pull request. I'll revise it one more time locally with projects of mine, clean up some commented out code and release to the maven central during this week.

Thank you, Oleg

kurbatov commented 7 years ago

The changes from the pull request are in 2.3.5 release.