Recent Changes - Search:

Sunspot

SunSPOT is a hard- and software platform developed by Oracle Labs (http://www.sunspotworld.com/)

Project SunSPOT was created to encourage the development of new applications and devices.
It is designed from the ground up to allow programmers who never before worked with embedded
devices to think beyond the keyboard, mouse and screen and write programs that interact with each other,
the environment and their users in completely new ways. A Java programmer can use standard Java development
tools such as NetBeans to write code.

SunSPOT layers

Sunspot has three layers:

  • Battery
  • Processor Board with Radio
  • Sensor Board

Attach:sunspotleyers.jpg

Hardware Characteristics

  • SunSPOTS have common characteristics with mobile phones
  • SunSPOTS Processor Board:
    • 180MHz 32-bit ARM processor, 512K RAM, 4M Flash
    • 2.4GHz radio, IEEE 802.15.4 compliant, with an antenna
    • USB interface to connect to a PC
    • rechargeable lithium-ion battery
  • SunSPOTS Sensor Board has the following characteristics:
    • 8 tri-color LEDs
    • 2 momentary switches
    • a 3-axis accelerometer
    • a temperature sensor
    • a light sensor
    • 5 general purpose I/O pins and 4 high current output pins
  • SunSPOT has a unique IEEE 64-bit address
    • Expressed as four sets of four-digit hexadecimal numbers: nnnn.nnnn.nnnn.nnnn.
    • The first eight digits will always be 0014.4F01
    • The last eight digits should be printed on a sticker on the SunSPOTS

Software Characteristics

  • SunSPOTS have the following software characteristics:
    • run a Java VM (Squawk VM) that provides basic OS functionality
    • Squawk VM implements Java Micro Edition (J2ME)
    • all major parts of the Sun SPOT project are open source: hardware, operating system/virtual machine, drivers and libraries, applications
  • The SPOTManager tools is provided for managing SDK and \suns devices
  • A SunSPOT emulator is also provided that runs applications in virtual SunSPOT (Solarium)

SPOTManager

The SPOTManager tool provides the following functionalities:

  • allows you to query and change the configuration of individual SunSPOT
  • allows you to download and install versions of the SunSPOT SDK
  • launches Solarium, a tool for managing individual SunSPOTS and simulating virtual SunSPOTS

Topology

SunSPOTs are usually used in the following topology:

Attach:sunspottopology.jpg

  • The free-range SunSPOT communicate wirelessly with other SunSPOT and the basestation
  • The basestation is a SunSPOT connected, through USB, with a host
  • The host applications interact with the SunSPOT through the basestation application
  • The host application is a J2SE program, that also has access to a subset of the API of the libraries used by SunSPOT
  • A host application communicates with a SunSPOT via a basestation using code identical that which you would use to communicate between two SunSPOTs
  • The basestation may run in either dedicated or shared mode
  • In the shared model, the host application has its own address, distinct from that of the basestation
  • The main advantage of shared mode is that more than one host application can use the same basestation simultaneously
  • The disadvantage of shared mode is that run-time manipulation of the basestation SunSPOT's radio chatacteristics is not possible

Development

Deploy

In general there are three ways in order to develop, build, deploy and manage an application and the corresponding \suns:

  • command line: develop, deploy, run
  • IDE: develop, deploy, run
  • SPOTManager: deploy, manage

Deploy and run BounceDemo Application using command line:

  # Go to SunSPOT's sdk directory
  cd ~/SunSPOT/sdk/

  # Go to Demos/BounceDemo
  cd Demos/BounceDemo/BounceDemo-OnSPOT/

  # Deploy application using ant
  ant deploy -Dport=/dev/ttyACM0

  # Run the application 
  ant run -Dport=/dev/ttyACM0  

Files Structure

All application root directories have the same layout:

  • The root directory contains two files that control the ant script used to build and run applications
    • build.xml
    • build.properties
  • The root directory also contains two main sub-directories
    • src, is the root of the source code tree for this application
    • resources, contains the manifest file that defines the application, plus any other resource files that the application needs at run time
    • other IDE specific or not directories may exist or appear after the build process, such as suite where the jar app is saved.

Code Structure

  • In Java SE, an application consists of a static main() method defined in one of the loaded classes
  • In Java ME, an application is defined as a class that extends the MIDlet class
  • The Jave ME applications are also called MIDlets
  • All Java ME applications implement the three members
    • startApp(): application acquires the resources that it requires and starts executing
    • pauseApp()
    • destroyApp(): application releases resources and stops executing
  • If the application wants to exit, it must call notifyDestroyed()

Hello World Demo

public class SunSpotApplication extends MIDlet {

    protected void startApp() throws MIDletStateChangeException {

        System.out.println("Hello, world");

    }

    protected void pauseApp() {
        // This is not currently called by the Squawk VM
    }

    protected void destroyApp(final boolean unconditional) 
                                throws MIDletStateChangeException {
        System.out.println("Bye Bye!");
        notifyDestroyed();                          // cause the MIDlet to exit
    }

Hello World Demo

Update startApp() and print the IEEE address of the SunSPOT

protected void startApp() throws MIDletStateChangeException {

  System.out.println("Hello, world");

 //the 64-bit IEEE address of this device
 long ourAddr = Spot.getInstance().getRadioPolicyManager().getIEEEAddress();

 System.out.println("Our radio address = " + IEEEAddress.toDottedHex(ourAddr));
}  

Switches

This app illustrates a call back style of using the switches.

  • Declare Variables sw1 and sw2 to hold the two switches
    /**
     * Represents the SW1 switch.
     */
    public final ISwitch sw1 = EDemoBoard.getInstance().getSwitches()[EDemoBoard.SW1];

    /**
     * Represents the SW2 switch.
     */
    public final ISwitch sw2 = EDemoBoard.getInstance().getSwitches()[EDemoBoard.SW2];

Switches}

  • Setup a switch listener to monitor both switches for press or release events. MIDlet should implement ISwitchListener .

\\ Add on startApp() the following lines:

    //Adds the specified switch listener to 
    //receive callbacks from this switch.
    sw1.addISwitchListener(this);

    //Adds the specified switch listener to 
    //receive callbacks from this switch.
    sw2.addISwitchListener(this);

Switches

  • These methods are the "call backs" that are invoked whenever the switch is pressed or released. They run in a new thread. Parameter sw represents
    the switch that was pressed/released.
    /**
     * Callback for when the switch state changes from released to pressed.
     */
    public void switchPressed(final ISwitch iSwitch) {
        final int switchNum = (iSwitch == sw1) ? 1 : 2;
        if (switchNum == 1) {
            System.out.println("SW1 switch pressed");
            }
        } else {
            System.out.println("SW2 switch pressed");
            try {
                destroyApp(true);
            } catch (MIDletStateChangeException e) {
                e.printStackTrace();
            }
        }
    }

