Pi4J / pi4j-v2

Pi4J Version 2.0
Apache License 2.0
274 stars 60 forks source link

How to use Context #139

Closed tatery closed 2 years ago

tatery commented 3 years ago

Hi,

I wonder what is the right way to manage contexts, as it is possible to create multiple contexts (Version 1 was implemented using a static singleton, while version 2 uses a “Context” to avoid static singletons). Should I create one context and share it across my application classes, or can each class manage its own pi4j context? Documentation says: "Terminating/destroying the context stops and releases all resources, threads, listeners, and provisioned I/O instances held by the context" - does this mean that the created contexts are independent and destroying one does not affect the others? If so, is it possible to have reference to the same device (e.g. the same i2c device) in few contexts?

Thanks in advance for clarification.

savageautomate commented 3 years ago

For almost all use cases you will need to create a single Context instance and share and re-use that in your application. A Context object contains all the runtime and management state of the I/O. If you had multiple Context objects and attempted to REUSE certain I/O hardware or I/O providers it's possible that they could conflict or get out of sync. I would avoid multiple Context instances unless you really have a very specific use case where you were using separate I/O providers.

I can't think of many use cases for multiple Context instances. Perhaps if you had a system that supported multiple "hot-plug" add-on boards that exposed additional I/O capability and where your software needed to manage the lifecycle of those add-on board I/Os independently. As you can see ... I'm stretching to identify a viable use case :-)

tatery commented 3 years ago

Thanks for clarification. Please consider expanding the description of the context to include the above explanation.

tatery commented 3 years ago

I have additional questions: Let's assume there is only one context in an application. What happens when different parts of the application try to access the same I/O hardware? Does the context retain a reference to the already created handler to the hardware and can return it somehow?

savageautomate commented 3 years ago

Yes the context maintains a reference to each I/O instance created. (Until pi4j.shutdown() is called.)

Somewhere you will need to create() your I/O instance giving it a unique id (string). If you try to call create() a second time with the same id, you will get an IOAlreadyExistsException

 pi4j.digitalOutput().create(1, "my-gpio");

Elsewhere in your application, you can get access to existing I/O instances using the Context's io() or getIO() methods.

 if(pi4j.hasIO("my-gpio")){
     DigitalOutput myOutput = pi4j.io("my-gpio");
 }

Additional methods to access the registered I/O instances can be obtained thru the Registry class..

pi4j.registry().*
tatery commented 3 years ago

@savageautomate Again, many thanks. I have just started a project with pi4j v2 so more questions may arise in the near future ;)

tatery commented 3 years ago

Hello,

Since the SPI configuration is currently limited (please see: https://github.com/Pi4J/pi4j-v2/issues/77) I have to use PiGpioNativeImpl to be able to communicate with the device on second SPI bus:

piGpio = PiGpioNativeImpl.newInstance();
spiHandler = piGpio.spiOpen(SpiChipEnable.CE_1.getChannel(), 15600000, flags);

Questions:

  1. Is it possible to access PiGpioNativeImpl and additionally at the same time use PiGpio as a provider for other I/O hardware, for example:
    pi4j = Pj4Context.getInstance();
    var ledConfig = DigitalOutput.newConfigBuilder(pi4j)
      .id("led")
      .name("LED Flasher")
      .address(PIN_LED)
      .shutdown(DigitalState.LOW)
      .initial(DigitalState.LOW)
      .provider("pigpio-digital-output");
  2. Does pi4j.shutdown(); also close/release the resources allocated by piGpio = PiGpioNativeImpl.newInstance();?
  3. Is it possible to get reference to PiGpioNativeImpl from context?
savageautomate commented 3 years ago

1) Is it possible to access PiGpioNativeImpl and additionally at the same time use PiGpio as a provider for other I/O hardware, for example:

I don't think the PiGpioNativeImpl class is exported in the module-info. So accessing it might be troublesome. However the PiGpio interface is exported and it has the following static default method which effectively is the same thing:

PiGpio.newNativeInstance()

Yes, it's technically possible; however, it really is not intended for direct use outside and in combination with the Pi4J framework. I'm not entirely sure of any problems as longs as you keep careful and distinct control over the IO hardware you are accessing separate. I can't guarantee no conflicts will occur :-)

2) Does pi4j.shutdown(); also close/release the resources allocated by piGpio = PiGpioNativeImpl.newInstance();?

Yes if your Pi4J context includes the PiGPIO providers it will call into the provider and invoke the shutdown() against the PiGpioNativeImpl library. However, if your program did not load the PiGPIO providers into the Pi4J context, then no.

3) Is it possible to get reference to PiGpioNativeImpl from context?

I don't believe so. The Pi4J context should only provide Pi4J I/O interfaces and not direct library interfaces for interacting with the I/O. In fact, the Pi4J runtime/context only knows about the PiGPIO providers. The PiGPIO providers are who internally reference the PiGpioNativeImpl library.

tatery commented 3 years ago

@savageautomate Thanks for clarification.

FDelporte commented 2 years ago

Thanks @tatery and @savageautomate for these clear questions and answers. I used part of it to extend the page https://pi4j.com/documentation/create-context/. OK?