Skip to content

WIP/parallel backed digital devices - #833

Draft
IAmNickNack wants to merge 8 commits into
Pi4J:mainfrom
IAmNickNack:wip/parallel-backed-digital-devices
Draft

IAmNickNack wants to merge 8 commits into
Pi4J:mainfrom
IAmNickNack:wip/parallel-backed-digital-devices

Conversation

@IAmNickNack

Copy link
Copy Markdown
Contributor

Sharing this as only draft PR for demonstration purposes. I'm not (yet) proposing that we lose FFMDigital* devices. Only sharing the idea to maybe provoke discussion

This PR provides ParallelPort wrappers for Digital* devices, potentially negating the need for distinct digital implementations.

Currently the ParallelPort does not implement software debounce. However, when using this context and the change proposed in #832, DigitalInputDebounceTimeTestCase and DigitalInputDebounceCountTestCase appear to complete successfully with no software debounce.

It would be very helpful if I could get a second opinion on this. Maybe somebody else can pull this branch and also run the smoke tests.

@taartspi

Copy link
Copy Markdown
Contributor

I saw the build tests fail same as your PR. Built with -DskipTests
Test results with NEWAUTOCONTEXT:

  • Total Tests: 13
  • Passed: 8
  • Failed: 5
  1. Test: Event on Fifth Digital Input
    19274 [main] INFO com.pi4j.test.Main - FAILED
    19274 [main] INFO com.pi4j.test.Main - Test failure: IO instance with address 26 already exists in the Pi4J runtime context; unable to create a new instance using this reserved id.
  2. Test: Digital Debounce Count
    19275 [main] INFO com.pi4j.test.Main - FAILED
    19275 [main] INFO com.pi4j.test.Main - Test failure: IO instance with address 22 already exists in the Pi4J runtime context; unable to create a new instance using this reserved id.
  3. Test: Multiple Digital Listeners
    19275 [main] INFO com.pi4j.test.Main - FAILED
    19275 [main] INFO com.pi4j.test.Main - Test failure: IO instance with address 22 already exists in the Pi4J runtime context; unable to create a new instance using this reserved id.
  4. Test: Parallel Port
    19275 [main] INFO com.pi4j.test.Main - FAILED
    19275 [main] INFO com.pi4j.test.Main - Write-read test failure: Failed to initialize IO parallel-in
  5. Test: Parallel Port Events
    19275 [main] INFO com.pi4j.test.Main - FAILED
    19275 [main] INFO com.pi4j.test.Main - Test failure: Failed to initialize IO parallel-in

@IAmNickNack

Copy link
Copy Markdown
Contributor Author

Thanks @taartspi

This looks like a context close problem. I'll get this resolved

@IAmNickNack
IAmNickNack force-pushed the wip/parallel-backed-digital-devices branch from 40ffc11 to b064128 Compare October 29, 2026 17:19
@IAmNickNack

IAmNickNack commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor Author

I've updated the shutdown logic, so the tests should now only fail because of debounce tolerance.

I see the eventing now working. I do get intermittent failures with the reported time being 10 or 15 ms outside tolerance. "Generally" the tests appear to work for me with (no software debounce).

I've resolved some of the test errors, but not necessarily made failing tests pass. I think the errors are a result of an expectation that device implementations will maintain an internal representation of the state. If this is the case, I'd question these cases being valid unit tests for FFM. This would be something more appropriate to expect of the mock.

Obviously we'd resolve these issues if this was a PR I expect to be merged.

@taartspi would you mind re-retesting with the latest commit?

@IAmNickNack

Copy link
Copy Markdown
Contributor Author

I do get intermittent failures with the reported time being 10 or 15 ms outside tolerance.

I think this could be to be expected. I'm not sure hardware/kernel debounce is really intended for debounce of 1,000,000 microseconds. I imagine that there could be skew which is proportional to the duration. A lower (more realistic) debounce would likely not be so obvious/noticeable.

@taartspi

Copy link
Copy Markdown
Contributor