Switches

    /**
     * Callback for when the switch state changes from pressed to released.
     */
    public void switchReleased(final ISwitch iSwitch) {
        final int switchNum = (iSwitch == sw1) ? 1 : 2;
        if (switchNum == 1) {
            System.out.println("SW1 switch released");
        } else {
            System.out.println("SW2 switch released");
        }
    }

LEDs

There are eight three-color LEDs on the demo Sensor Board. \\Sample code to show how to use the tricolor LEDs.

  • Initialize an ITriColorLED array which controls the built in LEDs.
    /**
     * An array of all the built in LEDs.
     */
    private final ITriColorLED[] leds = EDemoBoard.getInstance().getLEDs();

LEDs

  • Update the implementation code of switchPressed() callback.
    public void switchPressed(final ISwitch iSwitch) {
        int switchNum = (iSwitch == sw1) ? 1 : 2;
        if (switchNum == 1) {
            System.out.println("SW1 switch pressed");
            for (int i = 0; i < 8; i++) {
                leds[i].setColor(LEDColor.RED);     // set color to red
                leds[i].setOn();                    // turn the LED on 
                Utils.sleep(250);                   // wait 1/4 seconds
            }
        } else {
            System.out.println("SW2 switch pressed");
            try {
                destroyApp(true);
            } catch (MIDletStateChangeException e) {
                e.printStackTrace();
            }
        }
    }

LEDs

  • Update the implementation code of destroyApp()
    protected void destroyApp(final boolean unconditional) 
                          throws MIDletStateChangeException {
        System.out.println("Bye Bye!");
     for (int i = 7; i >= 0; i--) {
         leds[i].setOff();               // turn the LED off
         Utils.sleep(250);               // wait 1/4 seconds
     }
        notifyDestroyed();                  // cause the MIDlet to exit
    }

Communication

  • Every SunSPOT can act as a mesh router, forwarding packets it receives on to other SunSPOT. This way multihop communication is possible
  • Two multihop protocol can be used:
    • AODVManager, Ad Hoc On Demand Distance Vector Routing protocol.
    • LQRPManager, Link Quality Routing Protocol (default)
  • SingleHopManager, single hop (non-mesh) Routing protocol.
  • Two communication protocols are supported:
    • The Radiostream protocol is a socket-like peer-to-peer and provides reliable, buffered, stream-based communication
    • The Radiogram protocol provides unreliable datagram-based communication
  • Http connections can be started from any \suns to any accessible web service

Radiogram

  • To establish a point-to-point connection both ends must open connections specifying the same portNo and corresponding IEEE addresses.
    Port numbers between 0 and 31 are reserved for system services.
  • Radiogram supports broadcast mode, where radiograms are delivered to all listeners on the given port.

Radio Demo (broadcast)}

This simple demo shows how to use the radio to broadcast some data to any listening SPOTs.

There are two components:

  • The Broadcaster is sending broadcast messages every 1000 ms.
  • The Reveiver is listening for incoming messages on specific port.

Radio Demo (broadcast) - Broadcaster


public class Broadcaster extends Thread {

    public void run() {
        // We create a DatagramConnection
        DatagramConnection dgConnection = null;
        Datagram dg = null;
        try {
            // The Connection is a broadcast
            dgConnection = 
                (DatagramConnection) Connector.open("radiogram://broadcast:37");

            //Set maximum hops Number of the Broadcasted messages
            ((RadiogramConnection) dgConnection).setMaxBroadcastHops(1);

            // Then, we ask for a datagram with the maximum size allowed
            dg = dgConnection.newDatagram(dgConnection.getMaximumLength());

        } catch (IOException ex) {
            System.out.println("Could not open radiogram broadcast connection");
            ex.printStackTrace();
        }
        while (true) {
            try {
                // Reset the datagram
                dg.reset();

                //Send the Datagram.
                dgConnection.send(dg);

            } catch (IOException ex) {
                ex.printStackTrace();
            }
            Utils.sleep(1000);
        }

    }

}

Radio Demo (broadcast) - Receiver}

public class Receiver extends Thread {

