package lejos.pc.comm;
import javax.microedition.io.*;
import javax.bluetooth.*;
import java.io.*;
import java.util.Vector;
import java.util.Enumeration;
/**
* Implementation of NXTComm using the Bluecove libraries
* on Microsoft Windows.
*
* Should not be used directly - use NXTCommFactory to create
* an appropriate NXTComm object for your system and the protocol
* you are using.
*
*/
public class NXTCommBluecove implements NXTComm, DiscoveryListener {
private static Vector<RemoteDevice> devices;
private static Vector<NXTInfo> nxtInfos;
private StreamConnection con;
private OutputStream os;
private InputStream is;
private NXTInfo nxtInfo;
public NXTInfo[] search(String name, int protocol) throws NXTCommException {
devices = new Vector<RemoteDevice>();
nxtInfos = new Vector<NXTInfo>();
if ((protocol & NXTCommFactory.BLUETOOTH) == 0)
return new NXTInfo[0];
synchronized (this) {
try {
LocalDevice.getLocalDevice().getDiscoveryAgent().startInquiry(
DiscoveryAgent.GIAC, this);
try {
wait();
} catch (InterruptedException e) {
System.err.println(e.getMessage());
}
} catch(Throwable t) {
//System.err.println(e.getMessage());
throw new NXTCommException("Bluetooth stack not detected",t);
}
}
for (Enumeration<RemoteDevice> enum_d = devices.elements(); enum_d.hasMoreElements();) {
RemoteDevice d = enum_d.nextElement();
try {
nxtInfo = new NXTInfo();
nxtInfo.name = d.getFriendlyName(false);
if (nxtInfo.name == null || nxtInfo.name.length() == 0)
nxtInfo.name = "Unknown";
nxtInfo.deviceAddress = d.getBluetoothAddress();
nxtInfo.protocol = NXTCommFactory.BLUETOOTH;
if (name == null || name.equals(nxtInfo.name))
nxtInfos.addElement(nxtInfo);
else
continue;
System.out.println("Found: " + nxtInfo.name);
// We want additional attributes, ServiceName (0x100),
// ServiceDescription (0x101) and ProviderName (0x102).
int[] attributes = { 0x100, 0x101, 0x102 };
UUID[] uuids = new UUID[1];
uuids[0] = new UUID("1101", true); // Serial Port
synchronized (this) {
try {
LocalDevice.getLocalDevice().getDiscoveryAgent()
.searchServices(attributes, uuids, d, this);
try {
wait();
} catch (InterruptedException e) {
System.err.println(e.getMessage());
}
} catch (BluetoothStateException e) {
System.err.println(e.getMessage());
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.err.println(e.getMessage());
}
} catch (IOException e) {
System.err.println(e.getMessage());
}
}
NXTInfo[] nxts = new NXTInfo[nxtInfos.size()];
for (int i = 0; i < nxts.length; i++)
nxts[i] = (NXTInfo) nxtInfos.elementAt(i);
return nxts;
}
public boolean open(NXTInfo nxt, int mode) throws NXTCommException {
if (mode == RAW) throw new NXTCommException("RAW mode not implemented");
// Construct URL if not present
if (nxt.btResourceString == null || nxt.btResourceString.length() < 5
|| !(nxt.btResourceString.substring(0, 5).equals("btspp"))) {
nxt.btResourceString = "btspp://"
+ stripColons(nxt.deviceAddress)
+ ":1;authenticate=false;encrypt=false";
}
try {
con = (StreamConnection) Connector.open(nxt.btResourceString);
os = con.openOutputStream();
is = con.openInputStream();
nxt.connectionState = (mode == LCP ? NXTConnectionState.LCP_CONNECTED : NXTConnectionState.PACKET_STREAM_CONNECTED);
return true;
} catch (IOException e) {
nxt.connectionState = NXTConnectionState.DISCONNECTED;
throw new NXTCommException("Open of " + nxt.name + " failed: " + e.getMessage());
}
}
public boolean open(NXTInfo nxt) throws NXTCommException
{
return open(nxt, PACKET);
}
public void close() throws IOException {
if (os != null)
os.close();
if (is != null)
is.close();
if (con != null)
con.close();
}
/**
* Sends a request to the NXT brick.
*
* @param message
* Data to send.
*/
public synchronized byte[] sendRequest(byte[] message, int replyLen)
throws IOException {
// length of packet (Least and Most significant byte)
// * NOTE: Bluetooth only.
int LSB = message.length;
int MSB = message.length >>> 8;
if (os == null)
return new byte[0];
// Send length of packet:
os.write((byte) LSB);
os.write((byte) MSB);
os.write(message);
os.flush();
if (replyLen == 0)
return new byte[0];
byte[] reply = null;
int length = -1;
if (is == null)
return new byte[0];
do {
length = is.read(); // First byte specifies length of packet.
} while (length < 0);
int lengthMSB = is.read(); // Most Significant Byte value
length = (0xFF & length) | ((0xFF & lengthMSB) << 8);
reply = new byte[length];
int len = is.read(reply);
if (len != replyLen) throw new IOException("Unexpected reply length");
return (reply == null) ? new byte[0] : reply;
}
public byte[] read() throws IOException {
int lsb = is.read();
if (lsb < 0) return null;
int msb = is.read();
if (msb < 0) return null;
int len = lsb | (msb << 8);
byte[] bb = new byte[len];
for (int i=0;i<len;i++) bb[i] = (byte) is.read();
return bb;
}
public int available() throws IOException {
return 0;
}
public void write(byte[] data) throws IOException {
os.write((byte)(data.length & 0xff));
os.write((byte)((data.length >> 8) & 0xff));
os.write(data);
os.flush();
}
public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
// System.out.println("Found Device, class: " +
// cod.getMajorDeviceClass() + "/" + cod.getMinorDeviceClass());
if (cod.getMajorDeviceClass() == 2048 && cod.getMinorDeviceClass() == 4)
devices.addElement(btDevice);
}
public synchronized void inquiryCompleted(int discType) {
// if (discType == INQUIRY_COMPLETED) System.out.println("Inquiry
// completed");
// else System.out.println("Inquiry Failed");
notifyAll();
}
public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
// System.out.println(servRecord.length + " service(s) discovered");
// Should only be one service on a NXT
if (servRecord.length != 1)
return;
nxtInfo.btResourceString = servRecord[0].getConnectionURL(
ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
// System.out.println("Setting url to : " + nxtInfo.btResourceString);
}
public synchronized void serviceSearchCompleted(int transID, int respCode) {
// System.out.println("Service search completed: respCode = " +
// respCode);
notifyAll();
}
public OutputStream getOutputStream() {
return new NXTCommOutputStream(this);
}
public InputStream getInputStream() {
return new NXTCommInputStream(this);
}
public String stripColons(String s) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c != ':') {
sb.append(c);
}
}
return sb.toString();
}
}