Pi4J / pi4j-v2

Pi4J Version 2.0
Apache License 2.0
273 stars 57 forks source link

Data read over I2C becomes out of sync over a slower wireless network #303

Closed IAmNickNack closed 11 months ago

IAmNickNack commented 11 months ago

I have come across a similar issue to #16 when using I2C via the GPIO socket implementation over a slow wireless network. I did not observe the problem when running the same code locally on the Pi via the loopback interface.

I observed that any payload was intermittently ignored when requesting multiple bytes over I2C and would be delivered as preamble prior to the next requested packet.

For example, the request for 25 bytes, made over a slow network returns zero bytes:

c.p.l.pigpio.impl.PiGpioSocketImpl       : [I2C::READ] -> [0]; Register [18]; I2C Block [25 bytes]; offset=0
c.p.l.pigpio.impl.PiGpioSocketBase       : [TX] -> CMD=I2CRI(67); P1=0; P2=18; P3=4; PAYLOAD=[0x19 00 00 00]
c.p.l.pigpio.impl.PiGpioSocketBase       : [RX] <- CMD=I2CRI(67); P1=0; P2=18; P3=25; PAYLOAD=[0x]
c.p.l.pigpio.impl.PiGpioSocketImpl       : [I2C::READ] <- HANDLE=0; SUCCESS=true; RESULT=25

... the subsequent request then returns the payload:

c.p.l.pigpio.impl.PiGpioSocketImpl       : [I2C::WRITE] -> [0]; Register [16]; I2C Block [2 bytes]; offset=0
c.p.l.pigpio.impl.PiGpioSocketBase       : [TX] -> CMD=I2CWI(68); P1=0; P2=16; P3=2; PAYLOAD=[0x00 00]
c.p.l.pigpio.impl.PiGpioSocketBase       : [RX] <- CMD=I2CRI(67); P1=0; P2=18; P3=25; PAYLOAD=[0x00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
c.p.l.pigpio.impl.PiGpioSocketImpl       : [I2C::WRITE] <- HANDLE=0; SUCCESS=true; RESULT=25

On the other hand, the same request made via sockets when using the loopback interface returns the data as expected:

c.p.l.pigpio.impl.PiGpioSocketImpl       : [I2C::READ] -> [0]; Register [18]; I2C Block [25 bytes]; offset=0
c.p.l.pigpio.impl.PiGpioSocketBase       : [TX] -> CMD=I2CRI(67); P1=0; P2=18; P3=4; PAYLOAD=[0x19 00 00 00]
c.p.l.pigpio.impl.PiGpioSocketBase       : [RX] <- CMD=I2CRI(67); P1=0; P2=18; P3=25; PAYLOAD=[0x00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
c.p.l.pigpio.impl.PiGpioSocketImpl       : [I2C::READ] <- HANDLE=0; SUCCESS=true; RESULT=25

The problem appears to stem from PiGpioPacket#decode assuming that all the data for the packet, including the payload, is already available from the socket stream.

I have been able to solve this in a local build of pi4j which, rather than assuming all the bytes currently available, depending on the command (e.g. I2CRI, I2CRD) takes packets p3 value as a hint for the content length to expect.

This works for my I2C use cases. I don't have an SPI or serial project on the go at the moment, so have not been able to validate those cases.

eitch commented 11 months ago

Closing, as PR merged.