mattjlewis / diozero

Java Device I/O library that is portable across Single Board Computers and microcontrollers. Tested with Raspberry Pi, Odroid C2, BeagleBone Black, Next Thing CHIP, Asus Tinker Board and Arduinos / Pico. Supports GPIO, I2C, SPI as well as Serial communication. Also known to work with Udoo Quad.
https://www.diozero.com
MIT License
263 stars 59 forks source link

IllegalStateException: Duplicate key 0 #216

Closed TGlev closed 2 weeks ago

TGlev commented 3 weeks ago

Hi,

I am trying to open a I2C device and use a Gpio output. I got this working on our development boards with a CM4 running latest raspbian os. However, we have added a Zymkey4 to our board to encrypt our filesystem. This causes the code for the I2C and GPIO to crash for reasons that are unknown to me.

Please see following log entries:

2024-10-07 12:12:44.895 | com.diozero.sbc.UnknownBoardInfo         | Line 49   | WARN  | Failed to resolve board info for hardware 'Raspberry Pi Compute Module 4 Rev 1.1' and revision 'b03141'. Local O/S: Linux-aarch64

2024-10-07 12:12:44.901 | com.diozero.util.LibraryLoader           | Line 84   | DEBUG | Looking for lib '/lib/linux-aarch64/libdiozero-system-utils.so' on classpath
2024-10-07 12:12:44.936 | com.diozero.util.LibraryLoader           | Line 93   | DEBUG | Loaded library 'diozero-system-utils' from classpath
2024-10-07 12:12:44.994 | com.diozero.sbc.DeviceFactoryHelper      | Line 84   | DEBUG | Using native device factory class DefaultDeviceFactory
2024-10-07 12:12:45.004 | al.provider.builtin.DefaultDeviceFactory | Line 102  | DEBUG | Using chardev GPIO implementation
2024-10-07 12:12:45.044 | <>       | Line 20   | ERROR | java.lang.IllegalStateException: Duplicate key 0 (attempted merging values com.diozero.internal.provider.builtin.gpio.GpioChip@5ccddd20 and com.diozero.internal.provider.builtin.gpio.GpioChip@1ed1993a)
    at java.base/java.util.stream.Collectors.duplicateKeyException(Collectors.java:135)
    at java.base/java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$1(Collectors.java:182)
    at java.base/java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
    at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
    at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1939)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
    at com.diozero.internal.provider.builtin.gpio.GpioChip.openAllChips(GpioChip.java:67)
    at com.diozero.internal.provider.builtin.DefaultDeviceFactory.start(DefaultDeviceFactory.java:109)
    at com.diozero.sbc.DeviceFactoryHelper.initialise(DeviceFactoryHelper.java:88)
    at com.diozero.sbc.DeviceFactoryHelper.getNativeDeviceFactory(DeviceFactoryHelper.java:110)
    at com.diozero.api.I2CDevice$Builder.build(I2CDevice.java:142))
2024-10-07 12:12:45.613 | <> | Line 34   | ERROR | java.lang.NullPointerException: Cannot invoke "java.util.Map.get(Object)" because "this.chips" is null
    at com.diozero.internal.provider.builtin.DefaultDeviceFactory.createDigitalOutputDevice(DefaultDeviceFactory.java:344)
    at com.diozero.internal.spi.GpioDeviceFactoryInterface.provisionDigitalOutputDevice(GpioDeviceFactoryInterface.java:84)
    at com.diozero.api.DigitalOutputDevice.<init>(DigitalOutputDevice.java:158)
    at com.diozero.api.DigitalOutputDevice.<init>(DigitalOutputDevice.java:142)
    at com.diozero.api.DigitalOutputDevice.<init>(DigitalOutputDevice.java:129)
    at com.diozero.api.DigitalOutputDevice.<init>(DigitalOutputDevice.java:118)

