Thales' cellular IoT products business is now part of Telit Cinterion, find out more.

You are here

Telit Cinterion IoT Developer Community

Concept Board: GPIO demo MIDlet

Tutorial, April 10, 2014 - 4:42pm, 8384 views

General overview

Java capable modules - like EHS6 embedded in Gemalto Concept Board, offer the possibility to access GPIO from Java application. Generally there are two strategies to control GPIO from Java:

  1. ATCommand instance may be used to send GPIO related commands over AT command interface.
  2. Special GPIO API with provided with SDK may be used.

This tutorial is focused on 2nd strategy. Java API offers following types:

  • public class InPort - support for accessing input pins
  • public class OutPort - support for accessing output pins
  • public interface InPortListener - support for automatic notifications on input port changes

General idea of InPort and OutPort classes is to create virtual parallel port integrating up to 10 selected GPIO pins. After port creation its value is mapped to unsigned integer where consecutive bits match adequate pins. The order of pins added to port is unrestricted. GPIO pins must be configured to work in GPIO mode. Every pin may be used with only one port. The usage of all GPIO ports is restricted to the same interface where the GPIO driver was opened. The parallel access of the GPIO driver by Java and another interface (i.e. AT command interface) is not supported.

Although this tutorial is in general applicable to all Java modules, please note that other Gemalto products may have other GPIO configuration.

Application concept

For tutorial purpose we will create Java MIDlet for Gemalto Concept Board that will:

  • consecutively flash 8 LED diodes (D2-D9),
  • suspend/resume flashing with BTN-A,
  • terminate application with BTN-B.

 

Initial configuration

Part of GPIO lines can be configured to work in GPIO mode or be used by alternate features. Full mapping is available in GPIO Configuration Table in AT Command Set.

For Concept Board's GPIO following mapping is applicable:

 Concept Board mapping

 

Ensure that all alternate functions are disabled so GPIO driver can access pins. AT^SCFG="GPIO/mode/ASC1",<g_mode> command corresponding to all features must be set to "gpio". Check below listing for reference:

at^scfg?

(…)

^SCFG: "Gpio/mode/DAI","gpio"

(…)

^SCFG: "Gpio/mode/PULSE","gpio"

^SCFG: "Gpio/mode/PWM","gpio"

(…)

^SCFG: "Gpio/mode/SYNC","gpio"

(…)

OK

Please note that GPIO mode changes take effect after module's restart.

InPort usage

To read values on input pins input port must be configured. Vector with GPIO identifiers must be created to be passed to InPort constructor. First pin in vector is the LSB:

Vector inPins = new Vector();
inPins.addElement("GPIO11");
inPins.addElement("GPIO12");
	
InPort inPort = new InPort(inPins);  

After this you can read port value or register InPortListener to handle port changes:

int inPortValue = inPort.getValue();

inPort.addListener(new InPortListener() {
	public void portValueChanged(int val) {
		System.out.println("Port value: " + val);
	}

});

OutPort usage

To set state of output pins output port must be configured. Vector with GPIO identifiers and vector with initial pins' values must be created to be passed to OutPort constructor. First pin in vector is the LSB:

Vector outPins = new Vector(8);
Vector outValues = new Vector(8);
outPins.addElement("GPIO5"); outValues.addElement(new Integer(1));
outPins.addElement("GPIO6"); outValues.addElement(new Integer(1));
outPins.addElement("GPIO8"); outValues.addElement(new Integer(1));
outPins.addElement("GPIO7"); outValues.addElement(new Integer(1));
outPins.addElement("GPIO20"); outValues.addElement(new Integer(1));
outPins.addElement("GPIO21"); outValues.addElement(new Integer(1));
outPins.addElement("GPIO22"); outValues.addElement(new Integer(1));
outPins.addElement("GPIO23"); outValues.addElement(new Integer(1));

OutPort outPort = new OutPort(outPins, outValues); 

After this you can set port value, example below:

 outPort.setValue(1 << 3); // set only 3rd pin 

MIDlet implementation

Implementation consists of two classes - Main and FlasherTask.

Main task configures InPort and OutPort, starts Flasher Task and waits for Flasher Task to complete. Flasher Task performs flashing routine and reacts to changes on input port according to scenario.

Main class implementation

import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
import java.io.IOException;
import java.util.Vector;
import com.cinterion.io.InPort;
import com.cinterion.io.InPortListener;
import com.cinterion.io.OutPort;

/**
 * Main MIDlet class
 * 
 * @author Jedrzej Wiewiora
 */
public class Main extends MIDlet {
	
	InPort inPort = null;
	OutPort outPort = null;

	protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
		try {
			inPort.release();
		}
		catch(IOException e){}
		catch(NullPointerException e){}
		
		try {
			outPort.release();
		}
		catch(IOException e){}
		catch(NullPointerException e){}
		
