Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "Tutorial: OSGi Remote Services for Raspberry Pi GPIO"

(Introduction)
 
(4 intermediate revisions by the same user not shown)
Line 77: Line 77:
  
 
See the [[Tutorial:_Raspberry_Pi_GPIO_with_OSGi_Services | previous tutorial]] for the declaration and description of the GPIO Pin Output service interface.
 
See the [[Tutorial:_Raspberry_Pi_GPIO_with_OSGi_Services | previous tutorial]] for the declaration and description of the GPIO Pin Output service interface.
 +
 +
==Exporting the IGPIOPinOutput Service==
  
 
To make the control of GPIO pin 0 available for remote access, all that's necessary is to provide some service properties when registering the instance of the IGPIOPinOutput instance.  The service properties are standardized by the OSGi Remote Services chapter 100 in the [http://www.osgi.org/Specifications/HomePage OSGi Enterprise specification].
 
To make the control of GPIO pin 0 available for remote access, all that's necessary is to provide some service properties when registering the instance of the IGPIOPinOutput instance.  The service properties are standardized by the OSGi Remote Services chapter 100 in the [http://www.osgi.org/Specifications/HomePage OSGi Enterprise specification].
Line 98: Line 100:
  
 
With ECF's implementation of [[ECF#OSGi_Remote_Services | OSGi Remote Services]] present in the target framework, the properties added above will result in the IGPIOPinOutput service being automatically exported as an OSGi Remote service synchronously during the registerService call.  Exporting will make it available for subsequent discovery and use by other processes.  In the case of the [https://github.com/ECF/RaspberryPI/tree/master/test/features/org.eclipse.ecf.raspberrypi.test.gpio.feature example], the SLP protocol is used for LAN-based network discovery.   
 
With ECF's implementation of [[ECF#OSGi_Remote_Services | OSGi Remote Services]] present in the target framework, the properties added above will result in the IGPIOPinOutput service being automatically exported as an OSGi Remote service synchronously during the registerService call.  Exporting will make it available for subsequent discovery and use by other processes.  In the case of the [https://github.com/ECF/RaspberryPI/tree/master/test/features/org.eclipse.ecf.raspberrypi.test.gpio.feature example], the SLP protocol is used for LAN-based network discovery.   
 +
 +