The I2C and GPIO are accessible normally through their CLI interfaces. Works just fine. We did not have these issues before adding the Zymkey to the board, so we suspect the issue is in the way that device uses the I2C and GPIO, however we don't know how to debug these issues. I have tried with the latest 1.4.0 maven version and also with a version I built from the latest code available on github. Both give the same result.

I am unsure what kind of information or detail you need more, please let me know so I can provide you with the correct information.

TGlev commented 3 weeks ago

Setting this property: System.setProperty("diozero.gpio.chardev", "false");

Seems to fix the I2C issue, but not the GPIO issue. However, this is not preferred as chardev is no longer the preferred method of using GPIO in Linux. :)

mattjlewis commented 3 weeks ago

I believe this is the same as #215 and 1.4.1 will address this issue.

TGlev commented 3 weeks ago

I have compiled the latest commit in the main branch and ran with that library. My maven build told me it was 1.4.1. Same issue.

mattjlewis commented 3 weeks ago

Thank you for ruling this out. Can you please share the output of the command gpioinfo please.

TGlev commented 3 weeks ago
gpiochip0 - 58 lines:
        line   0:     "ID_SDA"       unused   input  active-high
        line   1:     "ID_SCL"       unused   input  active-high
        line   2:      "GPIO2"       unused   input  active-high
        line   3:      "GPIO3"       unused   input  active-high
        line   4:      "GPIO4"      "sysfs"   input  active-high [used]
        line   5:      "GPIO5"       unused   input  active-high
        line   6:      "GPIO6"       unused  output  active-high
        line   7:      "GPIO7"   "spi0 CS1"  output   active-low [used]
        line   8:      "GPIO8"   "spi0 CS0"  output   active-low [used]
        line   9:      "GPIO9"       unused   input  active-high
        line  10:     "GPIO10"       unused   input  active-high
        line  11:     "GPIO11"       unused   input  active-high
        line  12:     "GPIO12"       unused   input  active-high
        line  13:     "GPIO13"       unused   input  active-high
        line  14:     "GPIO14"       unused   input  active-high
        line  15:     "GPIO15"       unused   input  active-high
        line  16:     "GPIO16"       unused   input  active-high
        line  17:     "GPIO17"       unused   input  active-high
        line  18:     "GPIO18"   "spi1 CS0"  output   active-low [used]
        line  19:     "GPIO19"       unused   input  active-high
        line  20:     "GPIO20"       unused   input  active-high
        line  21:     "GPIO21"       unused   input  active-high
        line  22:     "GPIO22"  "interrupt"   input  active-high [used]
        line  23:     "GPIO23"       unused   input  active-high
        line  24:     "GPIO24"  "interrupt"   input  active-high [used]
        line  25:     "GPIO25"       unused  output  active-high
        line  26:     "GPIO26"       unused   input  active-high
        line  27:     "GPIO27"       unused   input  active-high
        line  28: "RGMII_MDIO"       unused   input  active-high
        line  29:  "RGMIO_MDC"       unused   input  active-high
        line  30:       "CTS0"       unused   input  active-high
        line  31:       "RTS0"       unused   input  active-high
        line  32:       "TXD0"       unused   input  active-high
        line  33:       "RXD0"       unused   input  active-high
        line  34:    "SD1_CLK"       unused   input  active-high
        line  35:    "SD1_CMD"       unused   input  active-high
        line  36:  "SD1_DATA0"       unused   input  active-high
        line  37:  "SD1_DATA1"       unused   input  active-high
        line  38:  "SD1_DATA2"       unused   input  active-high
        line  39:  "SD1_DATA3"       unused   input  active-high
        line  40:  "PWM0_MISO"       unused   input  active-high
        line  41:  "PWM1_MOSI"       unused   input  active-high
        line  42: "STATUS_LED_G_CLK" "ACT" output active-high [used]
        line  43: "SPIFLASH_CE_N" unused input active-high
        line  44:       "SDA0"       unused   input  active-high
        line  45:       "SCL0"       unused   input  active-high
        line  46: "RGMII_RXCLK" unused input active-high
        line  47: "RGMII_RXCTL" unused input active-high
        line  48: "RGMII_RXD0"       unused   input  active-high
        line  49: "RGMII_RXD1"       unused   input  active-high
        line  50: "RGMII_RXD2"       unused   input  active-high
        line  51: "RGMII_RXD3"       unused   input  active-high
        line  52: "RGMII_TXCLK" unused input active-high
        line  53: "RGMII_TXCTL" unused input active-high
        line  54: "RGMII_TXD0"       unused   input  active-high
        line  55: "RGMII_TXD1"       unused   input  active-high
        line  56: "RGMII_TXD2"       unused   input  active-high
        line  57: "RGMII_TXD3"       unused   input  active-high
