Monday, May 13, 2013

Android IOIO - Listen for Digital Input

Summary
This tutorial shows how to slightly modify the ioio lib in order to add a listener for digital input.
Description
At the very least, you're reading this because you want to do something when the value of your digital input changes.  This might even mean that you've tried to listen for the digital input changes by creating a new thread and use the blocking call Digitalinput.waitForValue().  This is one way but we can also go into the IOIOLib and add a listener.  Adding this listener to the pin is what this article is all about. 

Before we begin
This tutorial assumes you are somewhat familiar with your ioio, java, and android.   How familiar do you have to be to use the tutorial without problems?  Work with the ioio examples first or be able to read your targeted digital input before attempting this tutorial.

Steps

As an overview, we are going to make the following changes/additions to the IOIOLib:
  1. Add the abstract class, "Listener.java", to the package "ioio.lib.impl"
  2. Modify the abstract class, "DigitalInput.java", in the package "ioio.lib.api".  Adding the the abstract methods for the Listener.
  3. Modify the class, "DigitalInputImpl.java", in the package "ioio.lib.impl".  Add the implementation for the Listener, and call  "firePropertyChanged" at the start of "setValue"
  4. Create your DigitalInput in the Looper class
  5. Add the listener in the setup method of your looper class 

Step One



Add the abstract class, "Listener.java" to the package "ioio.lib.impl".
Create a new class named "Listener.java" inside of the package "ioio.lib.impl". 
In this class delete everything and the following:

package ioio.lib.impl;

import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;


public abstract class Listener {

    private final Set<String> properties;

    public Listener(String... properties) {
        Collections.addAll(this.properties = new TreeSet<String>(), properties);
    }

    protected final Set<String> getProperties() {
        return this.properties;
    }

    public abstract <T> void propertyChanged(final String property,
            final T oldValue, final T newValue);
}

See it on github at:
https://github.com/ergobot/IOIOLib/blob/master/src/ioio/lib/impl/Listener.java



Step Two
Modify the abstract class, "DigitalInput.java", in the package "ioio.lib.api".  Adding the the abstract methods for the Listener.

To do this, find the file "DigitalInput.java" in the package "ioio.lib.api" and add the following (inside the class):
     // Custom
    public boolean addListener(final Listener x);
    public boolean removeListener(final Listener x);

See it on github at (lines 129 and 130):
https://github.com/ergobot/IOIOLib/blob/master/src/ioio/lib/api/DigitalInput.java



Step Three
Modify the class, "DigitalInputImpl.java", in the package "ioio.lib.impl".  Add the implementation for the Listener, and call  "firePropertyChanged" at the start of "setValue".

Find the class "DigitalInputImpl.java" in the package "ioio.lib.impl" and add the following (inside the class):

    private final List<Listener> listeners = new LinkedList<Listener>();

    protected final <T> void firePropertyChanged(final String property,
            final T oldValue, final T newValue) {
        assert(property != null);
        if((oldValue != null && oldValue.equals(newValue))
                || (oldValue == null && newValue == null))
            return;
        for(final Listener listener : this.listeners) {
            try {
                if(listener.getProperties().contains(property))
                    //System.out.println("property changed");
                    listener.propertyChanged(property, oldValue, newValue);
            } catch(Exception ex) {
             System.out.println(ex.getMessage());
                // log these, to help debugging
                ex.printStackTrace();
            }
        }
    }

    @Override
    synchronized public final boolean addListener(final Listener x) {
        if(x == null) return false;
        return this.listeners.add(x);
    }

    @Override
    synchronized public final boolean removeListener(final Listener x) {
        return this.listeners.remove(x);
    }

See it on github at: https://github.com/ergobot/IOIOLib/blob/master/src/ioio/lib/impl/DigitalInputImpl.java  (lines 107 through 135)

In this same class add the following inside of the method "setValue":

firePropertyChanged("value",value_,value);
See it on github at: https://github.com/ergobot/IOIOLib/blob/master/src/ioio/lib/impl/DigitalInputImpl.java  (line 55)



Step Four
Create your DigitalInput in the Looper class

I'm using the HelloIOIO project as the example.  Find where your looper class starts, and declare a DigitalInput named "exampleInput".  For this example, it is directly under the line "private DigitalOuput led_;".  The line we are adding looks like this:

private DigitalInput exampleInput;

See it on github at:
https://github.com/ergobot/HelloIOIO/blob/master/src/ioio/examples/hello/MainActivity.java
(line 47)



Step Five
Add the listener in the setup method of the looper class 

Note:  For the example, we are using pin 47.

Find your setup method in the looper class, and add the following:

            // Our digital input (the pin being used for this example is pin #47)
            exampleInput = ioio_.openDigitalInput(47);
           
            exampleInput.addListener(new ioio.lib.impl.Listener("value") {
                public <T> void propertyChanged(final String p, final T oldValue,
                final T newValue) {
                                           
                        // This is where you do what you want with the old or new value
                   
                        // Write to the logcat
                        Log.v("exampleInput", "exampleInput - " + System.nanoTime() +"  oldValue = " + ((Boolean) oldValue ? 0:1) + " : newValue = " + newValue);
               
                        // or another way to write it... print it out
                        System.out.println(p + " changed: " + oldValue + " to "    + newValue);
               
                }
                });

See it on github at: https://github.com/ergobot/HelloIOIO/blob/master/src/ioio/examples/hello/MainActivity.java (lines 64 to 79)


...and there it is!  Hope you helps you.  When searching, there wasn't a way to do this.  It may not be the best but take it and make it your own.  If you know of a better way, put it in the comments. 



Resources:

Original idea:
https://groups.google.com/d/msg/ioio-users/aROyaAVOhAQ/UVQHx5Lmh6kJ

Listener based on stackoverflow.com answer:
http://stackoverflow.com/questions/2822901/watching-a-variable-for-changes-without-polling

Eclipse IDE (from the adt-bundle)
     link - http://developer.android.com/sdk/index.html

HelloIOIO
     original - https://github.com/ytai/ioio/tree/master/software/applications/HelloIOIO
     modified -  https://github.com/ergobot/HelloIOIO

IOIOLib
     original - https://github.com/ytai/ioio/tree/master/software/IOIOLib 
     modified - https://github.com/ergobot/IOIOLib

IOIO Mint
     adafruit - http://www.adafruit.com/products/885


No comments:

Post a Comment