==Discovering and Importing the IGPIOPinOutput Service==
  
 
Once exported, remote consumers may discover, import, and then use the IGPIOPinOutput service.  To demonstrate this, here is simple Eclipse View present the discovered IGPIOPinOutput remote service instances.  The code for this Eclipse plugin is [https://github.com/ECF/RaspberryPI/tree/master/test/bundles/org.eclipse.ecf.raspberrypi.test.gpio.ide in the test/bundles/org.eclipse.ecf.raspberrypi.test.gpio.ide] project.  When run in the Eclipse ide, the empty view (no discovered IGPIOPinOutput services) looks like this
 
Once exported, remote consumers may discover, import, and then use the IGPIOPinOutput service.  To demonstrate this, here is simple Eclipse View present the discovered IGPIOPinOutput remote service instances.  The code for this Eclipse plugin is [https://github.com/ECF/RaspberryPI/tree/master/test/bundles/org.eclipse.ecf.raspberrypi.test.gpio.ide in the test/bundles/org.eclipse.ecf.raspberrypi.test.gpio.ide] project.  When run in the Eclipse ide, the empty view (no discovered IGPIOPinOutput services) looks like this
Line 117: Line 121:
 
The same as if we had accessed the IGPIOPinOutput service from the Raspberry Pi directly.   
 
The same as if we had accessed the IGPIOPinOutput service from the Raspberry Pi directly.   
  
Note
+
==Technical Notes==
  
 
OSGi Remote Services allows service consumers to ignore the underlying communications transport used for the remoting of the IGPIOPinOutput service.  The code implementing the Eclipse view does not access *any* transport-specific mechanisms, allowing both the Raspberry Pi (service host) and the Eclipse view to use whatever provider transport they prefer.
 
OSGi Remote Services allows service consumers to ignore the underlying communications transport used for the remoting of the IGPIOPinOutput service.  The code implementing the Eclipse view does not access *any* transport-specific mechanisms, allowing both the Raspberry Pi (service host) and the Eclipse view to use whatever provider transport they prefer.
Line 136: Line 140:
  
 
public CompletableFuture<Void> setStateAsync(boolean value);
 
public CompletableFuture<Void> setStateAsync(boolean value);
 
 
...
 
...
  
Line 144: Line 147:
 
The full source for this asynchronous service interface is available [https://github.com/ECF/RaspberryPI/blob/master/bundles/org.eclipse.ecf.raspberrypi.gpio/src/org/eclipse/ecf/raspberrypi/gpio/IGPIOPinOutputAsync.java here].
 
The full source for this asynchronous service interface is available [https://github.com/ECF/RaspberryPI/blob/master/bundles/org.eclipse.ecf.raspberrypi.gpio/src/org/eclipse/ecf/raspberrypi/gpio/IGPIOPinOutputAsync.java here].
  
The Eclipse UI code can then use this asynchronous service to remotely control the GPIO Pin 0 without any blocking operations.  The implementation of the IGPIOPinOutputAsync interface is created on the Eclipse client/consumer by the ECF Remote Services proxy creation.  More about asynchronous remote services is described in [[ECF/Asynchronous_Remote_Services | Asynchronous Remote Services]].
+
The Eclipse UI code can then use this asynchronous service to remotely control the GPIO Pin 0 without any blocking operations.  The implementation of the IGPIOPinOutputAsync interface is created on the Eclipse client/consumer by the ECF Remote Services proxy creation.   
 +
 
 +
Here is a snippet from the implementation of the GPIO Pin View class, showing the use of the IGPIOPinOutputAsync  and support for lambda expressions
 +
 
 +
<source lang="java">
 +
public void toggle() {
 +
// Set waiting to true
 +
waiting = true;
 +
boolean newState = !this.state;
 +
// If we have asynchronous access to service,
 +
// then use it
 +
if (pinOutputAsync != null) {
 +
// Set state asynchronously to newState,
 +
// and when complete change the UI state
 +
// and refresh the viewer
 +
pinOutputAsync.setStateAsync(newState).whenComplete(
 +
(result, exception) -> {
 +
this.waiting = false;
 +
if (viewer != null) {
 +
// No exception means success
 +
if (exception == null) {
 +
// Set UI state to newState
 +
state = newState;
 +
asyncRefresh();
 +
} else
 +
showCommErrorDialog(exception);
 +
}
 +
});
 +
} else {
 +
// If we do not have access to async service, then
 +
// call pinOutput synchronously
 +
pinOutput.setState(newState);
 +
state = newState;
 +
}
 +
}
 +
</source>
 +
 
 +
The entire source for this view class is available [https://github.com/ECF/RaspberryPI/blob/master/test/bundles/org.eclipse.ecf.raspberrypi.test.gpio.ide/src/org/eclipse/ecf/raspberrypi/internal/test/gpio/ide/views/RpiGPIOPinView.java here].
 +
 
 +
More about asynchronous remote services is described in [[ECF/Asynchronous_Remote_Services | Asynchronous Remote Services]].
  
 
==Related Articles==
 
==Related Articles==

Latest revision as of 19:14, 20 October 2014


Introduction

In a previous tutorial we showed how to abstract the Raspberry Pi's GPIO pins as a very simple OSGi Services. This tutorial will show how to export IGPIOPinOutput service instances for remote access via a simple and standard mechanism known as OSGi Remote Services. We also show how to create and use a very simple Eclipse-based user interface as a client for controlling devices connected to the Pi's GPIO.

See the previous tutorial for the declaration and description of the GPIO Pin Output service interface.

Exporting the IGPIOPinOutput Service

To make the control of GPIO pin 0 available for remote access, all that's necessary is to provide some service properties when registering the instance of the IGPIOPinOutput instance. The service properties are standardized by the OSGi Remote Services chapter 100 in the OSGi Enterprise specification.

Here is the code to export the IGPIOPinOutput service

Map<String, Object> pinProps = new HashMap<String, Object>();
pinProps.put("service.exported.interfaces", "*");
pinProps.put("service.exported.configs", "ecf.generic.server");
pinProps.put("ecf.generic.server.port", "3288");
pinProps.put("ecf.generic.server.hostname",InetAddress.getLocalHost().getHostAddress());
pinProps.put("ecf.exported.async.interfaces", "*");
...
 
// register GPIOPin 0 with the above export properties
reg = Pi4jGPIOPinOutput.registerGPIOPinOutput(0, pinProps, context);

See here for the entire source for this example.

With ECF's implementation of OSGi Remote Services present in the target framework, the properties added above will result in the IGPIOPinOutput service being automatically exported as an OSGi Remote service synchronously during the registerService call. Exporting will make it available for subsequent discovery and use by other processes. In the case of the example, the SLP protocol is used for LAN-based network discovery.

Discovering and Importing the IGPIOPinOutput Service

Once exported, remote consumers may discover, import, and then use the IGPIOPinOutput service. To demonstrate this, here is simple Eclipse View present the discovered IGPIOPinOutput remote service instances. The code for this Eclipse plugin is in the test/bundles/org.eclipse.ecf.raspberrypi.test.gpio.ide project. When run in the Eclipse ide, the empty view (no discovered IGPIOPinOutput services) looks like this

Eclipsenopins.png

After discovering an instance of IGPIOPinOutput remote service via SLP LAN-based discovery the view is automatically updated with the IGPIOPinOutput proxy, which is automatically created by the OSGi Remote Services implementation.

Eclipsepinlow.png

With the discovery of this IGPIOPinOutput remote service, and it's appearance in this view, a simple click on the 'State (click to toggle)' cell results in the pin toggling it's state via a call to IGPIOPinUpdate.setState, resulting in both the Eclipse UI being updated with a different icon

Eclipsepinhigh.png

and the LED that's connected to the Raspberry Pi lights up

Leghigheclipse.png

The same as if we had accessed the IGPIOPinOutput service from the Raspberry Pi directly.

Technical Notes

OSGi Remote Services allows service consumers to ignore the underlying communications transport used for the remoting of the IGPIOPinOutput service. The code implementing the Eclipse view does not access *any* transport-specific mechanisms, allowing both the Raspberry Pi (service host) and the Eclipse view to use whatever provider transport they prefer.

The dynamics of unreliable remote services (i.e. that services come and go over time) is handled extremely well by OSGi services.

ECF provides support for using the Java8 CompletableFuture for asynchronous remote services, eliminating the potential for user interface blocking, without complicated threading code. On the remote service consumer (Eclipse UI in this case), the ECF proxy automatically implements this asynchronous service type


package org.eclipse.ecf.raspberrypi.gpio;
 
import java.util.concurrent.CompletableFuture;
 
public interface IGPIOPinOutputAsync {
 
	public CompletableFuture<Boolean> getStateAsync();
 
	public CompletableFuture<Void> setStateAsync(boolean value);
...
 
}

The full source for this asynchronous service interface is available here.

The Eclipse UI code can then use this asynchronous service to remotely control the GPIO Pin 0 without any blocking operations. The implementation of the IGPIOPinOutputAsync interface is created on the Eclipse client/consumer by the ECF Remote Services proxy creation.

Here is a snippet from the implementation of the GPIO Pin View class, showing the use of the IGPIOPinOutputAsync and support for lambda expressions

public void toggle() {
	// Set waiting to true
	waiting = true;
	boolean newState = !this.state;
	// If we have asynchronous access to service,
	// then use it
	if (pinOutputAsync != null) {
		// Set state asynchronously to newState,
		// and when complete change the UI state
		// and refresh the viewer
		pinOutputAsync.setStateAsync(newState).whenComplete(
				(result, exception) -> {
					this.waiting = false;
					if (viewer != null) {
						// No exception means success
						if (exception == null) {
							// Set UI state to newState
							state = newState;
							asyncRefresh();
						} else
							showCommErrorDialog(exception);
					}
				});
	} else {
		// If we do not have access to async service, then
		// call pinOutput synchronously
		pinOutput.setState(newState);
		state = newState;
	}
}

The entire source for this view class is available here.

More about asynchronous remote services is described in Asynchronous Remote Services.

Related Articles

Tutorial:Raspberry Pi GPIO with OSGi Services

Asynchronous Remote Services

Getting Started with ECF's OSGi Remote Services Implementation

Download ECF Remote Services/RSA Implementation

How to Add Remote Services/RSA to Your Target Platform

Back to the top