gpiochip1 - 8 lines:
        line   0:      "BT_ON"       unused  output  active-high
        line   1:      "WL_ON"       unused  output  active-high
        line   2: "PWR_LED_OFF" "PWR" output active-low [used]
        line   3:       "ANT1"       "ant1"  output  active-high [used]
        line   4: "VDD_SD_IO_SEL" "vdd-sd-io" output active-high [used]
        line   5:   "CAM_GPIO" "cam1_regulator" output active-high [used]
        line   6:  "SD_PWR_ON" "sd_vcc_reg"  output  active-high [used]
        line   7:       "ANT2"       "ant2"  output  active-high [used]
gpiochip2 - 8 lines:
        line   0:      unnamed       unused   input  active-high
        line   1:      unnamed       unused   input  active-high
        line   2:      unnamed       unused   input  active-high
        line   3:      unnamed       unused   input  active-high
        line   4:      unnamed       unused   input  active-high
        line   5:      unnamed       unused   input  active-high
        line   6:      unnamed       unused   input  active-high
        line   7:      unnamed       unused   input  active-high
gpiochip0 - 58 lines:
        line   0:     "ID_SDA"       unused   input  active-high
        line   1:     "ID_SCL"       unused   input  active-high
        line   2:      "GPIO2"       unused   input  active-high
        line   3:      "GPIO3"       unused   input  active-high
        line   4:      "GPIO4"      "sysfs"   input  active-high [used]
        line   5:      "GPIO5"       unused   input  active-high
        line   6:      "GPIO6"       unused  output  active-high
        line   7:      "GPIO7"   "spi0 CS1"  output   active-low [used]
        line   8:      "GPIO8"   "spi0 CS0"  output   active-low [used]
        line   9:      "GPIO9"       unused   input  active-high
        line  10:     "GPIO10"       unused   input  active-high
        line  11:     "GPIO11"       unused   input  active-high
        line  12:     "GPIO12"       unused   input  active-high
        line  13:     "GPIO13"       unused   input  active-high
        line  14:     "GPIO14"       unused   input  active-high
        line  15:     "GPIO15"       unused   input  active-high
        line  16:     "GPIO16"       unused   input  active-high
        line  17:     "GPIO17"       unused   input  active-high
        line  18:     "GPIO18"   "spi1 CS0"  output   active-low [used]
        line  19:     "GPIO19"       unused   input  active-high
        line  20:     "GPIO20"       unused   input  active-high
        line  21:     "GPIO21"       unused   input  active-high
        line  22:     "GPIO22"  "interrupt"   input  active-high [used]
        line  23:     "GPIO23"       unused   input  active-high
        line  24:     "GPIO24"  "interrupt"   input  active-high [used]
        line  25:     "GPIO25"       unused  output  active-high
        line  26:     "GPIO26"       unused   input  active-high
        line  27:     "GPIO27"       unused   input  active-high
        line  28: "RGMII_MDIO"       unused   input  active-high
        line  29:  "RGMIO_MDC"       unused   input  active-high
        line  30:       "CTS0"       unused   input  active-high
        line  31:       "RTS0"       unused   input  active-high
        line  32:       "TXD0"       unused   input  active-high
        line  33:       "RXD0"       unused   input  active-high
        line  34:    "SD1_CLK"       unused   input  active-high
        line  35:    "SD1_CMD"       unused   input  active-high
        line  36:  "SD1_DATA0"       unused   input  active-high
        line  37:  "SD1_DATA1"       unused   input  active-high
        line  38:  "SD1_DATA2"       unused   input  active-high
        line  39:  "SD1_DATA3"       unused   input  active-high
        line  40:  "PWM0_MISO"       unused   input  active-high
        line  41:  "PWM1_MOSI"       unused   input  active-high
        line  42: "STATUS_LED_G_CLK" "ACT" output active-high [used]
        line  43: "SPIFLASH_CE_N" unused input active-high
        line  44:       "SDA0"       unused   input  active-high
        line  45:       "SCL0"       unused   input  active-high
        line  46: "RGMII_RXCLK" unused input active-high
        line  47: "RGMII_RXCTL" unused input active-high
        line  48: "RGMII_RXD0"       unused   input  active-high
        line  49: "RGMII_RXD1"       unused   input  active-high
        line  50: "RGMII_RXD2"       unused   input  active-high
        line  51: "RGMII_RXD3"       unused   input  active-high
        line  52: "RGMII_TXCLK" unused input active-high
        line  53: "RGMII_TXCTL" unused input active-high
        line  54: "RGMII_TXD0"       unused   input  active-high
        line  55: "RGMII_TXD1"       unused   input  active-high
        line  56: "RGMII_TXD2"       unused   input  active-high
        line  57: "RGMII_TXD3"       unused   input  active-high