    public void run() {
        //Setting up the Datagram Connection
        DatagramConnection dgConnection = null;
        Datagram dg = null;

        try {
            //Open Datagram Connection on port 37
            dgConnection = (DatagramConnection) Connector.open("radiogram://:37");

            // Then, we ask for a datagram with the maximum size allowed
            dg = dgConnection.newDatagram(dgConnection.getMaximumLength());

        } catch (IOException e) {
            System.out.println("Could not open radiogram receiver connection");
            e.printStackTrace();
            return;
        }

        while (true) {
            try {
                //Ensures that the next read or write operation 
                //will read/write from the start of the radiogram
                dg.reset();

                //Receive a Datagram
                dgConnection.receive(dg);

                System.out.println("Received Datagram from: " + dg.getAddress());

            } catch (IOException e) {
                System.out.println("Nothing received");
            }
        }
    }

}

Radio Demo (broadcast) - MIDlet app

public class RadioDemo extends MIDlet {

    protected void destroyApp(final boolean b) throws MIDletStateChangeException {
    }

    protected void pauseApp() {
    }

    protected void startApp() throws MIDletStateChangeException {

        //Start the Broadcaster
        (new Broadcaster()).start();

        //Start the Receiver
        (new Receiver()).start();

        System.out.println("Waiting for messages!!");
    }
}

Radio Demo (unicast)

This simple demo shows how to use the radio to send some data to a specific listening SPOT.

We will modify the Radio Demo (broadcast):

  • Disable the Broadcaster.
  • Update the Reveiver and the RadioDemo MIDlet.
  • Implement a new component, the DataSender. \\DataSender sends a message (String) to a specific destination.

Radio Demo (unicast) - DataSender

public class DataSender {

    /**
     * static instance(ourInstance) initialized as null.
     */
    private static DataSender ourInstance = null;

    /**
     * Private constructor suppresses generation of a default constructor.
     */
    private DataSender() {
        // Does nothing
    }
    /**
     * DataSender is loaded on the first execution of DataSender.getInstance()
     * or the first access to DataSender.ourInstance, not before.
     *
     * @return ourInstance
     */
    public static DataSender getInstance() {
        synchronized (DataSender.class) {
            if (ourInstance == null) {
                ourInstance = new DataSender();
            }
        }
        return ourInstance;
    }

    /**
     * Send a message (String) to a specific Destination.
     */
    public void send(final String targetAddress, final String msg) {
        try {
            // We create a DatagramConnection
            final DatagramConnection dgConnection = 
                        (DatagramConnection) Connector.open("radiogram://" + targetAddress + ":37");

            // Then, we ask for a datagram with the maximum size allowed
            final Datagram dg = dgConnection.newDatagram(dgConnection.getMaximumLength());

            //Ensures that the next read/write operation will read/write from the start of the datagram
            dg.reset();

            //Write Data to Datagram
            dg.writeUTF(msg);

            //Send Datagram
            dgConnection.send(dg);

            //Close the connection
            dgConnection.close();

        } catch (IOException ex) {
            System.out.println("Could not open radiogram connection");
        }
    }
}

Radio Demo (unicast) - Receiver