Oct 29 PR 833
.
20269 [main] INFO com.pi4j.test.Main - ==============================================================
20269 [main] INFO com.pi4j.test.Main - Test: Multiple Digital Listeners
20269 [main] INFO com.pi4j.test.Main - FAILED
20269 [main] INFO com.pi4j.test.Main - Test failure: Failed to initialize IO DIN-27
20269 [main] INFO com.pi4j.test.Main - ==============================================================
20

Running these three tests together, 1 out of 5 runs the MultipleListener test fails. Whether the debounceTime test passed or failed does not change this result. Running MultipleListener alone two dozen times no failure.
I see the exception Offsets are in use: [27], is the previous tests use not completely released in the kernel ?

       DigitalInputDebounceTimeTestCase.run(providerContext),
        DigitalInputDebounceCountTestCase.run(providerContext),
        DigitalInputMultipleListenersTestCase.run(providerContext)/*,

PS The debounceTime test tolerance is another discussion. It is intended only for HW and real providers (FFM) and not mocks. We can talk later on what pi4j changed and how the test should change.

906 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - requesting GPIO line (DOUT-22)...
906 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - opening device file.
923 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - getting line info.
989 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - GPIO line info: LineInfo{name=(GPIO22)[71, 80, 73, 79, 50, 50], consumer=()[], offset=22, numAttrs=0, flags=8, attrs=[]}
1018 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - GPIO line configured: LineRequest{offsets=[22], consumer=(pi4j.DOUT-22)[112, 105, 52, 106, 46, 68, 79, 85, 84, 45, 50, 50], config=LineConfig{flags=8, numAttrs=0, attrs=[]}, numLines=1, eventBufferSize=0, fd=17}
1029 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - writing GPIO offset 0.
1129 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - reading GPIO offset.
1130 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - GPIO offset state is 0.
1144 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - requesting GPIO line (DIN-27)...
1144 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - opening device file.
1144 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - getting line info.
1145 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - GPIO line info: LineInfo{name=(GPIO27)[71, 80, 73, 79, 50, 55], consumer=()[], offset=27, numAttrs=0, flags=4, attrs=[]}
1151 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - GPIO line configured: LineRequest{offsets=[27], consumer=(pi4j.DIN-27)[112, 105, 52, 106, 46, 68, 73, 78, 45, 50, 55], config=LineConfig{flags=564, numAttrs=1, attrs=[LineConfigAttribute{attr=LineAttribute{id=3, flags=0, values=0, debouncePeriodUs=1000000}, mask=1}]}, numLines=1, eventBufferSize=0, fd=18}
1293 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - reading GPIO offset.
1293 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - GPIO offset state is 0.
1293 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - writing GPIO offset 1.
1296 [DIN-27-watcher-0] TRACE com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Start polling GPIO data on offset 134217728 at 2026-10-30T02:52:07.465211550Z
2324 [DIN-27-watcher-0] TRACE com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Detected new event on offset 134217728: LineEvent{timestampNs=291081436039317, id=1, offset=27, seqno=1, lineSeqno=1}
2326 [DIN-27-watcher-0] TRACE com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Total events on offset 134217728: 1
2326 [DIN-27-watcher-0] TRACE com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Total processing on offset 134217728 took 1030ms
2327 [DIN-27-dispatcher-0] DEBUG com.pi4j.test.smoketest.DigitalInputDebounceTimeTestCase - onDigitalStateChange fired after 1033 ms
7295 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - closing GPIO file descriptor '18'.
7295 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - writing GPIO offset 0.
7295 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - writing GPIO offset 0.
7296 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - closing GPIO file descriptor '17'.
7296 [main] INFO com.pi4j.test.smoketest.DigitalInputDebounceCountTestCase - Starting Digital Debounce Count test
7297 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - requesting GPIO line (DOUT-22)...
7297 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - opening device file.
7297 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - getting line info.
7297 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - GPIO line info: LineInfo{name=(GPIO22)[71, 80, 73, 79, 50, 50], consumer=()[], offset=22, numAttrs=0, flags=8, attrs=[]}
7298 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - GPIO line configured: LineRequest{offsets=[22], consumer=(pi4j.DOUT-22)[112, 105, 52, 106, 46, 68, 79, 85, 84, 45, 50, 50], config=LineConfig{flags=8, numAttrs=0, attrs=[]}, numLines=1, eventBufferSize=0, fd=17}
7298 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - writing GPIO offset 0.
7340 [DIN-27-watcher-0] ERROR com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Internal error during polling on offset 134217728. Last polling data: PollingData{fd=18, events=3, revents=32}
7398 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - reading GPIO offset.
7398 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - GPIO offset state is 0.
7399 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - requesting GPIO line (DIN-27)...
7399 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - opening device file.
7399 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - getting line info.
7400 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - GPIO line info: LineInfo{name=(GPIO27)[71, 80, 73, 79, 50, 55], consumer=()[], offset=27, numAttrs=0, flags=4, attrs=[]}
7400 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - GPIO line configured: LineRequest{offsets=[27], consumer=(pi4j.DIN-27)[112, 105, 52, 106, 46, 68, 73, 78, 45, 50, 55], config=LineConfig{flags=564, numAttrs=1, attrs=[LineConfigAttribute{attr=LineAttribute{id=3, flags=0, values=0, debouncePeriodUs=100000}, mask=1}]}, numLines=1, eventBufferSize=0, fd=18}
7501 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - reading GPIO offset.
7501 [DIN-27-watcher-0] TRACE com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Start polling GPIO data on offset 134217728 at 2026-10-30T02:52:13.670696661Z
7502 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - GPIO offset state is 0.
7502 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - writing GPIO offset 1.
7552 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - writing GPIO offset 0.
7602 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - writing GPIO offset 1.
7706 [DIN-27-watcher-0] TRACE com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Detected new event on offset 134217728: LineEvent{timestampNs=291086820031625, id=1, offset=27, seqno=1, lineSeqno=1}
7706 [DIN-27-watcher-0] TRACE com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Total events on offset 134217728: 1
7707 [DIN-27-watcher-0] TRACE com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Total processing on offset 134217728 took 205ms
7803 [main] INFO com.pi4j.test.smoketest.DigitalInputDebounceCountTestCase - Step 1: 1/0
8003 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - writing GPIO offset 0.
8106 [DIN-27-watcher-0] TRACE com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Detected new event on offset 134217728: LineEvent{timestampNs=291087220015101, id=2, offset=27, seqno=2, lineSeqno=2}
8106 [DIN-27-watcher-0] TRACE com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Total events on offset 134217728: 1
8106 [DIN-27-watcher-0] TRACE com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Total processing on offset 134217728 took 399ms
8203 [main] INFO com.pi4j.test.smoketest.DigitalInputDebounceCountTestCase - Step 2: 1/1
8404 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - writing GPIO offset 1.
8510 [DIN-27-watcher-0] TRACE com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Detected new event on offset 134217728: LineEvent{timestampNs=291087624024570, id=1, offset=27, seqno=3, lineSeqno=3}
8510 [DIN-27-watcher-0] TRACE com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Total events on offset 134217728: 1
8510 [DIN-27-watcher-0] TRACE com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Total processing on offset 134217728 took 403ms
8604 [main] INFO com.pi4j.test.smoketest.DigitalInputDebounceCountTestCase - Step 3: 2/1
8604 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - closing GPIO file descriptor '18'.
8605 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - writing GPIO offset 0.
8605 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - writing GPIO offset 0.
8605 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - closing GPIO file descriptor '17'.
8606 [main] INFO com.pi4j.test.smoketest.DigitalInputMultipleListenersTestCase - Starting Multiple Digital Listeners test
8606 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - requesting GPIO line (DOUT-22)...
8606 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - opening device file.
8606 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - getting line info.
8606 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - GPIO line info: LineInfo{name=(GPIO22)[71, 80, 73, 79, 50, 50], consumer=()[], offset=22, numAttrs=0, flags=8, attrs=[]}
8606 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - GPIO line configured: LineRequest{offsets=[22], consumer=(pi4j.DOUT-22)[112, 105, 52, 106, 46, 68, 79, 85, 84, 45, 50, 50], config=LineConfig{flags=8, numAttrs=0, attrs=[]}, numLines=1, eventBufferSize=0, fd=17}
8607 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - writing GPIO offset 0.
8607 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - requesting GPIO line (DIN-27)...
8607 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - opening device file.
8607 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - getting line info.
8607 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - GPIO line info: LineInfo{name=(GPIO27)[71, 80, 73, 79, 50, 55], consumer=(pi4j.DIN-27)[112, 105, 52, 106, 46, 68, 73, 78, 45, 50, 55], offset=27, numAttrs=1, flags=565, attrs=[]}
8608 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - writing GPIO offset 0.
8608 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - writing GPIO offset 0.
8608 [main] TRACE com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - closing GPIO file descriptor '17'.
8608 [main] ERROR com.pi4j.test.smoketest.DigitalInputMultipleListenersTestCase - Test failure
java.lang.IllegalStateException: Failed to initialize IO DIN-27
	at com.pi4j.context.impl.MutableRegistry.register(MutableRegistry.java:57)
	at com.pi4j.context.impl.DefaultContext.register(DefaultContext.java:243)
	at com.pi4j.context.impl.DefaultContext.create(DefaultContext.java:249)
	at com.pi4j.internal.IOCreator.create(IOCreator.java:33)
	at com.pi4j.internal.IOCreator.create(IOCreator.java:49)
	at com.pi4j.internal.IOCreator.create(IOCreator.java:73)
	at com.pi4j.test.smoketest.TestCase.createDigitalInput(TestCase.java:22)
	at com.pi4j.test.smoketest.DigitalInputMultipleListenersTestCase.run(DigitalInputMultipleListenersTestCase.java:21)
	at com.pi4j.test.Main.main(Main.java:75)
Caused by: com.pi4j.exception.InitializeException: Offsets are in use: [27]
	at com.pi4j.plugin.ffm.common.FFMGpioLine.openAndRequest(FFMGpioLine.java:102)
	at com.pi4j.plugin.ffm.providers.parallel.FFMParallelPort.applyInitialState(FFMParallelPort.java:91)
	at com.pi4j.io.gpio.parallel.ParallelDigitalInput.applyInitialState(ParallelDigitalInput.java:37)
	at com.pi4j.context.impl.MutableRegistry.register(MutableRegistry.java:53)
	... 8 more
8609 [main] INFO com.pi4j.test.Main - 
8609 [main] INFO com.pi4j.test.Main - ==============================================================
8609 [main] INFO com.pi4j.test.Main - Test results with NEWAUTOCONTEXT:
8609 [main] INFO com.pi4j.test.Main - 	Total Tests: 3
8610 [main] INFO com.pi4j.test.Main - 	Passed: 1
8610 [main] INFO com.pi4j.test.Main - 	Failed: 2
8610 [main] INFO com.pi4j.test.Main - ==============================================================
8611 [main] INFO com.pi4j.test.Main - 
8611 [DIN-27-watcher-0] ERROR com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Internal error during polling on offset 134217728. Last polling data: PollingData{fd=18, events=3, revents=32}
8611 [main] INFO com.pi4j.test.Main - Test: Digital Debounce Time
8611 [main] INFO com.pi4j.test.Main - 	FAILED
8611 [main] INFO com.pi4j.test.Main - 	Event fired outside tolerance at 1033ms (debounce not working properly)
8611 [main] INFO com.pi4j.test.Main - ==============================================================
8611 [main] INFO com.pi4j.test.Main - Test: Digital Debounce Count
8611 [main] INFO com.pi4j.test.Main - 	PASSED
8611 [main] INFO com.pi4j.test.Main - 	Correct state change counts detected
8611 [main] INFO com.pi4j.test.Main - ==============================================================
8611 [main] INFO com.pi4j.test.Main - Test: Multiple Digital Listeners
8611 [main] INFO com.pi4j.test.Main - 	FAILED
8611 [main] INFO com.pi4j.test.Main - 	Test failure: Failed to initialize IO DIN-27
8611 [main] INFO com.pi4j.test.Main - ==============================================================
8611 [main] INFO com.pi4j.context.impl.DefaultContext - Shutting down Pi4J context/runtime...
8614 [main] INFO com.pi4j.util.ExecutorPool - Shutting down executor pool Pi4J.RUNTIME
8615 [main] INFO com.pi4j.context.impl.DefaultContext - Pi4J context/runtime successfully shutdown. Dispatching shutdown event.

Process finished with exit code 0

@IAmNickNack

Copy link
Copy Markdown
Contributor Author

Hmm ... I get different results:

8946 [main] INFO com.pi4j.test.Main - ==============================================================
8946 [main] INFO com.pi4j.test.Main - Test results with NEWAUTOCONTEXT:
8946 [main] INFO com.pi4j.test.Main - 	Total Tests: 5
8947 [main] INFO com.pi4j.test.Main - 	Passed: 4
8948 [main] INFO com.pi4j.test.Main - 	Failed: 1
8948 [main] INFO com.pi4j.test.Main - ==============================================================
8948 [main] INFO com.pi4j.test.Main - 
8948 [main] INFO com.pi4j.test.Main - Test: Digital Debounce Time
8948 [main] INFO com.pi4j.test.Main - 	FAILED
8948 [main] INFO com.pi4j.test.Main - 	Event fired outside tolerance at 1035ms (debounce not working properly)
8948 [main] INFO com.pi4j.test.Main - ==============================================================
8948 [main] INFO com.pi4j.test.Main - Test: Digital Debounce Count
8948 [main] INFO com.pi4j.test.Main - 	PASSED
8948 [main] INFO com.pi4j.test.Main - 	Correct state change counts detected
8949 [main] INFO com.pi4j.test.Main - ==============================================================
8949 [main] INFO com.pi4j.test.Main - Test: Multiple Digital Listeners
8949 [main] INFO com.pi4j.test.Main - 	PASSED
8949 [main] INFO com.pi4j.test.Main - 	All events were received
8949 [main] INFO com.pi4j.test.Main - ==============================================================
8949 [main] INFO com.pi4j.test.Main - Test: Parallel Port
8949 [main] INFO com.pi4j.test.Main - 	PASSED
8949 [main] INFO com.pi4j.test.Main - 	Parallel port operations completed
8949 [main] INFO com.pi4j.test.Main - ==============================================================
8949 [main] INFO com.pi4j.test.Main - Test: Parallel Port Events
8949 [main] INFO com.pi4j.test.Main - 	PASSED
8949 [main] INFO com.pi4j.test.Main - 	Parallel port event operations completed
8949 [main] INFO com.pi4j.test.Main - ==============================================================

Does main work for you?

@taartspi

taartspi commented Oct 30, 2026 via email

Copy link
Copy Markdown
Contributor

@IAmNickNack
IAmNickNack force-pushed the wip/parallel-backed-digital-devices branch from bb327ff to 6f5c80f Compare October 30, 2026 16:54
# Conflicts:
#	pi4j-core/src/main/java/com/pi4j/io/gpio/parallel/ParallelPortConfig.java
@IAmNickNack
IAmNickNack force-pushed the wip/parallel-backed-digital-devices branch from 6f5c80f to 615446a Compare October 30, 2026 16:57
@taartspi

Copy link
Copy Markdown
Contributor

I still see a fail. I included how I create the environment in case you want different steps.


Oct 30

pi@Pi5-8-M2:~/Pi4J/pi4j/pi4j-test/target/distribution $ git fetch origin main
From https://github.com/Pi4J/pi4j
 * branch              main       -> FETCH_HEAD
pi@Pi5-8-M2:~/Pi4J/pi4j/pi4j-test/target/distribution $ git rebase origin main
Current branch main is up to date.
pi@Pi5-8-M2:~/Pi4J/pi4j/pi4j-test/target/distribution $ 


 git fetch origin pull/833/head:shared_command 

pi@Pi5-8-M2:~/Pi4J/pi4j/pi4j-test/target/distribution $ git checkout shared_command 
Switched to branch 'shared_command'

pi@Pi5-8-M2:~/Pi4J/pi4j/pi4j-test/target/distribution $ git log
commit 615446a6a5fe92a313cda6c478d6f92294d1f335 (HEAD -> shared_command)
Author: iamnicknack <5727098+IAmNickNack@users.noreply.github.com>
Date:   Fri Oct 30 16:53:45 2026 +0000

    handle missing initial value for parallel port configuration
    
    # Conflicts:
    #       pi4j-core/src/main/java/com/pi4j/io/gpio/parallel/ParallelPortConfig.java

commit bb327fffe58c3df53d2032a3c2f039c45d3b979e
Author: iamnicknack <5727098+IAmNickNack@users.noreply.github.com>
Date:   Fri Oct 30 07:53:46 2026 +0000

    add digital profiler test case

commit ef4fbb3b1cee7008be8ee3d426e691f60934c447
Autho

 ./mvnw clean install


INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  01:40 min
[INFO] Finished at: 2026-10-30T16:11:09-05:00
[INFO] ------------------------------------------------------------------------
pi@Pi5-8-M2:~/Pi4J/pi4j $ cd pi4j-test/target/distribution/
pi@Pi5-8-M2:~/Pi4J/pi4j/pi4j-test/target/distribution $ ./runSmoketest.sh 

Third time running the test it failed
0188 [main] INFO com.pi4j.test.Main - 	Correct state change counts detected
20188 [main] INFO com.pi4j.test.Main - ==============================================================
20188 [main] INFO com.pi4j.test.Main - Test: Multiple Digital Listeners
20188 [main] INFO com.pi4j.test.Main - 	FAILED
20188 [main] INFO com.pi4j.test.Main - 	Test failure: Failed to initialize IO DIN-27
20188 [main] INFO com.pi4j.test.Main - ==============================================================
20188 [main] INFO com.pi4j.test.Main - Test: Parallel Port
20188 [main] INFO com.pi4j.test.Main - 	PASSED
20188 [main] 

0142 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - requesting GPIO line (DIN-27)...
20144 [main] ERROR com.pi4j.test.smoketest.DigitalInputMultipleListenersTestCase - Test failure
java.lang.IllegalStateException: Failed to initialize IO DIN-27
	at com.pi4j.context.impl.MutableRegistry.register(MutableRegistry.java:57)
	at com.pi4j.context.impl.DefaultContext.register(DefaultContext.java:243)
	at com.pi4j.context.impl.DefaultContext.create(DefaultContext.java:249)
	at com.pi4j.internal.IOCreator.create(IOCreator.java:33)
	at com.pi4j.internal.IOCreator.create(IOCreator.java:49)
	at com.pi4j.internal.IOCreator.create(IOCreator.java:73)
	at com.pi4j.test.smoketest.TestCase.createDigitalInput(TestCase.java:22)
	at com.pi4j.test.smoketest.DigitalInputMultipleListenersTestCase.run(DigitalInputMultipleListenersTestCase.java:21)
	at com.pi4j.test.Main.main(Main.java:75)
Caused by: com.pi4j.exception.InitializeException: Offsets are in use: [27]
	at com.pi4j.plugin.ffm.common.FFMGpioLine.openAndRequest(FFMGpioLine.java:102)
	at com.pi4j.plugin.ffm.providers.parallel.FFMParallelPort.applyInitialState(FFMParallelPort.java:91)
	at com.pi4j.io.gpio.parallel.ParallelDigitalInput.applyInitialState(ParallelDigitalInput.java:37)
	at com.pi4j.context.impl.MutableRegistry.register(MutableRegistry.java:53)
	... 8 more
20146 [main] INFO com.pi4j.test.smoketest.ParallelPortTestCase - Starting Parallel Port test
20146 [DIN-27-watcher-0] ERROR com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Internal error during polling on offset 134217728. Last polling data: PollingData{fd=11, events=3, revents=32}
20147 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-83886080 - requesting GPIO line (parallel-out)...
20148 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev



Separate point. 
When all pass this ERROR text is still present.

20695 [parallel-in-watcher-0] ERROR com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Internal error during polling on offset 33619968. Last polling data: PollingData{fd=11, events=3, revents=32}


@IAmNickNack

IAmNickNack commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor Author

In this latest, I see it's the first test which is failing on an issue with pin 27.

Up until this point, none of the smoke tests will have had an opportunity to request and not release this pin, so it looks unrelated to the code change.

Maybe your device has something assigned to it by the kernel. What does gpioinfo report?

If you change the bcm values for the digital tests to alternative pins, does that make a difference? The parallel test uses the pairs:

  • Out: 24, In: 25
  • Out: 26, In: 16

Edit:

Apologies if I've misread the output pasted above. I would though suggest two things:

  • run the smoke tests using the code from main to get a known good result
  • try an alternative pair of pins and avoid 27

@IAmNickNack

IAmNickNack commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor Author

Ah .. Finally, I now see the same error:

8438 [main] INFO com.pi4j.test.smoketest.DigitalInputDebounceCountTestCase - Starting Digital Debounce Count test
8438 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - requesting GPIO line (DOUT-22)...
8439 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - GPIO line configured: LineRequest{offsets=[22], consumer=(pi4j.DOUT-22)[112, 105, 52, 106, 46, 68, 79, 85, 84, 45, 50, 50], config=LineConfig{flags=8, numAttrs=1, attrs=[LineConfigAttribute{attr=LineAttribute{id=2, flags=0, values=0, debouncePeriodUs=0}, mask=1}]}, numLines=1, eventBufferSize=0, fd=17}
8539 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - requesting GPIO line (DIN-27)...
8540 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - GPIO line configured: LineRequest{offsets=[27], consumer=(pi4j.DIN-27)[112, 105, 52, 106, 46, 68, 73, 78, 45, 50, 55], config=LineConfig{flags=564, numAttrs=1, attrs=[LineConfigAttribute{attr=LineAttribute{id=3, flags=0, values=0, debouncePeriodUs=100000}, mask=1}]}, numLines=1, eventBufferSize=0, fd=18}
8942 [main] INFO com.pi4j.test.smoketest.DigitalInputDebounceCountTestCase - Step 1: 1/0
9343 [main] INFO com.pi4j.test.smoketest.DigitalInputDebounceCountTestCase - Step 2: 1/1
9743 [main] INFO com.pi4j.test.smoketest.DigitalInputDebounceCountTestCase - Step 3: 2/1
9744 [main] INFO com.pi4j.test.smoketest.DigitalInputMultipleListenersTestCase - Starting Multiple Digital Listeners test
9745 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - requesting GPIO line (DOUT-22)...
9746 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-4194304 - GPIO line configured: LineRequest{offsets=[22], consumer=(pi4j.DOUT-22)[112, 105, 52, 106, 46, 68, 79, 85, 84, 45, 50, 50], config=LineConfig{flags=8, numAttrs=1, attrs=[LineConfigAttribute{attr=LineAttribute{id=2, flags=0, values=0, debouncePeriodUs=0}, mask=1}]}, numLines=1, eventBufferSize=0, fd=17}
9746 [main] INFO com.pi4j.plugin.ffm.common.FFMGpioLine - /dev/gpiochip0-134217728 - requesting GPIO line (DIN-27)...
9747 [main] ERROR com.pi4j.test.smoketest.DigitalInputMultipleListenersTestCase - Test failure
java.lang.IllegalStateException: Failed to initialize IO DIN-27

Interesting that pin 22 doesn't fail 🤔

Also, I wonder if the preceding test has had problems releasing the line

@sonarqubecloud

Copy link
Copy Markdown

@IAmNickNack

Copy link
Copy Markdown
Contributor Author

I have now seen your error. It appears to be very intermittent for me though.

However, I think I may have found the problem:

10063 [parallel-in-watcher-0] ERROR com.pi4j.plugin.ffm.providers.gpio.EventWatcher - Internal error during polling on offset 33619968. Last polling data: PollingData{fd=18, events=3, revents=32}

This error quite reliably appears for every test. This is logged because the poller is attempting to read from a file descriptor which is closed during the timeout period for the event watcher's call to poll.

It looks like there's a race condition during the shutdown logic. I.e. setting the EventWatcher::stopWatching and calling FFMGpioLine::close. The error you've found could be due to the call to close silently failing at some point and the close not completing cleanly.

There are probably multiple fixes for this, but the quick and dirty one I have pushed introduces a delay equal to the poll timeout when EventWatcher::stopWatching() is called. This allows the polling loop to complete before anything else can happen.

At least for me, this avoids the Internal error mentioned above and, so far I've not seen your error again.

I wonder if software debounce may introduce a slight delay which causes this not to happen when it is enabled.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants