package javax.bluetooth;
import lejos.nxt.comm.Bluetooth;
import java.util.Vector;
/**
* The <code>DiscoveryAgent</code> class provides methods to perform device
* discovery (but not service discovery in leJOS NXJ). A local device must have only one
* <code>DiscoveryAgent</code> object. This object must be retrieved by a call
* to <code>getDiscoveryAgent()</code> on the <code>LocalDevice</code>
* object.
*
* The three service methods normally in the DiscoveryAgent class such as searchServices()
* are not included because the Lego NXT brick only allows one service: SPP (Serial Port
* Profile). It would waste memory to implement the service methods considering they are not
* really functional.
*
* <H3>Device Discovery</H3>
*
* There are two ways to discover devices. First, an application may use
* <code>startInquiry()</code> to start an inquiry to find devices in
* proximity to the local device. Discovered devices are returned via the
* <code>deviceDiscovered()</code> method of the interface
* <code>DiscoveryListener</code>. The second way to discover devices is via
* the <code>retrieveDevices()</code> method. This method will return devices
* that have been discovered via a previous inquiry or devices that are
* classified as pre-known. (Pre-known devices are those devices that are
* defined in the Bluetooth Control Center as devices this device frequently
* contacts.) The <code>retrieveDevices()</code> method does not perform an
* inquiry, but provides a quick way to get a list of devices that may be in the
* area.
*
* WARNING: If a device is found that has not yet been paired with the NXT brick, the name
* field of RemoteDevice will be blank. Make sure to pair your devices through the leJOS
* NXJ Bluetooth menu on your NXT.
*
* @author BB
* @version 1.0 January 17, 2009
*
*/
public class DiscoveryAgent {
/**
* Takes the device out of discoverable mode.
* <P>
* The value of <code>NOT_DISCOVERABLE</code> is 0x00 (0).
*/
public static final int NOT_DISCOVERABLE = 0;
/**
* The inquiry access code for General/Unlimited Inquiry Access Code (GIAC).
* This is used to specify the type of inquiry to complete or respond to.
* <P>
* The value of <code>GIAC</code> is 0x9E8B33 (10390323). This value is
* defined in the Bluetooth Assigned Numbers document.
* @see #startInquiry
*/
public static final int GIAC = 0x9E8B33;
/**
* The inquiry access code for Limited Dedicated Inquiry Access Code (LIAC).
* This is used to specify the type of inquiry to complete or respond to.
* <P>
* The value of <code>LIAC</code> is 0x9E8B00 (10390272). This value is
* defined in the Bluetooth Assigned Numbers document.
* @see #startInquiry
*/
public static final int LIAC = 0x9E8B00;
/**
* Used with the <code>retrieveDevices()</code> method to return those
* devices that were found via a previous inquiry. If no inquiries have been
* started, this will cause the method to return <code>null</code>.
* <P>
* The value of <code>CACHED</code> is 0x00 (0).
*
* @see #retrieveDevices
*/
public static final int CACHED = 0x00;
/**
* Used with the <code>retrieveDevices()</code> method to return those
* devices that are defined to be pre-known devices. Pre-known devices are
* specified in the BCC. These are devices that are specified by the user as
* devices with which the local device will frequently communicate.
* <P>
* The value of <code>PREKNOWN</code> is 0x01 (1).
*
* @see #retrieveDevices
*/
public static final int PREKNOWN = 0x01;
/**
* Use <code>LocalDevice.getDiscoveryAgent()</code> to get an object.
* Prevents user from creating their own <code>DiscoveryAgent</code> object.
*/
DiscoveryAgent() {
}
/**
* Returns an array of Bluetooth devices that have either been found by the
* local device during previous inquiry requests or been specified as a
* pre-known device depending on the argument. The list of previously found
* devices is maintained by the implementation of this API. (In other words,
* maintenance of the list of previously found devices is an implementation
* detail.) A device can be set as a pre-known device in the Bluetooth
* Control Center.
*
* @param option
* <code>CACHED</code> if previously found devices should be
* returned; <code>PREKNOWN</code> if pre-known devices should
* be returned
*
* @return an array containing the Bluetooth devices that were previously
* found if <code>option</code> is <code>CACHED</code>; an
* array of devices that are pre-known devices if
* <code>option</code> is <code>PREKNOWN</code>;
* <code>null</code> if no devices meet the criteria
*
* @exception IllegalArgumentException
* if <code>option</code> is not <code>CACHED</code> or
* <code>PREKNOWN</code>
*/
public RemoteDevice[] retrieveDevices(int option) {
Vector v = null;
// TODO: For now it doesn't discern between CACHED or PREKNOWN as our
// leJOS Bluetooth stack doesn't support this?
// if(option == CACHED|option == PREKNOWN)
v = Bluetooth.getKnownDevicesList();
RemoteDevice [] rdlist = new RemoteDevice[v.size()];
for(int i=0;i<rdlist.length;i++)
rdlist[i] = (RemoteDevice)v.elementAt(i);
return rdlist;
}
/**
* Places the device into inquiry mode. The length of the inquiry is
* implementation dependent. This method will search for devices with the
* specified inquiry access code. Devices that responded to the inquiry are
* returned to the application via the method
* <code>deviceDiscovered()</code> of the interface
* <code>DiscoveryListener</code>. The <code>cancelInquiry()</code>
* method is called to stop the inquiry.
* NOTE: If a device is found that has not yet been paired with the NXT brick,
* the name field of RemoteDevice will be blank. Make sure to pair your devices
* through the leJOS NXJ Bluetooth menu on your NXT.
*
* @see #cancelInquiry
* @see #GIAC
* @see #LIAC
*
* @param accessCode
* the type of inquiry to complete
*
* @param listener
* the event listener that will receive device discovery events
*
* @return <code>true</code> if the inquiry was started;
* <code>false</code> if the inquiry was not started because the
* <code>accessCode</code> is not supported
*
* @exception IllegalArgumentException
* if the access code provided is not <code>LIAC</code>,
* <code>GIAC</code>, or in the range 0x9E8B00 to 0x9E8B3F
*
* @exception NullPointerException
* if <code>listener</code> is <code>null</code>
*
* @exception BluetoothStateException
* if the Bluetooth device does not allow an inquiry to be
* started due to other operations that are being performed
* by the device
*/
public boolean startInquiry(int accessCode, DiscoveryListener listener) throws BluetoothStateException {
final DiscoveryListener listy = listener;
if (listener == null) {
throw new NullPointerException();
}
if ((accessCode != LIAC) && (accessCode != GIAC) && ((accessCode < 0x9E8B00) || (accessCode > 0x9E8B3F))) {
throw new IllegalArgumentException("Invalid accessCode " + accessCode);
}
// TODO: In the Bluetooth.inquireNotify() method:
// 1. Should probably NOT be daemon threads
// 2. Spawn new thread for each notify? Need to check the JSR spec.
// Spawn a separate thread to notify so it returns immediately:
Thread t = new Thread() {
public void run() {
// !! 5 x 1.28 = 6.4 second timeout long enough? Seems good.
final int MY_TIME_OUT = 7;
// !! Only finds 10 devices max at present. Good enough?
final int MAX_DEVICES = 10;
Bluetooth.inquireNotify(MAX_DEVICES, MY_TIME_OUT, listy);
}
};
// Daemon thread?
t.setDaemon(true);
t.start();
return true;
}
/**
* Removes the device from inquiry mode.
* <P>
* An <code>inquiryCompleted()</code> event will occur with a type of
* <code>INQUIRY_TERMINATED</code> as a result of calling this method.
* After receiving this event, no further <code>deviceDiscovered()</code>
* events will occur as a result of this inquiry.
*
* <P>
*
* This method will only cancel the inquiry if the <code>listener</code>
* provided is the listener that started the inquiry.
*
* @param listener
* the listener that is receiving inquiry events
*
* @return <code>true</code> if the inquiry was canceled; otherwise
* <code>false</code> if the inquiry was not canceled or if the
* inquiry was not started using <code>listener</code>
*
* @exception NullPointerException
* if <code>listener</code> is <code>null</code>
*/
public boolean cancelInquiry(DiscoveryListener listener) {
if (listener == null) {
throw new NullPointerException();
}
// Return true/false value from Bluetooth class
return Bluetooth.cancelInquiry();
}
}