pi4j-v2 icon indicating copy to clipboard operation
pi4j-v2 copied to clipboard

Issue: Unable to Reuse GPIO Pin After Removal from Registry

Open moreorover opened this issue 1 year ago • 2 comments

Description When attempting to remove a DigitalInput instance from the Pi4J registry and then reinitialize it, the system fails with an error indicating that the GPIO pin is still busy. It seems that Pi4J is unable to fully release the pin even after calling registry().remove() and shutdown().

Steps to Reproduce The following code reproduces the issue:

DigitalInputConfigBuilder buttonConfig = DigitalInput.newConfigBuilder(pi4j)
        .id("button-" + 22)
        .name("Button on pin " + 22)
        .address(22)
        .pull(PullResistance.PULL_DOWN)
        .debounce(3000L);
DigitalInput button = pi4j.create(buttonConfig);

// Remove the instance from the Pi4J registry and shut it down
pi4j.registry().remove(button.id());
button.shutdown(pi4j);

// Attempt to reinitialize the same pin
DigitalInputConfigBuilder buttonConfig2 = DigitalInput.newConfigBuilder(pi4j)
        .id("button-" + 22)
        .name("Button on pin " + 22)
        .address(22)
        .pull(PullResistance.PULL_DOWN)
        .debounce(3000L);
DigitalInput button2 = pi4j.create(buttonConfig2); // Error occurs here

Observed Behavior The system throws the following exception when trying to reinitialize the pin:

Caused by: java.lang.IllegalStateException: Failed to initialize IO button-22 at com.pi4j.registry.impl.DefaultRuntimeRegistry.add(DefaultRuntimeRegistry.java:102) ~[pi4j-core-2.7.0.jar!/:na] at com.pi4j.registry.impl.DefaultRegistry.add(DefaultRegistry.java:97) ~[pi4j-core-2.7.0.jar!/:na] at com.pi4j.plugin.gpiod.provider.gpio.digital.GpioDDigitalInputProviderImpl.create(GpioDDigitalInputProviderImpl.java:33) ~[pi4j-plugin-gpiod-2.7.0.jar!/:na] ... Caused by: com.pi4j.library.gpiod.internal.GpioDException: c_gpiod_line_request_both_edges_events_flags failed: -1 (Device or resource busy) at com.pi4j.library.gpiod.internal.GpioD.lineRequestBothEdgeEventsFlags(GpioD.java:221) ~[pi4j-library-gpiod-2.7.0.jar!/:na]

Expected Behavior After calling registry().remove() and shutdown(), the GPIO pin should be fully released and available for reuse. The DigitalInput instance should be re-creatable without encountering any "Device or resource busy" errors.

Environment

  • Pi4J Version: 2.7.0
  • Java Version: 17
  • OS: Raspberry Pi OS on Raspberry Pi 4 Model B Rev 1.4
  • libgpiod Version: 1.6.3

Additional Notes It appears that the underlying GPIO line remains locked at the OS level even after calling shutdown() and removing the pin from the Pi4J registry. This may require additional handling in Pi4J to ensure proper release of GPIO resources.

moreorover avatar Jan 24 '25 19:01 moreorover

The following code seems to release the GPIO pin at the OS level, allowing me to reassign the pin successfully:

DigitalInputConfigBuilder buttonConfig = DigitalInput.newConfigBuilder(pi4j)
        .id("button-" + 22)
        .name("Button on pin " + 22)
        .address(22)
        .pull(PullResistance.PULL_DOWN)
        .debounce(3000L);
DigitalInput button = pi4j.create(buttonConfig);

// Remove the instance from the Pi4J registry and shut it down
pi4j.registry().remove(button.id());
button.shutdown(pi4j);
+pi4j.shutdown();
+pi4j = Pi4J.newAutoContext();
// Attempt to reinitialize the same pin
DigitalInputConfigBuilder buttonConfig2 = DigitalInput.newConfigBuilder(pi4j)
        .id("button-" + 22)
        .name("Button on pin " + 22)
        .address(22)
        .pull(PullResistance.PULL_DOWN)
        .debounce(3000L);
DigitalInput button2 = pi4j.create(buttonConfig2); // Error occurs here

However, I was wondering if button.shutdown(pi4j) alone should be sufficient to release the pin. My understanding is that shutdown() should properly clean up resources and release the GPIO line, but without calling pi4j.shutdown() and recreating the context, the pin remains busy, and reinitialization fails. Is this the expected behavior, or could it be a bug in how shutdown() works for individual GPIO resources?

moreorover avatar Jan 25 '25 12:01 moreorover

I had created a test to reproduce this in https://github.com/Pi4J/pi4j/pull/438 where I was told that the correct shutdown call would be

pi4j.shutdown(button.getId());

However, for me the problem persists in V3.0.1 -- even after fixing the call.

Moreover, when debugging, I don't even get there because the listener shutdown timeout of 5s is apparently too short.

stefanhaustein avatar May 03 '25 17:05 stefanhaustein

I think this is fixed with #487

eitch avatar Sep 08 '25 08:09 eitch