		notifyDestroyed();
	}
	
	protected void startApp() throws MIDletStateChangeException {
		// configuration for input port with 2 pins
		Vector inPins = new Vector();
		inPins.addElement("GPIO11");
		inPins.addElement("GPIO12");
		
		// configuration for output port with 8 pins
		Vector outPins = new Vector(8);
		Vector outValues = new Vector(8);
		outPins.addElement("GPIO5"); outValues.addElement(new Integer(1));
		outPins.addElement("GPIO6"); outValues.addElement(new Integer(1));
		outPins.addElement("GPIO8"); outValues.addElement(new Integer(1));
		outPins.addElement("GPIO7"); outValues.addElement(new Integer(1));
		outPins.addElement("GPIO20"); outValues.addElement(new Integer(1));
		outPins.addElement("GPIO21"); outValues.addElement(new Integer(1));
		outPins.addElement("GPIO22"); outValues.addElement(new Integer(1));
		outPins.addElement("GPIO23"); outValues.addElement(new Integer(1));
	    
		try {
			// create input port 
			inPort = new InPort(inPins);
			// create output port
			outPort = new OutPort(outPins, outValues);
			
			// create and start flasher task
			FlasherTask flasher = new FlasherTask(outPort);
			flasher.start();
			
			// register flasher task as input port listener
			inPort.addListener(flasher);
			
			// print messages 
			System.out.println("Flasher task started");
			System.out.println("Use BTN-A to resume/suspend flashing");
			System.out.println("Use BTN-B to terminate");
			
			// wait for flasher task to complete
			flasher.join();
			
			System.out.println("Flasher thread completed");
		}
		catch (InterruptedException e) {
			e.printStackTrace();
		}
		catch (IOException e1) {
			e1.printStackTrace();
		}
		finally {
			destroyApp(true);
		}
	}
	
	protected void pauseApp() {
	}
}

FlasherTask class implementation

import java.io.IOException;
import com.cinterion.io.InPortListener;
import com.cinterion.io.OutPort;

/**
* FlasherTask thread class
* handles output port and  input port listener and  
*
* @author Jedrzej Wiewiora
*/
public class FlasherTask extends Thread implements InPortListener {
	private boolean terminated, suspended;
	private int step;
	private int portLen;
	private OutPort outPort;
	
	public FlasherTask(OutPort _outPort) {
		outPort = _outPort;
		portLen = outPort.getPins().size();
		
		terminated = false;
		suspended = false;
	}
	
	/**
	 * InPortListener API implementation.
	 * Suspends, wakes up and terminates the flasher thread.
	 * If 1st pin of input port is set:
	 *   Suspends if working or wakes up if suspended.
	 * If 2nd pin of input port is set.
	 *   Terminates the flasher thread.
	 * 
	 * @param portValue new value of listened port
	 */
	public synchronized void portValueChanged(int portValue) {
		if( portValue == 1){
			if(suspended) {
				suspended = false;
				this.notify();
			}
			else {
				suspended = true;
			}
		}
		else if( portValue == 2) {
			stop();
		}
	}
	
	/**
	 * Sets "terminated" flag to true.
	 * Forces main loop to quit on next iteration.
	 */
	public synchronized void stop(){
		terminated = true;
		if(suspended){
			suspended = false;
			this.notify();
		}
	}
	
	/**
	 * Thread API implementation.
	 * Performs flashing routine.
	 * Suspends when "suspended" flag is set.
	 * Quits when "terminated" flag is set.
	 */
	public void run(){
		step = 0;
		try {
			// main loop
			while(true){
				synchronized(this){
					// wait while suspended
					while(suspended)
						this.wait();
					// quit loop if terminated
					if(terminated)
						break;
				}
				// set new value output port
				outPort.setValue(1<<step);
				step = (step + 1) % portLen;
				// wait 0.1s
				Thread.sleep(100);
			}
			// when main loop is left flash all diodes for 1 s
			outPort.setValue((1<<portLen) - 1);
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

Deployment and usage

After running the application (check https://iot-developer.thalesgroup.com/tutorial/hello-world-application for basics) diodes are flashing. BTN-A and BTN-B may be used to control the MIDlet and simple instructions are printed on stdout. In case of exception occurance (e.g. GPIO lines can't be used as they're already reserved), stack trace is printed on stdout.

Hi you can also use the very good Libary from the install CD https://iot-developer.thalesgroup.com/tutorial/conceptboard-java-gpiolib

Thanks for the example. I could not get it to run with Eclipse, got a bunch of errors, and found some info that Netbeans could work better. So I installed NB and got this to run.

How ever, I ran into something weird when trying to debug the app. I haven't done more than a couple of months of Java development earlier, so I really have no clue whether this is because of my Netbeans setup, something to do with the cldc platform, EHS6 related, the way the threads are set up or something completely different... any pointers appreciated:

If I set a breakpoint at the line "suspended = false;" at the end of the Flasher contructor, I'd expect the debugger to be able to show me the class variables. But they are not availabe, nor is "this" as a watch in NB. Weirdly enough, the parameter to the function, i.e. _outPort is visible for NB. If I break somewhere in portValueChanged(), once again the parameter "portValue" is available for debugging, but none of the class variables are. 

So in short: any idea what might be wrong in my setup? I really need to get this basic stuff solved before any further development plans. Obviously, if you feel this post should be at another place on the forums, feel free to move it.

Cheers,

Pasi

Author

Jędrzej Gemalto Moderator's picture
Jędrzej Gemalto Moderator