Read the String from the received datagram and print a debug message with its value.


    while (true) {
        try {
            //Ensures that the next...
            dg.reset();

            //Receive a Datagram
            dgConnection.receive(dg);

            //Read a String from datagram.
         final String rcvMsg = dg.readUTF();

         //System.out.println("Received Datagram from " + dg.getAddress());
        System.out.println("Received msg: " + rcvMsg 
                           + " from: " + dg.getAddress());

        }

Radio Demo (unicast) - MIDlet app

When SW1 is pressed, SunSPOT send a message to another predefined SunSPOT. Modifications:

  • Add the following line
     /**
     * Represents the SW1 switch.
     */
    public final ISwitch sw1 = 
                EDemoBoard.getInstance().getSwitches()[EDemoBoard.SW1];
  • Update the startApp() function:
   protected void startApp() throws MIDletStateChangeException {
     //Start the Broadcaster
     //(new Broadcaster()).start();

        //Start the Receiver
        (new Receiver()).start();
        System.out.println("Waiting for messages!!");
     final String destination = "0014.4F01.0000.6192";
     final String message = "Hello!!";

     while (true) {
         //Block the current thread until the switch's state changes.
         sw1.waitForChange();  //waitForChange() uses interrupts, not polls

         //Check if sw1 is closed
         if (sw1.isClosed()) {
             DataSender.getInstance().send(destination, message);
         }
     }
    }

Host Application

This host application shows how to use the radio to receive some data. It uses the Receiver Thread from the previous Radio Demo (unicast) and prints the received data.

For building and run as a host application :

  • Define the host application's main class in build.properties file. main.class=org.sunspotworld.demo.SunSpotHostApplication
  • Use ant host-run instead ant deploy and ant run
  • The main class should not extends MIDlet.
  • Spot Class (Spot.getInstance()) has been deprecated on host applications

Radio Demo (unicast) - main Class

/**
 * Sample Sun SPOT host application.
 */
public class SunSpotHostApplication {

    /**
     * Default Constructor.
     */
    public SunSpotHostApplication() {
        long ourAddr = RadioFactory.getRadioPolicyManager().getIEEEAddress();
        System.out.println("Our radio address = " + IEEEAddress.toDottedHex(ourAddr));

        //Start Receiver Thread
        (new Receiver()).start();
    }

    /**
     * Start up the host application.
     *
     * @param args any command line arguments
     */
    public static void main(String[] args) throws Exception {
        new SunSpotHostApplication();
        System.exit(0);
    }
}

Delay Tolerant Routing Services Development over Sunspot Deployment

In the following we present an implementation of a delay tolerant message forwarding service.

We present the Message Sender Class, the Message Receiver calls, the DTSManager Service class and

the EchoProtocolManager Class.


Message Sender Class

import com.sun.spot.util.IEEEAddress;
import com.sun.spot.util.Queue;
import eu.fronts.moway.communication.echoprotocol.EchoProtocolManager;
import eu.fronts.moway.util.Node;

import java.util.Enumeration;
import java.util.Vector;

/**
 * DTS Message Sender.
 */
public class MessageSender extends Thread { //NOPMD

    /**
     * True if thread is enabled.
     */
    private boolean isEnabled;

    /**
     * Node Queue.
     */
    private final Queue queue;

    /**
     * Default Constructor.
     */
    public MessageSender(final Queue que) {
        super();
        this.queue = que;
        isEnabled = true;

    }

    /**
     * If this thread was constructed using a separate
     * <code>Runnable</code> run object, then that
     * <code>Runnable</code> object's <code>run</code> method is called;
     * otherwise, this method does nothing and returns.
     * <p/>
     * Subclasses of <code>Thread</code> should override this method.
     *
     * @see #start()
     * @see #stop()
     * @see #Thread(ThreadGroup, Runnable, String)
     */
    public final void run() { //NOPMD

        while (isEnabled) {

            final Node node = (Node) queue.get();

            System.out.println("New node");

            if (node.getType() == Node.MOWAY) {
                //This is another Moway,

            } else if (node.getType() == EchoProtocolManager.SIMPLE_NODE) {
                //Check for undelivered messages.
                if (DTSManager.getInstance().getMsgToDeliver().containsKey(node.getMyaddress())) {
                    System.out.println("Destination Found: " + IEEEAddress.toDottedHex(node.getMyaddress().longValue()));
                    if (!((Queue) DTSManager.getInstance().getMsgToDeliver().get(node.getMyaddress())).isEmpty()) {
                        //Deliver the messages.
                        DTSManager.getInstance().sendMessage(node.getMyaddress(), (Queue) DTSManager.getInstance().getMsgToDeliver().get(node.getMyaddress()));
                    }
                }
            }
        }
    }
}

Message Receiver Class

import com.sun.spot.io.j2me.radiogram.Radiogram;
import com.sun.spot.io.j2me.radiogram.RadiogramConnection;
import com.sun.spot.util.IEEEAddress;
import com.sun.spot.util.Utils;
import eu.fronts.moway.storage.Messages;

import javax.microedition.io.Connector;
import java.io.IOException;


public class Receiver extends Thread {

    private boolean isEnabled;

    /**
     * Default Constructor.
     */
    public Receiver() {
        super();
        isEnabled = true;
    }

    /**
     * If this thread was constructed using a separate
     * <code>Runnable</code> run object, then that
     * <code>Runnable</code> object's <code>run</code> method is called;
     * otherwise, this method does nothing and returns.
     * <p/>
     * Subclasses of <code>Thread</code> should override this method.
     *
     * @see #start()
     * @see #stop()
     * @see #Thread(ThreadGroup, Runnable, String)
     */
    public void run() {
        RadiogramConnection rgConnection = null;

        Utils.sleep(1000);
        try {
            rgConnection = (RadiogramConnection) Connector.open("radiogram://:" + DTSManager.DTSPORT);

        } catch (IOException e) {
            System.out.println("Could not open radiogram receiver connection");
            e.printStackTrace();
            return;
        }

        while (isEnabled) {
            try {
                // We receive messages
                final Radiogram rg = (Radiogram) rgConnection.newDatagram(rgConnection.getMaximumLength());

                rg.reset();

                rgConnection.receive(rg);
                System.out.println("DTS Message Received: " + rg.getLength());
                //Message ID
                final byte messageid = rg.readByte();
                System.out.println(messageid);
                //Source
                final short source = rg.readShort();

                //Destination
                final short tmp = rg.readShort();
                final long destination = IEEEAddress.To64Bit(tmp);

                //Sequence Number
                final short seqNo = rg.readByte();

                //Payload Size
                final short pldSize = rg.readByte();

                //Payload
                final byte[] payload = new byte[rg.getLength()];
                rg.resetRead();
                rg.readFully(payload, 0, rg.getLength());

                //Initialize the message
                final Messages msg = new Messages(messageid, source, destination, seqNo, pldSize, payload);

                //Add this message to DTS.
                DTSManager.getInstance().addMessage(new Long(msg.getDestination()), msg);

            } catch (final IOException e) {
                System.out.println("Nothing received");
                e.printStackTrace();
            }
        }
    }

    /**
     * Stop thread execution
     */
    public void disable() {
        isEnabled = false;
    }
}

DTS Manager Class

import com.sun.spot.io.j2me.radiogram.RadiogramConnection;
import com.sun.spot.util.IEEEAddress;
import com.sun.spot.util.Queue;
import com.sun.spot.util.Utils;
import eu.fronts.moway.communication.echoprotocol.EchoProtocolManager;
import eu.fronts.moway.mowaycontroller.Controller;
import eu.fronts.moway.storage.Messages;
import eu.fronts.moway.ui.LEDManager;
import eu.fronts.moway.util.HashMap;
import eu.fronts.moway.util.Node;
import eu.fronts.moway.util.Observable;
import eu.fronts.moway.util.Observer;

import javax.microedition.io.Connector;
import javax.microedition.io.Datagram;
import java.io.IOException;
import java.util.Vector;

/**
 * DTSManager observes the EchoProtocolManager.
 */
public final class DTSManager implements Observer {

    /**
     * The Radiogram Port to transmit messages.
     */
    public static final int DTSPORT = 105;

    /**
     * Unique instance of this class.
     */
    private static DTSManager thisInstance;

    /**
     * The Radiogram Connection.
     */
    private RadiogramConnection dgConnection = null;

    /**
     * Instance of Message Sender.
     */
    private final MessageSender msgSender;

    /**
     * Messages Delivered to destination. Key: Destination, Value: Vector with messages.
     */
    private final HashMap msgDelivered;

    /**
     * Undelivered messages.Key: Destination, Value: Messages with messages.
     */
    private final HashMap msgToDeliver;

    /**
     * Buffer for the Echo Notifications.
     */
    private final Queue notificationBuffer;

    /**
     * The Message Receiver Thread.
     */
    private final Receiver receiver;

    /**
     * Counts the undelivered Messages.
     */
    private int msgCounter;

    /**
     * Counts the received messages.
     */
    private int receivedMessages;

    /**
     * Counts the delivered messages.
     */
    private int deliveredMessages;

    /**
     * Creates a new instance of DTSManager.
     */
    private DTSManager() {
        //Observer the Echo Protocol.
        EchoProtocolManager.getInstance().addObserver(this);

        msgCounter = 0;
        receivedMessages = 0;
        deliveredMessages = 0;

        //Initialize the HashMaps.
        msgDelivered = new HashMap();
        msgToDeliver = new HashMap();

        //Initialize the DTS message Sender.
        notificationBuffer = new Queue();
        msgSender = new MessageSender(notificationBuffer);
        msgSender.start();

        //Initialize the DTS message Receiver,
        receiver = new Receiver();
        receiver.start();
    }

    /**
     * getInstance should be used each time access to the DTSManager instance is needed.
     *
     * @return the DTSManager instance
     */
    public static DTSManager getInstance() {
        synchronized (DTSManager.class) {
            // Check if an instance has already been created
            if (thisInstance == null) {
                // Create a new instance if not
                thisInstance = new DTSManager();
            }
        }
        // Return the DTSManager instance
        return thisInstance;
    }

    /**
     * Return the delivered messages.
     *
     * @return the returned HashMap
     */
    public synchronized HashMap getMsgDelivered() {
        return msgDelivered;
    }

    /**
     * Return the undelivered messages.
     *
     * @return the returned HashMap
     */
    public synchronized HashMap getMsgToDeliver() {
        return msgToDeliver;
    }

    /**
     * Open Connection to a specific Node and deliver saved messages.
     *
     * @param destination the destination address
     * @param message     The Messages to be delivered.
     */
    public void sendMessage(final Long destination, final Queue message) {
        System.out.println("Vector size: " + message.size());
        Controller.getInstance().disableAutoMode();
        Controller.getInstance().stopRobot();

        try {
            final long delayTime = 300;
            // Creates a Unicast Datagram Connection
            dgConnection = (RadiogramConnection) Connector.open("radiogram://" + IEEEAddress.toDottedHex(destination.longValue()) + ":" + DTSPORT);
            System.out.println("radiogram://" + IEEEAddress.toDottedHex(destination.longValue()) + ":" + DTSPORT);
            dgConnection.setMaxBroadcastHops(1);
            int i = 0;
            while (!message.isEmpty()) {
                System.out.println(i);
                i++;
                // Creates a Datagram using the above Connection
                final Datagram datagram = dgConnection.newDatagram(dgConnection.getMaximumLength());

                // Clean the Datagram
                datagram.reset();

                final Messages msg = (Messages) message.get(i);

                datagram.write(msg.getPayload(), 0, msg.getPayload().length);
                System.out.println(msg.getPayload().length);
                /*datagram.writeShort(msg.getSource());
                datagram.writeShort((short) msg.getDestination());
                datagram.write((byte) msg.getSequenceNumber());
                datagram.write((byte) msg.getPayloadSize());
                datagram.write(msg.getPayload());*/

                // Send the datagram
                try {
                    // Send the message
                    dgConnection.send(datagram);
                    System.out.println(datagram.getLength());
                    System.out.println("Message Send");

                    /* if (msgDelivered.containsKey(destination)) {

                        //Queue is full. Remove the 10 first messages.
                        if (((Vector) msgDelivered.get(destination)).size() > 50) {
                            for (int index = 0; index < 10; index++) {
                                ((Vector) msgDelivered.get(destination)).removeElementAt(index);
                            }
                        }
                        // Add message to delivered Vector.
                        ((Vector) msgDelivered.get(destination)).addElement(message.elementAt(i));

                    } else {
                        final Vector tmp = new Vector();
                        tmp.addElement(msg);
                        // Add message to delivered Vector.
                        msgDelivered.put(new Long(msg.getDestination()), tmp);
                    }*/

                    // Add message to delivered Vector.
                    //((Vector) msgToDeliver.get(destination)).removeElement(message.elementAt(i));

                    msgCounter--;
                    deliveredMessages++;
                    LEDManager.getInstance().setOnLeds(msgCounter);
                } catch (final IOException e) {
                    e.printStackTrace();
                }

                Utils.sleep(delayTime);
            }

            dgConnection.close();
        } catch (final IOException e) {
            //Error Delivering the message
            e.printStackTrace();
            try {
                //Close the COnnection
                dgConnection.close();
            } catch (final IOException e1) {
                e1.printStackTrace();
            }
        }

        Controller.getInstance().enableAutoMode();
    }

    /**
     * Add message to undelivered messages.
     *
     * @param destination the message destination
     * @param msg         the message
     */
    public void addMessage(final Long destination, final Messages msg) {

        System.out.println("New message added to DTS with Dest: " + IEEEAddress.toDottedHex(destination.longValue())
                + "\n\t from " + IEEEAddress.toDottedHex(msg.getSource()) + "---" + destination);

        if (msgToDeliver.containsKey(destination) /*&& ((Vector) msgToDeliver.get(destination)).size() < 50 &&
                !((Vector) msgToDeliver.get(destination)).contains(msg)*/) {

            ((Queue) msgToDeliver.get(destination)).put(msg);

            System.out.println("More than one messages to deliver");
        } else {
            final Queue messages = new Queue();
            messages.put(msg);

            msgToDeliver.put(destination, messages);
            System.out.println("First message");
        }
        msgCounter++;
        receivedMessages++;
        LEDManager.getInstance().setOnLeds(msgCounter);
    }

    /**
     * Invoked when an <code>Observable</code> object notifies the <code>Observer</code>.
     *
     * @param observable the <code>Observable</code> object which notified the <code>Observer</code>
     * @param arg        the changed object
     */
    public void update(final Observable observable, final Object arg) {

        if (observable instanceof EchoProtocolManager && arg instanceof Node) {

            //Echo notification message.
            // New neighbor found.
            final Node node = (Node) arg;

            //Pass the message to the Event Sender.
            notificationBuffer.put(node);
        }
    }

    /**
     * Returns the total received messages.
     *
     * @return the number of messages
     */
    public int getReceivedMessages() {
        return receivedMessages;
    }

    /**
     * Returns the delivered messages.
     *
     * @return the number o messages
     */
    public int getDeliveredMessages() {
        return deliveredMessages;
    }
}

Echo Protocol Manager Class

import com.sun.spot.peripheral.NoRouteException;
import com.sun.spot.peripheral.radio.ILowPan;
import com.sun.spot.peripheral.radio.mhrp.interfaces.IMHEventListener;
import com.sun.spot.peripheral.radio.routing.RouteInfo;
import com.sun.spot.peripheral.radio.routing.RouteTable;
import com.sun.spot.peripheral.radio.routing.interfaces.RouteEventClient;
import com.sun.spot.service.IService;
import com.sun.spot.util.IEEEAddress;
import eu.fronts.moway.communication.echoprotocol.broadcaster.Broadcaster;
import eu.fronts.moway.communication.echoprotocol.broadcaster.BroadcasterInvStab;
import eu.fronts.moway.communication.echoprotocol.broadcaster.BroadcasterStab;
import eu.fronts.moway.communication.echoprotocol.receiver.Receiver;
import eu.fronts.moway.util.Node;
import eu.fronts.moway.util.Observable;
import eu.fronts.moway.util.SortedList;


/**
 * Implements the Echo Protocol. Every node listens for beacons form it's neighbours and creates a list
 * of it's neighbours. Runs in two modes (Unidirectional, Bidirectional).
 */
public class EchoProtocolManager extends Observable implements com.sun.spot.peripheral.radio.routing.interfaces.IRoutingManager {

    /**
     * ECHO PORT.
     */
    public static final short ECHO_PORT = 110;

    /**
     * Expiration Ttime.
     */
    public static final long EXPIRATION_TIME = 3000;

    /**
     * Beacon Interval.
     */
    public static final long BEACON_INTERVAL = 1000;

    /**
     * Cleaning Delta.
     */
    public static final long CLEAN_DELTA = 50;

    /**
     * Echo mode. 0 uni directional.
     */
    public static final short UNI_DIRECTIONAL = 0;

    /**
     * Echo mode :
     */
    public static final short BI_DIRECTIONAL = 1;

    public static final short GATEWAY = 0;

    public static final short SIMPLE_NODE = 42;

    public static final Long DISCONNECTED = new Long(-1);

    public static final boolean LQI_ENABLED = false;

    public static int LQI_THRESHOLD_MIN = 100;

    public static int LQI_THRESHOLD_MAX = 100;

    public static final short STABILITY_DISABLED = 0;

    public static final short STABILITY_ENABLED = 1;

    public static final short STABILITY_INV = 2;

    public static final short STABILITY = 0;

    /**
     * the type
     */
    private short type;

    private Node gateway;

    private Long myAddress;

    private short echo_mode;

    private static EchoProtocolManager instance = null;

    private SortedList uni_neighs;

    private SortedList bi_neighs;

    private static ILowPan lowpan;

    private int state;

    private static String name = "EchoProtocolManager";

    public static final short STABILITY_THRESHOLD = 50;

    /**
     * Constructs a new EchoProtocolManager.
     * Calls all services that need to run.
     */
    private EchoProtocolManager() {
        uni_neighs = new SortedList();
        bi_neighs = new SortedList();

        type = SIMPLE_NODE;
        echo_mode = BI_DIRECTIONAL;
        gateway = new Node();
        gateway.setMyaddress(DISCONNECTED);
        Receiver.getInstance();

        if (EchoProtocolManager.STABILITY == EchoProtocolManager.STABILITY_DISABLED) {
            Broadcaster.getInstance();
        } else if (EchoProtocolManager.STABILITY == EchoProtocolManager.STABILITY_ENABLED) {
            BroadcasterStab.getInstance();
        } else if (EchoProtocolManager.STABILITY == EchoProtocolManager.STABILITY_INV) {
            BroadcasterInvStab.getInstance();
        }


        System.out.println("Echo Protocol started");
    }

    /**
     * Updates Neighbour list with new node. Runs when a new beacon has been detected.
     *
     * @param node Represents the node of the beacon that was detected.
     */
    public void updateNeighs(final Node node) {
        if (node.getType() == GATEWAY) {
            if (echo_mode == UNI_DIRECTIONAL) {
                if (gateway.getMyaddress() == DISCONNECTED) {
                    //System.out.println("Inserted Gateway with address: " + IEEEAddress.toDottedHex((long) node.getMyaddress().longValue()));

                    gateway = node;
                } else if (gateway.getMyaddress() == node.getMyaddress()) {
                    gateway.setExpiryTime(node.getExpiryTime());
                }
            } else if (echo_mode == BI_DIRECTIONAL) {
                uni_neighs.insertElement(node);
                if (node.getMode() == BI_DIRECTIONAL) {
                    if (gateway.getMyaddress() == DISCONNECTED) {
                        //   System.out.println("Inserted Gateway with address: " + IEEEAddress.toDottedHex((long) node.getMyaddress().longValue()));
                        gateway = node;
                    } else if (gateway.getMyaddress() == node.getMyaddress()) {
                        gateway.setExpiryTime(node.getExpiryTime());
                    }
                }
            }
        } else if (node.getType() == SIMPLE_NODE) {
            if (echo_mode == BI_DIRECTIONAL) {

                if (!uni_neighs.insertElement(node)) {
                    System.out.println("NEW_NB;" + IEEEAddress.toDottedHex(node.getMyaddress().longValue()) + ";Time;" +  

System.currentTimeMillis() + ";Node;" + IEEEAddress.toDottedHex(myAddress.longValue()) + ";neighbors;" + uni_neighs.getSize() + ";bd_neighbors;" + bi_neighs.getSize() + ";");
                }
                //bi_neighs is subset of uni_neighs and stores neighs that can listen to us
                if (node.getMode() == BI_DIRECTIONAL) {
                    if (!bi_neighs.insertElement(node)) {
                        System.out.println("NEW_NB_BIDI;" + IEEEAddress.toDottedHex(node.getMyaddress().longValue()) + ";Time;" +  

System.currentTimeMillis() + ";Node;" + IEEEAddress.toDottedHex(myAddress.longValue()) + ";neighbors;" + uni_neighs.getSize() + ";bd_neighbors;" + bi_neighs.getSize() + ";");
                    }
                    this.setChanged();
                    this.notifyObservers(node);
                }
            } else if (echo_mode == UNI_DIRECTIONAL) {
                //we suppose that every neighbour is bidirectional so we update only bi_neighs list
                if (!bi_neighs.insertElement(node)) {
                    // System.out.println("Inserted Node with address: " + IEEEAddress.toDottedHex(node.getMyaddress().longValue()) + " " + 

bi_neighs.getSize());
                    this.setChanged();
                    this.notifyObservers(node);
                }
            }
        }
    }

    /**
     * Check if any neighbour is not broadcasting and remove it from the list.
     */
    public void cleanDeadNeighs() {

        //clean unidirectional neighbours
        if (uni_neighs.getFirstElement() != null) {
            while (uni_neighs.getFirstElement().getExpiryTime() < (System.currentTimeMillis() + CLEAN_DELTA)) {
                final Node tmp = uni_neighs.getFirstElement();
                uni_neighs.removeFirstElement();
                System.out.println("DROPPED_NB;" + IEEEAddress.toDottedHex(tmp.getMyaddress().longValue()) + ";Time;" + System.currentTimeMillis() + ";Node;" + IEEEAddress.toDottedHex(myAddress.longValue()) + ";neighbors;" + uni_neighs.getSize() + ";bd_neighbors;" + bi_neighs.getSize() + ";");
                if (uni_neighs.getFirstElement() == null)
                    break;
            }
        }

        //clean bidirectional neighbours
        if (bi_neighs.getFirstElement() != null) {
            while (bi_neighs.getFirstElement().getExpiryTime() < (System.currentTimeMillis() + CLEAN_DELTA)) {
                final Node tmp = bi_neighs.getFirstElement();
                bi_neighs.removeFirstElement();
                System.out.println("LOST_NB_BIDI;" + IEEEAddress.toDottedHex(tmp.getMyaddress().longValue()) + ";Time;" +  

 System.currentTimeMillis() + ";Node;" + IEEEAddress.toDottedHex(myAddress.longValue()) + ";neighbors;" + uni_neighs.getSize() +  

";bd_neighbors;" + bi_neighs.getSize() + ";");
                if (bi_neighs.getFirstElement() == null)
                    break;
            }
        }

        //clean gateway if connection lost
        if (gateway.getExpiryTime() < (System.currentTimeMillis() + CLEAN_DELTA)
                && gateway.getMyaddress() != DISCONNECTED) {
            System.out.println("Removed gateway: " + IEEEAddress.toDottedHex(gateway.getMyaddress().longValue()));
            gateway.setMyaddress(DISCONNECTED);
        }
    }

    /**
     * Initialization of manager.
     *
     * @param address address used by this LowPan layer
     * @param iLowPan a reference to the lowpan layer
     */
    public void initialize(long address, ILowPan iLowPan) {
        System.out.println("Initialize..");
        this.myAddress = new Long(address);
        this.lowpan = iLowPan;
    }

    /**
     * retrieve routing information for a destination address.
     *
     * @param address neighbour's address
     * @return returns a route info object where nexthop is the destination and is 1 hop away if address is in
     *         routing table. else returns No Route
     */
    public RouteInfo getRouteInfo(long address) {
        final RouteInfo info;
        if (bi_neighs.containsKey(new Long(address))) {
            info = new RouteInfo(address, address, 1);
        } else {
            info = new RouteInfo(address, -1, 0);
        }
        return info;
    }

    /**
     * lookup a route to this address.
     *
     * @param address          destination address
     * @param routeEventClient client to be called back with the routing information
     * @param o                a key that uniquely identifies this request/client
     * @return The answer will be that the destination address
     *         is exactly 1 hop away if the address is in the routing table. Else answer will be that there is no route
     *         to the destination address                `
     * @throws NoRouteException
     */
    public boolean findRoute(long address, RouteEventClient routeEventClient, Object o) throws NoRouteException {
        final RouteInfo info;
        if (bi_neighs.containsKey(new Long(address))) {
            info = new RouteInfo(address, address, 1);
        } else {
            info = new RouteInfo(address, -1, 0);
        }
        routeEventClient.routeFound(info, o);
        return true;
    }

    /**
     * This method returns a snapshot of the routing table
     *
     * @return an object containing a snapshot of the routing table
     */
    public RouteTable getRoutingTable() {
        RouteTable rt = new RouteTable();
        bi_neighs.initEnum();
        while (bi_neighs.hasMoreElements()) {
            final Node tmp = (Node) bi_neighs.nextElement();
            final RouteInfo route = new RouteInfo(tmp.getMyaddress().longValue(),
                    tmp.getMyaddress().longValue(), 1);
            rt.addEntry(route);
        }
        return rt;
    }

    /**
     * Create an array with neighbour addresses as long and return it
     *
     * @return long[] with neighs addresses
     */
    public long[] getSemiNeighAddr() {
        final long[] neighs = new long[uni_neighs.getSize()];
        uni_neighs.initEnum();
        for (int i = 0; i < neighs.length; i++) {
            if (uni_neighs.hasMoreElements()) {
                neighs[i] = ((Node) uni_neighs.nextElement()).getMyaddress().longValue();
            } else {
                neighs[i] = 0;
            }
        }
        return neighs;
    }

    /**
     * Nodes are always 1 hop away.  Mark a node unreachable if it isn't
     *
     * @param originator  node that requested the route
     * @param destination route destination originator
     * @return always returns true
     */
    public boolean invalidateRoute(long originator, long destination) {
        bi_neighs.removeElement(new Long(destination));
        return true;
    }

    /**
     * registers a listener for routing messages.  EchoProtocol hop has no messages so this
     * is a NO OP.
     *
     * @param imhEventListener event listener for callbacks
     */
    public void registerEventListener(IMHEventListener imhEventListener) {
    }

    /**
     * deregisters a listener for routing messages.  EchoProtocol has no messages so this
     * is a NO OP.
     *
     * @param imhEventListener the listener to remove
     */
    public void deregisterEventListener(IMHEventListener imhEventListener) {
    }

    /**
     * Registers an event listener that is notified when this node
     * initiates/receives supported route events
     *
     * @param imhEventListener object that is notified when route events occur
     */
    public void addEventListener(IMHEventListener imhEventListener) {

    }

    /**
     * Remove the specified event listener that was registered for route events
     *
     * @param imhEventListener object that is notified when route events occur
     */
    public void removeEventListener(IMHEventListener imhEventListener) {
    }

    public boolean start() {
        state = IService.RUNNING;
        return true;
    }

    public boolean stop() {
        Broadcaster.getInstance().disable();
        Receiver.getInstance().disable();
        state = IService.STOPPED;
        return true;
    }

    public boolean pause() {
        return stop();
    }

    public boolean resume() {
        return start();
    }

    public int getStatus() {
        return state;
    }

    public boolean isRunning() {
        return (state == IService.RUNNING);
    }

    public String getServiceName() {
        return name;
    }

    public void setServiceName(String s) {
        name = s;
    }

    public boolean getEnabled() {
        return false;
    }

    public void setEnabled(boolean b) {
    }

    /**
     * @return EchoProtocolManager instance of this singleton
     */
    public static EchoProtocolManager getInstance() {
        synchronized (EchoProtocolManager.class) {
            if (instance == null) {
                instance = new EchoProtocolManager();
            }
        }
        return instance;
    }


    public short getType() {
        return type;
    }

    public Long getMyAddress() {
        return myAddress;
    }

    public short getEcho_mode() {
        return echo_mode;
    }

    public Long getGatewayAddress() {
        return gateway.getMyaddress();
    }

    public void setEcho_mode(short echo_mode) {
        this.echo_mode = echo_mode;
    }

    public int getNeighSize() {
        return bi_neighs.getSize();
    }

    public SortedList getUnidirectionalNeighs() {
        return uni_neighs;
    }

    public SortedList getBidirectionalNeighs() {
        return bi_neighs;
    }

    /**
     * @return SortedList[] with neighs
     */
    public SortedList getUniNeighs() {
        final SortedList tmpneighs = new SortedList();
        uni_neighs.initEnum();
        while (uni_neighs.hasMoreElements()) {
            tmpneighs.insertElement((Node) uni_neighs.nextElement());
        }
        return tmpneighs;
    }

    /**
     * @return SortedList[] with neighs
     */
    public SortedList getBiNeighs() {
        final SortedList tmpneighs = new SortedList();
        bi_neighs.initEnum();
        while (bi_neighs.hasMoreElements()) {
            tmpneighs.insertElement((Node) bi_neighs.nextElement());
        }
        return tmpneighs;
    }

    public void cleanStabilityCounters() {
        final SortedList unis = getUniNeighs();
        final SortedList bis = getBiNeighs();
        unis.initEnum();
        bis.initEnum();
        long now = System.currentTimeMillis();

        while (unis.hasMoreElements()) {
            final Node node = unis.nextElement();
            if (now - (node.getExpiryTime() - (EXPIRATION_TIME)) > (BEACON_INTERVAL + CLEAN_DELTA)) {
                node.setAssocCounter(0);
                uni_neighs.insertElement(node);
            }
        }
        while (bis.hasMoreElements()) {
            final Node node = bis.nextElement();
            if (now - (node.getExpiryTime() - (EXPIRATION_TIME)) > (BEACON_INTERVAL + CLEAN_DELTA)) {
                node.setAssocCounter(0);
                bi_neighs.insertElement(node);
            }
        }
    }

}
Edit - History - Print - Recent Changes - Search
Page last modified on November 20, 2012, at 09:29 PM