All Downloads are FREE. Search and download functionalities are using the official Maven repository.

lejos.remote.nxt.LCP Maven / Gradle / Ivy

Go to download

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;
	}
	
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy