package lejos.nxt.remote;
import java.io.*;
import java.util.ArrayList;
import lejos.nxt.comm.*;
/**
* Provides an API similar to the leJOS API for accessing
* motors, sensors etc. on a remote NXT accessed over
* Bluetooth using LCP.
*
*/
public class RemoteNXT {
private NXTCommand nxtCommand = new NXTCommand();
private NXTComm nxtComm;
public RemoteMotor A, B, C;
public RemoteBattery Battery;
public RemoteSensorPort S1, S2, S3, S4;
public RemoteNXT(String name, NXTCommConnector connector) throws IOException {
nxtComm = new NXTComm(connector);
boolean open = nxtComm.open(name, NXTConnection.LCP);
if (!open) throw new IOException("Failed to connect to " + name);
nxtCommand.setNXTComm(nxtComm);
A = new RemoteMotor(nxtCommand, 0);
B = new RemoteMotor(nxtCommand, 1);
C = new RemoteMotor(nxtCommand, 2);
Battery = new RemoteBattery(nxtCommand);
S1 = new RemoteSensorPort(nxtCommand, 0);
S2 = new RemoteSensorPort(nxtCommand, 1);
S3 = new RemoteSensorPort(nxtCommand, 2);
S4 = new RemoteSensorPort(nxtCommand, 3);
}
/**
* Get the name of the remote brick
*
* @return name of remote brick
*/
public String getBrickName() {
try {
DeviceInfo i = nxtCommand.getDeviceInfo();
return i.NXTname;
} catch (IOException ioe) {
return null;
}
}
/**
* Get the bluetooth address of the remote device
*
* @return address with hex pairs separated by colons
*/
public String getBluetoothAddress() {
try {
DeviceInfo i = nxtCommand.getDeviceInfo();
return i.bluetoothAddress;
} catch (IOException ioe) {
return null;
}
}
/**
* Get the free flash memory on the remote NXT
* @return Free memory remaining in FLASH
*/
public int getFlashMemory() {
try {
DeviceInfo i = nxtCommand.getDeviceInfo();
return i.freeFlash;
} catch (IOException ioe) {
return 0;
}
}
/**
* Return the (emulated) Lego firmware version on the remote NXT
*
* @return <major>.<minor>
*/
public String getFirmwareVersion() {
try {
FirmwareInfo f = nxtCommand.getFirmwareVersion();
return f.firmwareVersion;
} catch (IOException ioe) {
return null;
}
}
/**
* Return LCP protocol version
*
* @return <major>.<minor>
*/
public String getProtocolVersion() {
try {
FirmwareInfo f = nxtCommand.getFirmwareVersion();
return f.protocolVersion;
} catch (IOException ioe) {
return null;
}
}
/**
* Deletes all user programs and data in FLASH memory
* @return zero for success
*/
public byte deleteFlashMemory() {
try {
return nxtCommand.deleteUserFlash();
} catch (IOException ioe) {
return -1;
}
}
/**
* Returns a list of files on NXT brick.
* @param searchCriteria "*.*" or [FileName].* or or *.[Extension] or [FileName].[Extension]
* @return An array on file names, or NULL if nothing found.
*/
// This method could provide file sizes by returning FileInfo objects
// instead. It's simpler for users to return fileNames.
public String [] getFileNames(String searchCriteria) {
try {
ArrayList<String> names = new ArrayList<String>();
FileInfo f = nxtCommand.findFirst(searchCriteria);
if(f == null)
return null;
do {
names.add(f.fileName);
if(f != null)
nxtCommand.closeFile(f.fileHandle); // According to protocol, must be closed when done with it.
f = nxtCommand.findNext(f.fileHandle);
} while (f != null);
String [] returnArray = new String [names.size()];
for(int i=0;i<names.size();i++) {
returnArray[i] = names.get(i);
}
return returnArray;
} catch (IOException ioe) {
return null;
}
}
/**
* Returns a list of all files on NXT brick.
* @return An array on file names, or NULL if no files found.
*/
public String [] getFileNames() {
return getFileNames("*.*");
}
/**
* Delete a file from the NXT.
* @param fileName
* @return 0 = success
*/
public byte delete(String fileName) {
try {
return nxtCommand.delete(fileName);
} catch (IOException ioe) {
return -1;
}
}
/**
* Starts a Lego executable file on the NXT.
* @param fileName
* @return the status (0 = success)
*/
public byte startProgram(String fileName) {
try {
return nxtCommand.startProgram(fileName);
} catch (IOException ioe) {
return -1;
}
}
/**
* Stops the currently running Lego executable on the NXT.
* @return the status (0 = success)
*/
public byte stopProgram() {
try {
return nxtCommand.stopProgram();
} catch (IOException ioe) {
return -1;
}
}
/**
* Retrieves the file name of the Lego executable currently running on the NXT.
* @return the status (0 = success)
*/
public String getCurrentProgramName() {
try {
return nxtCommand.getCurrentProgramName();
} catch (IOException ioe) {
return null;
}
}
/**
* Send a message to a remote inbox
* @param message the message
* @param inbox the remote inbox
* @return the status (0 = success)
*/
public int sendMessage(byte [] message, int inbox) {
try {
return nxtCommand.messageWrite(message, (byte)inbox);
} catch (IOException ioe) {
return -1;
}
}
/**
* Get a message from a remote index to a local inbox
* @param remoteInbox the remote inbox
* @param localInbox the local inbox
* @param remove true iff the message should be removed from the remote inbox
* @return the message or null if mailed
*/
public byte [] receiveMessage(int remoteInbox, int localInbox, boolean remove) {
try {
return nxtCommand.messageRead((byte)remoteInbox, (byte)localInbox, remove);
} catch (IOException ioe) {
return null;
}
}
/**
* Play a tone on the remote NXT
* @param frequency the frequency of the tone
* @param duration the duration in milliseconds
* @return the status (0 = success)
*/
public int playTone(int frequency, int duration) {
try {
return nxtCommand.playTone(frequency, duration);
} catch (IOException ioe) {
return -1;
}
}
/**
* Plays a sound file on the remote NXT.
* @param fileName e.g. "Woops.wav"
* @param repeat true = repeat, false = play once.
* @return If you receive a non-zero number, the filename is probably wrong
* or the file is not uploaded to the remote NXT brick.
*/
public byte playSoundFile(String fileName, boolean repeat) {
try {
return nxtCommand.playSoundFile(fileName, repeat);
} catch (IOException ioe) {
return -1;
}
}
/**
* Plays a sound file on the remote NXT.
* @param fileName e.g. "Woops.wav"
* @return If you receive a non-zero number, the filename is probably wrong
* or the file is not uploaded to the remote NXT brick.
*/
public byte playSoundFile(String fileName) {
return playSoundFile(fileName, false);
}
/**
* Stops a sound file that has been playing/repeating on the remote NXT.
* @return Error code.
*/
public int stopSoundPlayback() {
try {
return nxtCommand.stopSoundPlayback();
} catch (IOException ioe) {
return -1;
}
}
/**
* Close the connection to the remote NXT
*/
public void close() {
try {
if (nxtCommand.isOpen()) {
nxtCommand.close();
}
} catch (IOException e) {}
}
// Consider using String instead of File?
public byte upload(String fileName) {
// FIRST get data from file
byte [] data;
byte success;
File localSource = new File(fileName);
try {
FileInputStream in = new FileInputStream(localSource);
data = new byte[(int) localSource.length()];
in.read(data);
in.close();
} catch (IOException ioe) {
return -1;
}
// Now send the data to the NXT
try {
byte handle = nxtCommand.openWrite(localSource.getName(), data.length);
success = nxtCommand.writeFile(handle, data);
nxtCommand.closeFile(handle);
} catch (IOException ioe) {
return -1;
}
return success;
}
/**
* Download a file from the remote NXT.
*
* @param fileName The name of the file on the NXT, including filename extension.
* @return The file data, as an array of bytes. If there is a problem, the array will
* contain one byte with the error code.
*/
public byte [] download(String fileName) {
byte [] data;
try {
FileInfo finfo = nxtCommand.openRead(fileName);
if(finfo.status != 0) { // Return error message
data = new byte[1];
data[0] = finfo.status;
return data;
}
data = nxtCommand.readFile(finfo.fileHandle, finfo.fileSize);
nxtCommand.closeFile(finfo.fileHandle);
} catch (IOException ioe) {
return null;
}
return data;
}
/**
* Download a file from the NXT and save it to a file.
* @param fileName
* @param destination Where the file will be saved.
* @return Error code.
*/
public byte download(String fileName, File destination) {
byte [] data = download(fileName);
File fullFile = destination;
try {
if (fullFile.exists()) fullFile.delete();
if (fullFile.createNewFile()) {
FileOutputStream out = new FileOutputStream(fullFile);
out.write(data);
out.close();
}
} catch (IOException e) {
return -1;
}
return 0;
}
}