mattjlewis commented 3 weeks ago

Strange that gpiochip0 appears twice. Can you do ls -il /dev/gpiochip* please

TGlev commented 3 weeks ago
 87 crw-rw---- 1 root gpio 254, 0 Oct  3 11:21 /dev/gpiochip0
 88 crw-rw---- 1 root gpio 254, 1 Oct  3 11:21 /dev/gpiochip1
558 crw-rw---- 1 root gpio 254, 2 Oct  3 11:21 /dev/gpiochip2
545 lrwxrwxrwx 1 root root      9 Oct  3 11:21 /dev/gpiochip4 -> gpiochip0
mattjlewis commented 3 weeks ago

Very strange 1.4.1 included a fix to filter our symbolic links. Are you able to compile and run this please:

public class ListGpioChips {
    public static void main(String[] args) {
        try {
            Files.list(Paths.get("/dev"))
                    .filter(p -> p.getFileName().toString().startsWith("gpiochip")) //
                    .forEach(ListGpioChips::printInfo);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private static void printInfo(Path p) {
        System.out.format("%s is symbolic link: %b, regular (no follow): %b, regular: %b\n", p,
                Boolean.valueOf(Files.isSymbolicLink(p)),
                Boolean.valueOf(Files.isRegularFile(p, LinkOption.NOFOLLOW_LINKS)),
                Boolean.valueOf(Files.isRegularFile(p)));
    }
}
TGlev commented 3 weeks ago
/dev/gpiochip0 is symbolic link: false, regular (no follow): false, regular: false
/dev/gpiochip1 is symbolic link: false, regular (no follow): false, regular: false
/dev/gpiochip4 is symbolic link: true, regular (no follow): false, regular: false
/dev/gpiochip2 is symbolic link: false, regular (no follow): false, regular: false
TGlev commented 3 weeks ago

I compiled the library from sources using maven and then imported this library manually into my IntelliJ project and removed the maven version of Diozero. Reading this output, combined with what you are explaining, I am starting to feel that I was not actually running 1.4.1 and was secretly running 1.4.0 :)

I'll see if I can find some time to re-run with an actual 1.4.1.

mattjlewis commented 3 weeks ago

No worries - I need to get 1.4.1 out ASAP anyway...

mattjlewis commented 2 weeks ago

Pushed 1.4.1 just now