Telit Cinterion IoT Developer Community
Concept Board: GPIO demo MIDlet
Tutorial, April 10, 2014 - 4:42pm, 7591 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:
- ATCommand instance may be used to send GPIO related commands over AT command interface.
- 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:
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.
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