package communication;
import java.util.List;
import java.util.ArrayList;
import java.util.Enumeration;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.BluetoothStateException;
import lejos.nxt.comm.Bluetooth;
/**
* Identifies and provides information a device that can be communicated with.
*
* @author Erik Lagercrantz
*/
public class Node {
private static Node localNode = null;
/**
* @return A Node identifying the local device.
*/
public static Node localNode() {
if (localNode == null) {
try {
LocalDevice device = LocalDevice.getLocalDevice();
localNode = new Node(device);
} catch (BluetoothStateException e) {
System.out.println("Bluetooth state exception.");
}
}
return localNode;
}
/**
* @return A list of known nodes that have at some point been available for communication.
*/
public static List<Node> knownNodes() {
List<Node> nodes = new ArrayList<Node>();
Enumeration deviceEnumeration = Bluetooth.getKnownDevicesList().elements();
while (deviceEnumeration.hasMoreElements()) {
RemoteDevice device = (RemoteDevice)deviceEnumeration.nextElement();
nodes.add(new Node(device));
}
return nodes;
}
private Object device; // Should be of type RemoteDevice or LocalDevice
private int identifier;
/**
* Constructs a Node identifying a certain Bluetooth device.
* @param device The remote Bluetooth device information that the Node should represent.
*/
public Node(RemoteDevice device) {
this.device = device;
this.identifier = -1;
}
/**
* Constructs a Node identifying a local Bluetooth device.
* @param device The local Bluetooth device information that the Node should represent.
*/
public Node(LocalDevice device) {
this.device = device;
this.identifier = -1;
}
/**
* Constructs a Node representing a device with a certain identifier.
* @param identifier The identifier of the device.
*/
public Node(int identifier) {
this.device = null;
this.identifier = identifier;
}
/**
* @return True if the Node identifies the local device, otherwise false.
*/
public boolean isLocal() {
return this.device instanceof LocalDevice;
}
/**
* @return Device information for this Node, if the Node is a remote device.
*/
public RemoteDevice getRemoteDevice() {
if (this.device == null) updateDeviceUsingIdentifier();
return (RemoteDevice)this.device;
}
/**
* @return Device information for this Node, if the Node is the local device.
*/
public LocalDevice getLocalDevice() {
if (this.device == null) updateDeviceUsingIdentifier();
return (LocalDevice)this.device;
}
/**
* Queries the node for its current device name.
* @return The current device name of this Node.
*/
public String getUpdatedName() {
if (this.device == null) updateDeviceUsingIdentifier();
return Node.nameFromDevice(this.device, true);
}
/**
* Gets a cached device name of the node.
* @return A cached device name of this Node.
*/
public String getName() {
if (this.device == null) updateDeviceUsingIdentifier();
return Node.nameFromDevice(this.device, false);
}
/**
* Queries the node for its current identifier value.
* @return The current identifier of this Node.
*/
public int getUpdatedIdentifier() {
updateIdentifierUsingDevice(true);
return this.identifier;
}
/**
* Gets a cached identifier value of the node.
* @return A cached identifier of this Node.
*/
public int getIdentifier() {
if (this.identifier < 0) updateIdentifierUsingDevice(false);
return this.identifier;
}
/**
* Sets the identifier value of this Node from the cached device information.
* Optionally queries the node to update the device information first.
* @param updateName Flag determining if the device information should be updated first.
*/
protected void updateIdentifierUsingDevice(boolean updateName) {
String name = Node.nameFromDevice(this.device, updateName);
this.identifier = Node.identifierFromName(name);
if (identifier < 0) {
System.out.println("No device id in "+name+"!");
}
}
/**
* Tries to find device information that matches the identifier of this Node, and caches that information in this Node.
* The information is found by asking the system about known devices.
*/
protected void updateDeviceUsingIdentifier() {
String name = Node.nameFromIdentifier(this.identifier);
this.device = Node.deviceFromName(name);
if (this.device == null) {
System.out.println("Uknown device "+name+"!");
}
}
/**
* Transforms a standardized device name into an identifier value by looking for an integer value within the name.
* @param name The device name from which to extract an identifier.
* @return The identifier value extracted from the device name, or -1 if no identifier was found.
*/
protected static int identifierFromName(String name) {
int len = name.length();
for (int i = 0; i < len; i++) {
if (Character.isDigit(name.charAt(i)))
return Integer.parseInt(name.substring(i));
}
return -1;
}
/**
* Transforms an identifier value into a standardized device name.
* @param identifier The identifier value for wich to create a device name.
* @return The name corresponding to the given identifier value.
*/
protected static String nameFromIdentifier(int identifier) {
return "NXT" + identifier;
}
/**
* Gets the name of the device identified by a device information object, optionally querying the node for its current name first.
* @param device Information about the device for which to get the name.
* @param ask Flag determining if the device should be asked for its current name or not.
* @return
*/
protected static String nameFromDevice(Object device, boolean ask) {
if (device == null) return null;
if (device instanceof LocalDevice)
return ((LocalDevice)device).getFriendlyName();
else if (device instanceof RemoteDevice)
return ((RemoteDevice)device).getFriendlyName(ask);
return null;
}
/**
* Gets device information for a device with a certain name, if available.
* The information is found by asking the system about known devices.
* @param name The name of the device for which the get information.
* @return Information about a device with the given name.
*/
protected static Object deviceFromName(String name) {
if (name == null) return null;
try {
LocalDevice localDevice = LocalDevice.getLocalDevice();
if (localDevice.getFriendlyName() == name) {
return localDevice;
}
} catch (BluetoothStateException e) {
System.out.println("Bluetooth state exception.");
}
return Bluetooth.getKnownDevice(name);
}
/**
* @return The Bluetooth device class for toy robots.
*/
protected static byte[] toyRobotDeviceType() {
byte[] cod = {0,0,8,4}; // Toy, Robot
return cod;
}
}