lejos.remote.nxt.LCP Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lejos-ev3-api Show documentation
Show all versions of lejos-ev3-api Show documentation
leJOS (pronounced like the Spanish word "lejos" for "far") is a tiny Java Virtual Machine. In 2013 it was ported to the LEGO EV3 brick.
The newest version!
package lejos.remote.nxt;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import lejos.hardware.BrickFinder;
import lejos.hardware.Button;
import lejos.hardware.Keys;
import lejos.hardware.Sound;
import lejos.hardware.motor.Motor;
import lejos.hardware.motor.NXTRegulatedMotor;
import lejos.hardware.port.Port;
import lejos.hardware.port.SensorPort;
import lejos.internal.io.Settings;
import lejos.internal.io.SystemSettings;
/**
*
* Implements the Lego Communication Protocol,
* with some extensions for lejos NXJ.
*
*/
public class LCP {
private static byte[] i2cBuffer = new byte[16];
private static File[] files = null;
private static String[] fileNames = null;
private static int fileIdx = -1;
private static String currentProgram = null;
private static File file = null;
private static FileOutputStream out = null;
private static FileInputStream in = null;
private static int numFiles;
private static char[] charBuffer = new char[20];
//public static InBox[] inBoxes = new InBox[20];
// Command types constants. Indicates type of packet being sent or received.
public static final byte DIRECT_COMMAND_REPLY = 0x00;
public static final byte SYSTEM_COMMAND_REPLY = 0x01;
public static final byte REPLY_COMMAND = 0x02;
public static final byte DIRECT_COMMAND_NOREPLY = (byte)0x80; // Avoids ~100ms latency
public static final byte SYSTEM_COMMAND_NOREPLY = (byte)0x81; // Avoids ~100ms latency
// Direct Commands
public static final byte START_PROGRAM = 0x00;
public static final byte STOP_PROGRAM = 0x01;
public static final byte PLAY_SOUND_FILE = 0x02;
public static final byte PLAY_TONE = 0x03;
public static final byte SET_OUTPUT_STATE = 0x04;
public static final byte SET_INPUT_MODE = 0x05;
public static final byte GET_OUTPUT_STATE = 0x06;
public static final byte GET_INPUT_VALUES = 0x07;
public static final byte RESET_SCALED_INPUT_VALUE = 0x08;
public static final byte MESSAGE_WRITE = 0x09;
public static final byte RESET_MOTOR_POSITION = 0x0A;
public static final byte GET_BATTERY_LEVEL = 0x0B;
public static final byte STOP_SOUND_PLAYBACK = 0x0C;
public static final byte KEEP_ALIVE = 0x0D;
public static final byte LS_GET_STATUS = 0x0E;
public static final byte LS_WRITE = 0x0F;
public static final byte LS_READ = 0x10;
public static final byte GET_CURRENT_PROGRAM_NAME = 0x11;
public static final byte MESSAGE_READ = 0x13;
// NXJ additions
public static final byte NXJ_DISCONNECT = 0x20;
public static final byte NXJ_DEFRAG = 0x21;
public static final byte NXJ_SET_DEFAULT_PROGRAM = 0x22;
public static final byte NXJ_SET_SLEEP_TIME = 0x23;
public static final byte NXJ_SET_VOLUME = 0x24;
public static final byte NXJ_SET_KEY_CLICK_VOLUME = 0x25;
public static final byte NXJ_SET_AUTO_RUN = 0x26;
public static final byte NXJ_GET_VERSION = 0x27;
public static final byte NXJ_GET_DEFAULT_PROGRAM = 0x28;
public static final byte NXJ_GET_SLEEP_TIME = 0x29;
public static final byte NXJ_GET_VOLUME = 0x2A;
public static final byte NXJ_GET_KEY_CLICK_VOLUME = 0x2B;
public static final byte NXJ_GET_AUTO_RUN = 0x2C;
// System Commands:
public static final byte OPEN_READ = (byte)0x80;
public static final byte OPEN_WRITE = (byte)0x81;
public static final byte READ = (byte)0x82;
public static final byte WRITE = (byte)0x83;
public static final byte CLOSE = (byte)0x84;
public static final byte DELETE = (byte)0x85;
public static final byte FIND_FIRST = (byte)0x86;
public static final byte FIND_NEXT = (byte)0x87;
public static final byte GET_FIRMWARE_VERSION = (byte)0x88;
public static final byte OPEN_WRITE_LINEAR = (byte)0x89;
public static final byte OPEN_READ_LINEAR = (byte)0x8A;
public static final byte OPEN_WRITE_DATA = (byte)0x8B;
public static final byte OPEN_APPEND_DATA = (byte)0x8C;
public static final byte BOOT = (byte)0x97;
public static final byte SET_BRICK_NAME = (byte)0x98;
public static final byte GET_DEVICE_INFO = (byte)0x9B;
public static final byte DELETE_USER_FLASH = (byte)0xA0;
public static final byte POLL_LENGTH = (byte)0xA1;
public static final byte POLL = (byte)0xA2;
public static final byte NXJ_PACKET_MODE = (byte)0xff;
// System settings
private static final String defaultProgramProperty = "lejos.default_program";
private static final String sleepTimeProperty = "lejos.sleep_time";
private static final String defaultProgramAutoRunProperty = "lejos.default_autoRun";
private static final int defaultSleepTime = 2;
private static byte menuMajorVersion = 0;
private static byte menuMinorVersion = 0;
private static byte menuPatchLevel = 0;
private static int menuRevision = 0;
private static LCPMessageListener listener = null;
private static Port[] PORTS = {SensorPort.S1, SensorPort.S2, SensorPort.S3, SensorPort.S4};
private LCP()
{
// Do not instantiate - all methods are static
}
/**
* Add a listener for incoming LCP messages.
* Currently only one listener is supported.
*
* @param aListener the LCP message listener
*/
public static void addMessageListener(LCPMessageListener aListener) {
listener = aListener;
}
/**
* Emulates a Lego firmware Direct or System command
* @param cmd the buffer containing the command
* @param cmdLen the length of the command
*/
public static int emulateCommand(byte[] cmd, int cmdLen, byte[] reply)
{
final byte cmdId = cmd[1];
reply[0] = REPLY_COMMAND;
reply[1] = cmdId;
for(int i=2; i0) m.forward();
else m.backward();
}
if (motorid >= 0) break;
}
break;
}
case RESET_MOTOR_POSITION: {
// Check if boolean value (cmd[3]) is false. If so,
// reset TachoCount (i.e. RotationCount in LEGO FW terminology)
// Note we assume that this like all other LCP motor commands needs to operate on
// a regulated motor.
if (cmd[3] == 0)
{
byte port = cmd[2];
NXTRegulatedMotor m = Motor.A;
m.resetTachoCount();
}
break;
}
case KEEP_ALIVE: {
len = 7;
break;
}
case LS_WRITE: {
byte port = cmd[2];
byte txLen = cmd[3];
byte rxLen = cmd[4];
//SensorPort p = SensorPort.getInstance(port);
//p.i2cEnable(I2CPort.LEGO_MODE);
//p.i2cStart(cmd[5], cmd, 6, txLen-1, rxLen);
//p.i2cWaitIOComplete();
break;
}
case LS_READ: {
byte port = cmd[2];
//SensorPort p = SensorPort.getInstance(port);
int ret = 0; // p.i2cComplete(i2cBuffer, 0, i2cBuffer.length);
if (ret < 0) {
// not sure whether that is correct
reply[2] = ErrorMessages.COMMUNICATION_BUS_ERROR;
reply[3] = 0;
} else {
reply[2] = ErrorMessages.SUCCESS;
reply[3] = (byte) ret;
System.arraycopy(i2cBuffer, 0, reply, 4, ret);
}
len = 20;
break;
}
case LS_GET_STATUS: {
byte port = cmd[2];
//SensorPort p = SensorPort.getInstance(port);
// TODO which status code to return? 0 and 1 seem to arbitrary choices
//reply[2] = (byte)(p.i2cStatus() == 0 ? 0 : 1);
// TODO reply[3] = number of bytes ready to read
len = 4;
break;
}
case OPEN_READ: {
initFiles();
file = new File(getFile(cmd,2));
try {
in = new FileInputStream(file);
int size = (int) file.length();
setReplyInt(size,reply,4);
} catch (Exception e) {
reply[2] = ErrorMessages.FILE_NOT_FOUND;
}
len = 8;
break;
}
case OPEN_WRITE: {
int size = getInt(cmd, 22);
initFiles();
// If insufficient flash memory, report an error
if (size > 0) { //File.freeMemory()) {
reply[2] = ErrorMessages.INSUFFICIENT_MEMORY_AVAILABLE;
} else {
try {
file = new File(getFile(cmd,2));
//TODO lego firmware reports error in case file exists
if (file.exists()) {
file.delete();
numFiles--;
}
file.createNewFile();
fileNames = new String[++numFiles];
for(int j=0;j= fileNames.length) reply[2] = ErrorMessages.FILE_NOT_FOUND;
else
{
for(int i=0;i 58 ? 58 : msgLen);
for(int i=0;i<58 && i= 0 && volume <= 100) {
Sound.setVolume(volume);
Settings.setProperty(Sound.VOL_SETTING, String.valueOf(volume));
}
break;
}
case NXJ_SET_KEY_CLICK_VOLUME: {
int volume = cmd[2];
if (volume >= 0 && volume <= 100) {
Button.setKeyClickVolume(volume);
Settings.setProperty(Keys.VOL_SETTING, String.valueOf(volume));
}
break;
}
case NXJ_GET_VERSION: {
//reply[3] = (byte) NXT.getFirmwareMajorVersion();
//reply[4] = (byte) NXT.getFirmwareMinorVersion();
//reply[5] = (byte) NXT.getFirmwarePatchLevel();
//setReplyInt(NXT.getFirmwareRevision(), reply, 6);
reply[10] = menuMajorVersion;
reply[11] = menuMinorVersion;
reply[12] = menuPatchLevel;
setReplyInt(menuRevision, reply, 13);
len = 17;
break;
}
case NXJ_GET_VOLUME: {
reply[3] = (byte) Sound.getVolume();
len = 4;
break;
}
case NXJ_GET_KEY_CLICK_VOLUME: {
reply[3] = (byte) Button.getKeyClickVolume();
len = 4;
break;
}
case NXJ_GET_SLEEP_TIME: {
reply[3] = (byte) SystemSettings.getIntSetting(sleepTimeProperty, defaultSleepTime);
len = 4;
break;
}
case NXJ_GET_AUTO_RUN: {
String autoRun = SystemSettings.getStringSetting(defaultProgramAutoRunProperty, "OFF");
reply[3] = (byte) (autoRun.equals("ON") ? 1 : 0);
len = 4;
break;
}
case NXJ_GET_DEFAULT_PROGRAM: {
String name = SystemSettings.getStringSetting(defaultProgramProperty, "");
for(int i=0;i> 8) & 0xFF);
}
private static byte getMSB1(int i)
{
return (byte) ((i >> 16) & 0xFF);
}
private static byte getMSB2(int i)
{
return (byte) ((i >> 24) & 0xFF);
}
private static void setReplyInt(int n, byte [] reply, int start) {
reply[start] = getLSB(n);
reply[start+1] = getMSB(n);
reply[start+2] = getMSB1(n);
reply[start+3] = getMSB2(n);
}
private static void setReplyShortInt(int n, byte [] reply, int start) {
reply[start] = getLSB(n);
reply[start+1] = getMSB(n);
}
private static void initFiles() {
if (files == null) {
files = new File("/home/lejos/programs").listFiles();
numFiles = 0;
for(int i=0;i> 16) & 0xFF);
menuMinorVersion = (byte) ((version >> 8) & 0xFF);
menuPatchLevel = (byte) (version & 0xFF);
menuRevision = revision;
}
}