/* ** file: nxt.mashenv ** created: 23 Apr 2009 ** author: Andrew Rock */ environment nxt { purpose <# This environment supports programming a Lego Mindstorms NXT robot, via the Lejos NXJ system. #><# Requires Lejos-NXJ version 0.9. #> private class { purpose <# The code must be wrapped in a class declaration. #><# There are no imports. Imports are BAD, as they cause name collisions with student program names that drive the students and tutors crazy trying to figure out. #><# The class extends a \verb+$SUPER+ class that defines methods that {\it might} be overidden. These include the default handlers for button presses and releases, and sensor changes. The default handler for ESCAPE releases is a more convenient way to terminate a program than the normal ENTER+ESCAPE method. #><# The name of the program is saved in \verb+mash_nxt_program_name+. #> prelude {# public class #PROGRAM_NAME# extends #PROGRAM_NAME#$SUPER { protected static java.lang.String mash_nxt_program_name = "#PROGRAM_NAME#"; #} postlude {# } // end of the program class class #PROGRAM_NAME#$SUPER { protected static void mash_nxt_onPressEnter() { } protected static void mash_nxt_onReleaseEnter() { lejos.nxt.Sound.beep(); } protected static void mash_nxt_onPressLeft() { } protected static void mash_nxt_onReleaseLeft() { lejos.nxt.Sound.beep(); } protected static void mash_nxt_onPressRight() { } protected static void mash_nxt_onReleaseRight() { lejos.nxt.Sound.beep(); } protected static void mash_nxt_onPressEscape() { } protected static void mash_nxt_onReleaseEscape() { System.exit(0); } protected static void mash_nxt_onChange1(int oldValue, int newValue) { if (oldValue != newValue) { lejos.nxt.Sound.beep(); } else { } } protected static void mash_nxt_onChange2(int oldValue, int newValue) { if (oldValue != newValue) { lejos.nxt.Sound.beep(); } else { } } protected static void mash_nxt_onChange3(int oldValue, int newValue) { if (oldValue != newValue) { lejos.nxt.Sound.beep(); } else { } } protected static void mash_nxt_onChange4(int oldValue, int newValue) { if (oldValue != newValue) { lejos.nxt.Sound.beep(); } else { } } } // end of superclass #} } // end environment class public mandatory rewrite void main() { purpose <# A program that is organised into methods must have a {\tt main} method (a procedure with no arguments). This will be the first method to execute. {\tt mashc} automatically rewrites this method to conform to standard Java. #> prelude {# public static void main(java.lang.String[] mash_args_param) throws Exception { // Listen to the ENTER button. There are spurious calls on startup. lejos.nxt.Button.ENTER.addButtonListener( new lejos.nxt.ButtonListener() { public void buttonPressed(lejos.nxt.Button b) { mash_nxt_onPressEnter(); } public void buttonReleased(lejos.nxt.Button b) { mash_nxt_onReleaseEnter(); } }); // Listen to the LEFT button. lejos.nxt.Button.LEFT.addButtonListener( new lejos.nxt.ButtonListener() { public void buttonPressed(lejos.nxt.Button b) { mash_nxt_onPressLeft(); } public void buttonReleased(lejos.nxt.Button b) { mash_nxt_onReleaseLeft(); } }); // Listen to the RIGHT button. lejos.nxt.Button.RIGHT.addButtonListener( new lejos.nxt.ButtonListener() { public void buttonPressed(lejos.nxt.Button b) { mash_nxt_onPressRight(); } public void buttonReleased(lejos.nxt.Button b) { mash_nxt_onReleaseRight(); } }); // Listen to the ESCAPE button. lejos.nxt.Button.ESCAPE.addButtonListener( new lejos.nxt.ButtonListener() { public void buttonPressed(lejos.nxt.Button b) { mash_nxt_onPressEscape(); } public void buttonReleased(lejos.nxt.Button b) { mash_nxt_onReleaseEscape(); } }); // Display a message to say what we are running. lejos.nxt.LCD.drawString("Running:", 0, 0); lejos.nxt.LCD.drawString(mash_nxt_program_name, 0, 1); // turn off motor speed regulation by default lejos.nxt.Motor.A.suspendRegulation(); lejos.nxt.Motor.B.suspendRegulation(); lejos.nxt.Motor.C.suspendRegulation(); #} postlude {# } // end of main method #} } // end main rewrite private void main() { purpose <# To allow a program to call its own {\tt main} method even though it gets rewritten. Probably a bad idea, but hey, why not. #> inline {# main(null) #} } private member { purpose <# If we can detect an error we should be kind and exit with a message. #> inline {# public static void mash_nxt_fatal(java.lang.String msg) { lejos.nxt.Motor.A.stop(); lejos.nxt.Motor.B.stop(); lejos.nxt.Motor.C.stop(); lejos.nxt.LCD.clearDisplay(); lejos.nxt.LCD.drawString(" ERROR DETECTED ", 0, 0, true); lejos.nxt.LCD.drawString("prog: " + mash_nxt_program_name, 0, 1); lejos.nxt.Sound.buzz(); int i = 0; while (i < msg.length() && i / 16 < 6) { lejos.nxt.LCD.drawString(msg.substring(i, java.lang.Math.min(i + 16, msg.length())), 0, 2 + i / 16); i = i + 16; } while (true) ; } #} } public section <#Setting up sensors#> { public purpose <# At the start of a program, the sensor ports need to be set up to work with the kind of sensor that is plugged into it. Sensors can be either the old RCX kinds or the new NXT kinds. #><# The rotation sensor built into an NXT motor does not have to be set up. #><# Light, sound and proximity sensors benefit from a time delay of about half a second between setting the sensor up and making measurements. #> public final int TOUCH { purpose <# Constant to select sensor type touch (NXT or RCX). #> inline {# lejos.nxt.SensorConstants.TYPE_SWITCH #} } public final int LIGHT_FLOOD { purpose <# Constant to select sensor type light (NXT with the floodlight on). #> inline {# lejos.nxt.SensorConstants.TYPE_LIGHT_ACTIVE #} } private final int LIGHT_NXT_FLOOD { purpose <# Old name for LIGHT_FLOOD. #> inline {# lejos.nxt.SensorConstants.TYPE_LIGHT_ACTIVE #} } public final int LIGHT_NOFLOOD { purpose <# Constant to select sensor type light (NXT with the floodlight off). #> inline {# lejos.nxt.SensorConstants.TYPE_LIGHT_INACTIVE #} } private final int LIGHT_NXT_NOFLOOD { purpose <# Old name for LIGHT_NOFLOOD. #> inline {# lejos.nxt.SensorConstants.TYPE_LIGHT_INACTIVE #} } public final int LIGHT_RCX { purpose <# Constant to select sensor type light (RCX with the floodlight on). #> inline {# - lejos.nxt.SensorConstants.TYPE_LIGHT_ACTIVE #} } public final int ROTATION_RCX { purpose <# Constant to select sensor type rotation (RCX). #> inline {# lejos.nxt.SensorConstants.TYPE_ANGLE #} } public final int SOUND { purpose <# Constant to select sensor type sound (NXT). #> inline {# lejos.nxt.SensorConstants.TYPE_SOUND_DB #} } public final int PROXIMITY { purpose <# Constant to select sensor type ultrasound proximity (NXT). #> inline {# lejos.nxt.SensorConstants.TYPE_REFLECTION #} } private member { purpose <# \verb+SensorPort mash_nxt_whichSensorPort(int port)+ picks the {\tt SensorPort} object for a given {\tt port} number $(1 ... 4)$. #> inline {# protected static lejos.nxt.SensorPort mash_nxt_whichSensorPort( int port) { if (port == 1) { return lejos.nxt.SensorPort.S1; } else if (port == 2) { return lejos.nxt.SensorPort.S2; } else if (port == 3) { return lejos.nxt.SensorPort.S3; } else if (port == 4) { return lejos.nxt.SensorPort.S4; } else { mash_nxt_fatal("port " + port + " is not a sensor port."); return null; } } #} } private member { purpose <# \verb+int mash_nxt_sensorTypes+ is an array that saves the sensor type set for each port. Element 0 is unused. 1 to 4 correspond to the true sensor ports. #> inline {# protected static int[] mash_nxt_sensorTypes = new int[5]; #} } private member { purpose <# \verb+Object[] mash_nxt_sensorObjects+ is an array of sensor objects of various kinds, indexed by port number. Element 0 is unused. 1 to 4 correspond to the true sensor ports. #> inline {# protected static java.lang.Object[] mash_nxt_sensorObjects = new java.lang.Object[5]; #} } private member { purpose <# \verb+void mash_nxt_setUpSensor(int port, int type)+ sets up a sensor port $(1 ... 4)$ as required by its {\tt type} ({\tt TOUCH}, ...). Always let a sensor stabilize for 0.5 seconds after it has been set up, or the initial readings may be inaccurate. #> inline {# protected static void mash_nxt_setUpSensor(int port, int type) { lejos.nxt.SensorPort s = mash_nxt_whichSensorPort(port); mash_nxt_sensorTypes[port] = type; if (type == TOUCH) { mash_nxt_sensorObjects[port] = new lejos.nxt.TouchSensor(s); } else if (type == LIGHT_FLOOD) { mash_nxt_sensorObjects[port] = new lejos.nxt.LightSensor(s, true); } else if (type == LIGHT_NOFLOOD) { mash_nxt_sensorObjects[port] = new lejos.nxt.LightSensor(s, false); } else if (type == LIGHT_RCX) { mash_nxt_sensorObjects[port] = new lejos.nxt.addon.RCXLightSensor(s); ((lejos.nxt.addon.RCXLightSensor) mash_nxt_sensorObjects[port]).setFloodlight(true); } else if (type == ROTATION_RCX) { mash_nxt_sensorObjects[port] = new lejos.nxt.addon.RCXRotationSensor(s); } else if (type == SOUND) { mash_nxt_sensorObjects[port] = new lejos.nxt.SoundSensor(s, false); } else if (type == PROXIMITY) { mash_nxt_sensorObjects[port] = new lejos.nxt.UltrasonicSensor(s); } else { mash_nxt_fatal("setUpSensor: Unknown sensor type " + type); } } #} } public void setUpSensor(int port, int type) { purpose <# Sets up the {\tt port} to be a sensor of the given {\tt type}. #> precondition <# {\tt port} is 1, 2, 3, or 4. #> precondition <# {\tt type} is \verb+TOUCH+, \verb+LIGHT_FLOOD+, \verb+LIGHT_NOFLOOD+, \verb+LIGHT_RCX+, \verb+ROTATION_RCX+, \verb+SOUND+, or \verb+PROXIMITY+. #> inline {# mash_nxt_setUpSensor(#port#, #type#) #} } } // end section: Setting up sensors public section <#Output port constants#> { public final int A { purpose <# Constant to select port A. #> inline {# 5 #} } public final int B { purpose <# Constant to select port B. #> inline {# 6 #} } public final int C { purpose <# Constant to select port C. #> inline {# 7 #} } private member { purpose <# An NXTMotor for port A. #> inline {# protected static lejos.nxt.NXTMotor mash_nxt_NXTMotor_A = new lejos.nxt.NXTMotor(lejos.nxt.MotorPort.A); #} } private member { purpose <# An NXTMotor for port B. #> inline {# protected static lejos.nxt.NXTMotor mash_nxt_NXTMotor_B = new lejos.nxt.NXTMotor(lejos.nxt.MotorPort.B); #} } private member { purpose <# An NXTMotor for port C. #> inline {# protected static lejos.nxt.NXTMotor mash_nxt_NXTMotor_C = new lejos.nxt.NXTMotor(lejos.nxt.MotorPort.C); #} } private member { purpose <# Pick a motor port. #> inline {# protected static lejos.nxt.MotorPort mash_nxt_whichMotorPort(int port) { if (port == A) { return lejos.nxt.MotorPort.A; } else if (port == B) { return lejos.nxt.MotorPort.B; } else if (port == C) { return lejos.nxt.MotorPort.C; } else { mash_nxt_fatal("port " + port + " is not an output port."); return null; } } #} } private member { purpose <# Pick an NXTMotor. #> inline {# protected static lejos.nxt.NXTMotor mash_nxt_whichNXTMotor(int port) { if (port == A) { return mash_nxt_NXTMotor_A; } else if (port == B) { return mash_nxt_NXTMotor_B; } else if (port == C) { return mash_nxt_NXTMotor_C; } else { mash_nxt_fatal("port " + port + " is not an output port."); return null; } } #} } private member { purpose <# Pick a regulated motor. #> inline {# protected static lejos.nxt.NXTRegulatedMotor mash_nxt_whichRegulatedMotor(int port) { if (port == A) { return lejos.nxt.Motor.A; } else if (port == B) { return lejos.nxt.Motor.B; } else if (port == C) { return lejos.nxt.Motor.C; } else { mash_nxt_fatal("port " + port + " is not an output port."); return null; } } #} } } // end section: Output port constants public section <#Using touch sensors#> { purpose <# These methods provide either waits for a touch sensor's state to change or the current state of the touch sensor. #><# These methods all assume that the {\tt port} number you provide as a parameter has been set up as a touch sensor of either the RCX or NXT kind. #> private member { purpose <# \verb+void mash_nxt_waitForPush(int port)+ waits for a push on {\tt port} $(1 ... 4)$. #> inline {# protected static void mash_nxt_waitForPush(int port) { if (port < 1 || port > 4 || mash_nxt_sensorTypes[port] != TOUCH) { mash_nxt_fatal("waitForPush: port " + port + " is not set up as a touch sensor."); } lejos.nxt.TouchSensor s = (lejos.nxt.TouchSensor) mash_nxt_sensorObjects[port]; while (s.isPressed()) { } while (!s.isPressed()) { } } #} } public void waitForPush(int port) { purpose <# Makes the program wait until the touch sensor on {\tt port} is pushed. #> precondition <# {\tt port} is 1, 2, 3 or 4. #> inline {# mash_nxt_waitForPush(#port#) #} } private member { purpose <# \verb+void mash_nxt_waitForLetGo(int port)+ waits for a let go on {\tt port} $(1 ... 4)$. #> inline {# protected static void mash_nxt_waitForLetGo(int port) { if (port < 1 || port > 4 || mash_nxt_sensorTypes[port] != TOUCH) { mash_nxt_fatal("waitForLetGo: port " + port + " is not set up as a touch sensor."); } lejos.nxt.TouchSensor s = (lejos.nxt.TouchSensor) mash_nxt_sensorObjects[port]; while (!s.isPressed()) { } while (s.isPressed()) { } } #} } public void waitForLetGo(int port) { purpose <# Makes the program wait until the touch sensor on {\tt port} is let go. #> precondition <# {\tt port} is 1, 2, 3, or 4. #> inline {# mash_nxt_waitForLetGo(#port#) #} } private member { purpose <# is pushed? #> inline {# protected static boolean mash_nxt_isPushed(int port) { if (port < 1 || port > 4 || mash_nxt_sensorTypes[port] != TOUCH) { mash_nxt_fatal("isPushed: port " + port + " is not set up as a touch sensor."); } return ((lejos.nxt.TouchSensor) mash_nxt_sensorObjects[port]) .isPressed(); } #} } public boolean isPushed(int port) { purpose <# Returns {\tt true} if and only if the touch sensor on {\tt port} is currently pushed. #> precondition <# {\tt port} is 1, 2, 3, or 4. #> inline {# mash_nxt_isPushed(#port#) #} } } // end section: Using touch sensors public section <#Using light sensors#> { purpose <# Most of these methods provide waits for the light level reported by a light sensor to change. In addition the current light level reported by a light sensor can be obtained and (for NXT sensors) the floodlight turned on or off. #><# These methods all assume that the {\tt port} number you provide as a parameter has been set up as a light sensor, of either the RCX or NXT kind. #> private member { purpose <# Wait For lighter. #> inline {# protected static void mash_nxt_waitForLighter(int port, int dif) { if (mash_nxt_sensorTypes[port] == LIGHT_FLOOD || mash_nxt_sensorTypes[port] == LIGHT_NOFLOOD) { lejos.nxt.LightSensor s = (lejos.nxt.LightSensor) mash_nxt_sensorObjects[port]; int init = s.readValue(); while (s.readValue() < init + dif) { } } else if (mash_nxt_sensorTypes[port] == LIGHT_RCX) { lejos.nxt.addon.RCXLightSensor s = (lejos.nxt.addon.RCXLightSensor) mash_nxt_sensorObjects[port]; int init = s.getLightValue(); while (s.getLightValue() < init + dif) { } } else { mash_nxt_fatal("waitForLighter: port " + port + " is not set" + " up as light sensor."); } } #} } public void waitForLighter(int port, int dif) { purpose <# Makes the program wait until the light sensor reading on {\tt port} is increased by {\tt dif}. #> precondition <# {\tt port} is 1, 2, 3 or 4. #> precondition <# {\tt dif} is between 0 and 100, inclusive. 0 is no wait at all. Real light levels never really change by anything like 100. #> inline {# mash_nxt_waitForLighter(#port#, #dif#) #} } private member { purpose <# Wait For light. #> inline {# protected static void mash_nxt_waitForLight(int port, int light) { if (mash_nxt_sensorTypes[port] == LIGHT_FLOOD || mash_nxt_sensorTypes[port] == LIGHT_NOFLOOD) { lejos.nxt.LightSensor s = (lejos.nxt.LightSensor) mash_nxt_sensorObjects[port]; int init = s.readValue(); while (s.readValue() < light) { } } else if (mash_nxt_sensorTypes[port] == LIGHT_RCX) { lejos.nxt.addon.RCXLightSensor s = (lejos.nxt.addon.RCXLightSensor) mash_nxt_sensorObjects[port]; int init = s.getLightValue(); while (s.getLightValue() < light) { } } else { mash_nxt_fatal("waitForLight: port " + port + " is not set up" + " as light sensor."); } } #} } public void waitForLight(int port, int light) { purpose <# Makes the program wait until the light sensor reading on {\tt port} is at least the desired {\tt light} level. #> precondition <# {\tt port} is 1, 2, 3 or 4. #> precondition <# {\tt light} is between 0 and 100, inclusive. #> inline {# mash_nxt_waitForLight(#port#, #light#) #} } private member { purpose <# Wait For darker. #> inline {# protected static void mash_nxt_waitForDarker(int port, int dif) { if (mash_nxt_sensorTypes[port] == LIGHT_FLOOD || mash_nxt_sensorTypes[port] == LIGHT_NOFLOOD) { lejos.nxt.LightSensor s = (lejos.nxt.LightSensor) mash_nxt_sensorObjects[port]; int init = s.readValue(); while (s.readValue() > init - dif) { } } else if (mash_nxt_sensorTypes[port] == LIGHT_RCX) { lejos.nxt.addon.RCXLightSensor s = (lejos.nxt.addon.RCXLightSensor) mash_nxt_sensorObjects[port]; int init = s.getLightValue(); while (s.getLightValue() > init - dif) { } } else { mash_nxt_fatal("waitForDarker: port " + port + " is not set" + " up as light sensor."); } } #} } public void waitForDarker(int port, int dif) { purpose <# Makes the program wait until the light sensor reading on {\tt port} is decreased by {\tt dif}. #> precondition <# {\tt port} is 1, 2, 3 or 4. #> precondition <# {\tt dif} is between 0 and 100, inclusive. 0 is no wait at all. Real light levels never really change by anything like 100. #> inline {# mash_nxt_waitForDarker(#port#, #dif#) #} } private member { purpose <# Wait For dark. #> inline {# protected static void mash_nxt_waitForDark(int port, int light) { if (mash_nxt_sensorTypes[port] == LIGHT_FLOOD || mash_nxt_sensorTypes[port] == LIGHT_NOFLOOD) { lejos.nxt.LightSensor s = (lejos.nxt.LightSensor) mash_nxt_sensorObjects[port]; int init = s.readValue(); while (s.readValue() > light) { } } else if (mash_nxt_sensorTypes[port] == LIGHT_RCX) { lejos.nxt.addon.RCXLightSensor s = (lejos.nxt.addon.RCXLightSensor) mash_nxt_sensorObjects[port]; int init = s.getLightValue(); while (s.getLightValue() > light) { } } else { mash_nxt_fatal("waitForDark: port " + port + " is not set up" + " as light sensor."); } } #} } public void waitForDark(int port, int light) { purpose <# Makes the program wait until the light sensor reading on {\tt port} is at most the desired {\tt light} level. #> precondition <# {\tt port} is 1, 2, 3 or 4. #> precondition <# {\tt light} is between 0 and 100, inclusive. #> inline {# mash_nxt_waitForDark(#port#, #light#) #} } private member { purpose <# get light #> inline {# protected static int mash_nxt_getLight(int port) { if (mash_nxt_sensorTypes[port] == LIGHT_FLOOD || mash_nxt_sensorTypes[port] == LIGHT_NOFLOOD) { return ((lejos.nxt.LightSensor) mash_nxt_sensorObjects[port]).readValue(); } else if (mash_nxt_sensorTypes[port] == LIGHT_RCX) { return ((lejos.nxt.addon.RCXLightSensor) mash_nxt_sensorObjects[port]).getLightValue(); } else { mash_nxt_fatal("getLight: port " + port + " is not set up" + " as light sensor."); return 0; } } #} } public int getLight(int port) { purpose <# Returns the current light sensor reading on {\tt port}. #> precondition <# {\tt port} is 1, 2, 3 or 4. #> inline {# mash_nxt_getLight(#port#) #} } private member { purpose <# get light #> inline {# protected static void mash_nxt_setFloodlight( int port, boolean floodlight) { if (mash_nxt_sensorTypes[port] == LIGHT_FLOOD || mash_nxt_sensorTypes[port] == LIGHT_NOFLOOD) { ((lejos.nxt.LightSensor) mash_nxt_sensorObjects[port]).setFloodlight(floodlight); } else { mash_nxt_fatal("setFloodlight: port " + port + " is not set" + " up as NXT light sensor."); } } #} } public void setFloodlight(int port, boolean floodlight) { purpose <# Turn the floodlight of the light sensor on {\tt port} on or off. #> precondition <# {\tt port} is 1, 2, 3 or 4. #> inline {# mash_nxt_setFloodlight(#port#, #floodlight#) #} } } // end section: Using light sensors public section <#Using sound sensors#> { purpose <# These methods provide either waits for the sound level reported by a sound sensor to change or the current volume reported by the sound sensor. #><# These methods all assume that the {\tt port} number you provide as a parameter has been set up as a sound sensor. #> private member { purpose <# \verb+void mash_nxt_waitForLouder(int port, int dif)+ waits for a sound sensor on {\tt port} $(1 ... 4)$ to report an increase of {\tt dif}~dB. #> inline {# protected static void mash_nxt_waitForLouder(int port, int dif) { if (port < 1 || port > 4 || mash_nxt_sensorTypes[port] != SOUND) { mash_nxt_fatal("waitForLouder: port " + port + " is not set up as a sound sensor."); } lejos.nxt.SoundSensor s = (lejos.nxt.SoundSensor) mash_nxt_sensorObjects[port]; int init = s.readValue(); while (s.readValue() < init + dif) { } } #} } public void waitForLouder(int port, int dif) { purpose <# Makes the program wait until the sound sensor reading on {\tt port} is increased by {\tt dif}. #> precondition <# {\tt port} is 1, 2, 3 or 4. #> precondition <# {\tt dif} is between 0 and 100, inclusive. 0 is no wait at all. #> inline {# mash_nxt_waitForLouder(#port#, #dif#) #} } private member { purpose <# \verb+void mash_nxt_waitForLoud(int port, int volume)+ waits for a sound sensor on {\tt port} $(1 ... 4)$ to report at least {\tt volume}~dB. #> inline {# protected static void mash_nxt_waitForLoud(int port, int volume) { if (port < 1 || port > 4 || mash_nxt_sensorTypes[port] != SOUND) { mash_nxt_fatal("waitForLoud: port " + port + " is not set up as a sound sensor."); } lejos.nxt.SoundSensor s = (lejos.nxt.SoundSensor) mash_nxt_sensorObjects[port]; while (s.readValue() < volume) { } } #} } public void waitForLoud(int port, int volume) { purpose <# Makes the program wait until the sound sensor reading on {\tt port} is at least the desired {\tt volume} level. #> precondition <# {\tt port} is 1, 2, 3 or 4. #> precondition <# {\tt volume} is between 0 and 100, inclusive. #> inline {# mash_nxt_waitForLoud(#port#, #volume#) #} } private member { purpose <# \verb+void mash_nxt_waitForQuieter(int port, int dif)+ waits for a sound sensor on {\tt port} $(1 ... 4)$ to report a drop of {\tt dif}~dB. #> inline {# protected static void mash_nxt_waitForQuieter(int port, int dif) { if (port < 1 || port > 4 || mash_nxt_sensorTypes[port] != SOUND) { mash_nxt_fatal("waitForQuieter: port " + port + " is not set up as a sound sensor."); } lejos.nxt.SoundSensor s = (lejos.nxt.SoundSensor) mash_nxt_sensorObjects[port]; int init = s.readValue(); while (s.readValue() > init - dif) { } } #} } public void waitForQuieter(int port, int dif) { purpose <# Makes the program wait until the sound sensor reading on {\tt port} has decreased by {\tt dif}. #> precondition <# {\tt port} is 1, 2, 3 or 4. #> precondition <# {\tt dif} is between 0 and 100, inclusive. 0 is no wait at all. #> inline {# mash_nxt_waitForQuieter(#port#, #dif#) #} } private member { purpose <# \verb+void mash_nxt_waitForQuiet(int port, int volume)+ waits for a sound sensor on {\tt port} $(1 ... 4)$ to report at most {\tt volume}~dB. #> inline {# protected static void mash_nxt_waitForQuiet(int port, int volume) { if (port < 1 || port > 4 || mash_nxt_sensorTypes[port] != SOUND) { mash_nxt_fatal("waitForQuiet: port " + port + " is not set up as a sound sensor."); } lejos.nxt.SoundSensor s = (lejos.nxt.SoundSensor) mash_nxt_sensorObjects[port]; while (s.readValue() > volume) { } } #} } public void waitForQuiet(int port, int volume) { purpose <# Makes the program wait until the sound sensor reading on {\tt port} is at most the desired {\tt volume} level. #> precondition <# {\tt port} is 1, 2, 3 or 4. #> precondition <# {\tt volume} is between 0 and 100, inclusive. #> inline {# mash_nxt_waitForQuiet(#port#, #volume#) #} } private member { purpose <# get volume #> inline {# protected static int mash_nxt_getVolume(int port) { if (port < 1 || port > 4 || mash_nxt_sensorTypes[port] != SOUND) { mash_nxt_fatal("getVolume: port " + port + " is not set up as a sound sensor."); } return ((lejos.nxt.SoundSensor) mash_nxt_sensorObjects[port]).readValue(); } #} } public int getVolume(int port) { purpose <# Returns the current volume sensor reading on {\tt port}. #> precondition <# {\tt port} is 1, 2, 3 or 4. #> inline {# mash_nxt_getVolume(#port#) #} } } // end section: Using sound sensors public section <#Using ultrasonic sensors#> { purpose <# These methods provide either waits for the distance reported by an ultrasonic sensor to change or the current distance reported by the ultrasonic sensor. #><# These methods all assume that the {\tt port} number you provide as a parameter has been set up as an ultrasonic sensor. #><# A known bug in Lejos 0.85 means the ultrasonic sensor does not work in input port 4. #> private member { purpose <# \verb+void mash_nxt_waitForNearer(int port, int dif)+ waits for an ultrasonic sensor on {\tt port} $(1 ... 4)$ to report a decrease of {\tt dif}~cm. #> inline {# protected static void mash_nxt_waitForNearer(int port, int dif) { if (port < 1 || port > 4 || mash_nxt_sensorTypes[port] != PROXIMITY) { mash_nxt_fatal("waitForNearer: port " + port + " is not set up as an ultrasound sensor."); } lejos.nxt.UltrasonicSensor s = (lejos.nxt.UltrasonicSensor) mash_nxt_sensorObjects[port]; int init = s.getDistance(); while (s.getDistance() > init - dif) { } } #} } public void waitForNearer(int port, int dif) { purpose <# Makes the program wait until the Ultrasonic sensor on {\tt port} senses that distance hss decreased by {\tt dif}~cm. #> precondition <# {\tt port} is 1, 2, 3 or 4. #> precondition <# {\tt dif} is between 0 and 255, inclusive. 0 is no wait at all. #> inline {# mash_nxt_waitForNearer(#port#, #dif#) #} } private member { purpose <# \verb+void mash_nxt_waitForNear(int port, int distance)+ waits for an ultrasonic sensor on {\tt port} $(1 ... 4)$ to report a distance at most of {\tt distance}~cm. #> inline {# protected static void mash_nxt_waitForNear(int port, int distance) { if (port < 1 || port > 4 || mash_nxt_sensorTypes[port] != PROXIMITY) { mash_nxt_fatal("waitForNear: port " + port + " is not set up as an ultrasound sensor."); } lejos.nxt.UltrasonicSensor s = (lejos.nxt.UltrasonicSensor) mash_nxt_sensorObjects[port]; while (s.getDistance() > distance) { } } #} } public void waitForNear(int port, int distance) { purpose <# Makes the program wait until the ultrasonic sensor on {\tt port} reports a distance which is at most {\tt distance}~cm. A distance of 255 means no object is in view. #> precondition <# {\tt port} is 1, 2, 3 or 4. #> precondition <# {\tt distance} is between 0 and 255, inclusive. #> inline {# mash_nxt_waitForNear(#port#, #distance#) #} } private member { purpose <# \verb+void mash_nxt_waitForFurther(int port, int dif)+ waits for an ultrasonic sensor on {\tt port} $(1 ... 4)$ to report an increase of {\tt dif}~cm. #> inline {# protected static void mash_nxt_waitForFurther(int port, int dif) { if (port < 1 || port > 4 || mash_nxt_sensorTypes[port] != PROXIMITY) { mash_nxt_fatal("waitForFurther: port " + port + " is not set up as an ultrasound sensor."); } lejos.nxt.UltrasonicSensor s = (lejos.nxt.UltrasonicSensor) mash_nxt_sensorObjects[port]; int init = s.getDistance(); while (s.getDistance() < init + dif) { } } #} } public void waitForFurther(int port, int dif) { purpose <# Makes the program wait until the ultrasonic sensor on {\tt port} reports the distance has increased by {\tt dif}~cm. #> precondition <# {\tt port} is 1, 2, 3 or 4. #> precondition <# {\tt dif} is between 0 and 255, inclusive. 0 is no wait at all. 255 represents no object currently in view. #> inline {# mash_nxt_waitForFurther(#port#, #dif#) #} } private member { purpose <# \verb+void mash_nxt_waitForFar(int port, int distance)+ waits for an ultrasonic sensor on {\tt port} $(1 ... 4)$ to report a distance at least of {\tt distance}~cm. #> inline {# protected static void mash_nxt_waitForFar(int port, int distance) { if (port < 1 || port > 4 || mash_nxt_sensorTypes[port] != PROXIMITY) { mash_nxt_fatal("waitForFar: port " + port + " is not set up as an ultrasound sensor."); } lejos.nxt.UltrasonicSensor s = (lejos.nxt.UltrasonicSensor) mash_nxt_sensorObjects[port]; while (s.getDistance() < distance) { } } #} } public void waitForFar(int port, int distance) { purpose <# Makes the program wait until the ultrasonic sensor on {\tt port} reports the distance has decreased by {\tt dif}~cm. #> precondition <# {\tt port} is 1, 2, 3 or 4. #> precondition <# {\tt distance} is between 0 and 255, inclusive. #> inline {# mash_nxt_waitForFar(#port#, #distance#) #} } private member { purpose <# get distance #> inline {# protected static int mash_nxt_getDistance(int port) { if (port < 1 || port > 4 || mash_nxt_sensorTypes[port] != PROXIMITY) { mash_nxt_fatal("getDistance: port " + port + " is not set up as an ultrasound sensor."); } return ((lejos.nxt.UltrasonicSensor) mash_nxt_sensorObjects[port]).getDistance(); } #} } public int getDistance(int port) { purpose <# Returns the current ultrasonic sensor reading on {\tt port} in centimetres. 255 means no object is in view. #> precondition <# {\tt port} is 1, 2, 3 or 4. #> inline {# mash_nxt_getDistance(#port#) #} } } // end section: Using ultrasonic sensors public section <#Using rotation sensors#> { purpose <# These methods provide a wait for the rotation count reported by a rotation sensor to change, the current rotation count reported by a sensor, or reset the count to zero. #><# An NXT rotation sensor registers 360 counts per full 360 degree rotation. NXT rotation sensors are built into NXT motors and must be plugged into port A, B or C. There is no need to call \verb+setUpSensor(int,int)+ to set up these sensors. #><# An RCX rotation sensor registers 16 counts per full 360 degree rotation. It must be plugged into port 1, 2, 3 or 4 and set up like other sensor kinds. #> private member { purpose <# Resets rotation. #> inline {# protected static void mash_nxt_resetRotation(int port) { if (1 <= port && port <= 4) { if (mash_nxt_sensorTypes[port] != ROTATION_RCX) { mash_nxt_fatal("resetRotation: port " + port + " is not set up as an RCX rotation sensor."); } ((lejos.nxt.addon.RCXRotationSensor) mash_nxt_sensorObjects[port]).resetTachoCount(); } else if (A <= port && port <= C) { mash_nxt_whichMotorPort(port).resetTachoCount(); } else { mash_nxt_fatal("resetRotation: " + port + " is not a port."); } } #} } public void resetRotation(int port) { purpose <# Sets the counter in the rotation sensor on {\tt port} to zero. #> precondition <# {\tt port} is 1, 2, 3, 4, {\tt A}, {\tt B}, or {\tt C}. #> inline {# mash_nxt_resetRotation(#port#) #} } private member { purpose <# Wait For rotation. #> inline {# protected static void mash_nxt_waitForRotation( int port, int rotation) { rotation = java.lang.Math.abs(rotation); if (1 <= port && port <= 4) { if (mash_nxt_sensorTypes[port] != ROTATION_RCX) { mash_nxt_fatal("waitForRotation: port " + port + " is not set up as an RCX rotation sensor."); } lejos.nxt.addon.RCXRotationSensor s = (lejos.nxt.addon.RCXRotationSensor) mash_nxt_sensorObjects[port]; int init = s.getTachoCount(); while (java.lang.Math.abs(s.getTachoCount() - init) < rotation) { } } else if (A <= port && port <= C) { lejos.nxt.NXTMotor m = mash_nxt_whichNXTMotor(port); int init = m.getTachoCount(); while (java.lang.Math.abs(m.getTachoCount() - init) < rotation) { } } else { mash_nxt_fatal("waitForRotation: " + port + " is not a port."); } } #} } public void waitForRotation(int port, int rotation) { purpose <# Makes the program wait until the counter in the rotation sensor on {\tt port} has changed by at least the absolute value of {\tt rotation}. #><# This method does not reset the counter in the rotation sensor. #> precondition <# {\tt port} is 1, 2, 3, 4, {\tt A}, {\tt B}, or {\tt C}. #> inline {# mash_nxt_waitForRotation(#port#, #rotation#) #} } private member { purpose <# Returns rotation. #> inline {# protected static int mash_nxt_getRotation(int port) { if (1 <= port && port <= 4) { if (mash_nxt_sensorTypes[port] != ROTATION_RCX) { mash_nxt_fatal("getRotation: port " + port + " is not set up as an RCX rotation sensor."); } return ((lejos.nxt.addon.RCXRotationSensor) mash_nxt_sensorObjects[port]).getTachoCount(); } else if (A <= port && port <= C) { return mash_nxt_whichMotorPort(port).getTachoCount(); } else { mash_nxt_fatal("getRotation: " + port + " is not a port."); return 0; } } #} } public int getRotation(int port) { purpose <# Returns the current rotation sensor reading from {\tt port}. #> precondition <# {\tt port} is 1, 2, 3, 4, {\tt A}, {\tt B}, or {\tt C}. #> inline {# mash_nxt_getRotation(#port#) #} } } // end section: Using rotation sensors public section <#Using motors#> { purpose <# The following methods apply to both NXT and RCX motors. #> private member { purpose <# lejos.nxt.NXTMotor forwards. #> inline {# protected static void mash_nxt_motorForward(int port, int power) { lejos.nxt.NXTMotor m = mash_nxt_whichNXTMotor(port); m.setPower(power); m.forward(); } #} } public void motorForward(int port, int power) { purpose <# Make the motor on {\tt port} go forwards at the given {\tt power}. #> precondition <# {\tt port} is {\tt A}, {\tt B}, or {\tt C}. #> precondition <# {\tt power} is betweeen 0 and 100, inclusive. #> inline {# mash_nxt_motorForward(#port#, #power#) #} } private member { purpose <# lejos.nxt.NXTMotor backwards. #> inline {# protected static void mash_nxt_motorBackward(int port, int power) { lejos.nxt.NXTMotor m = mash_nxt_whichNXTMotor(port); m.setPower(power); m.backward(); } #} } public void motorBackward(int port, int power) { purpose <# Make the motor on {\tt port} go backwards at the given {\tt power}. #> precondition <# {\tt port} is {\tt A}, {\tt B}, or {\tt C}. #> precondition <# {\tt power} is betweeen 0 and 100, inclusive. #> inline {# mash_nxt_motorBackward(#port#, #power#) #} } public void motorStop(int port) { purpose <# Stop the motor on {\tt port}. Stopping a motor cuts the power to it and stops it rotating. #> precondition <# {\tt port} is {\tt A}, {\tt B}, or {\tt C}. #> inline {# mash_nxt_whichNXTMotor(#port#).stop() #} } public void motorFloat(int port) { purpose <# Float the motor on {\tt port}. Floating a motor, cuts power to it and lets it rotate freely. #> precondition <# {\tt port} is {\tt A}, {\tt B}, or {\tt C}. #> inline {# mash_nxt_whichNXTMotor(#port#).flt() #} } } // end section: Using motors public section <#Using lamps#> { public void lampOn(int port, int power) { purpose <# Make the lamp on {\tt port} go on at the given {\tt power}. #> precondition <# {\tt port} is {\tt A}, {\tt B}, or {\tt C}. #> precondition <# {\tt power} is betweeen 0 and 100, inclusive. #> inline {# mash_nxt_motorForward(#port#, #power#) #} } public void lampOff(int port) { purpose <# Turns the lamp on {\tt port} off. #> precondition <# {\tt port} is {\tt A}, {\tt B}, or {\tt C}. #> inline {# mash_nxt_whichNXTMotor(#port#).stop() #} } } // end section: Using lamps public section <#Making sounds#> { public void beep() { purpose <# Beep once. #> inline {# lejos.nxt.Sound.beep() #} } public void twoBeeps() { purpose <# Beep twice. #> inline {# lejos.nxt.Sound.twoBeeps() #} } public void fallingBeeps() { purpose <# A few short beeps with descending tones. #> inline {# lejos.nxt.Sound.beepSequence() #} } public void risingBeeps() { purpose <# A few short beeps with ascending tones. #> inline {# lejos.nxt.Sound.beepSequenceUp() #} } public void buzz() { purpose <# Makes a low buzz. #> inline {# lejos.nxt.Sound.buzz() #} } public void pause(int t) { purpose <# Make no sound for {\tt t} milliseconds. #> inline {# lejos.nxt.Sound.pause(#t#) #} } public void playTone(int frequency, int duration) { purpose <# Plays a tone, given its {\tt frequency} (Hertz) and {\tt duration} (milliseconds). #> inline {# lejos.nxt.Sound.playTone(#frequency#, #duration#) #} } public final int[] PIANO { purpose <# Attack, decay, sustain and release shape parameters to emulate a piano. Use with \verb+playNote(int[], int, int)+. #> inline {# lejos.nxt.Sound.PIANO #} } public final int[] FLUTE { purpose <# Attack, decay, sustain and release shape parameters to emulate a flute. Use with \verb+playNote(int[], int, int)+. #> inline {# lejos.nxt.Sound.FLUTE #} } public final int[] XYLOPHONE { purpose <# Attack, decay, sustain and release shape parameters to emulate a xylophone. Use with \verb+playNote(int[], int, int)+. #> inline {# lejos.nxt.Sound.XYLOPHONE #} } public void playNote(int[] instrument, int frequency, int duration) { purpose <# Plays a note attack, decay, sustain and release shape specified by a selected {\tt instrument}, given its {\tt frequency} (Hertz) and {\tt duration} (milliseconds). #> inline {# lejos.nxt.Sound.playNote(#instrument#, #frequency#, #duration#) #} } } // end section: Making sounds public section <#Using the LCD#> { purpose <# The LCD display can be used to display text and graphics. #> public final int LCD_WIDTH { purpose <# The width of the LCD display in pixels, equals 100. #> inline {# lejos.nxt.LCD.SCREEN_WIDTH #} } public final int LCD_HEIGHT { purpose <# The height of the LCD display in pixels, equals 64. #> inline {# lejos.nxt.LCD.SCREEN_HEIGHT #} } public final int LCD_COLUMNS { purpose <# The width of the LCD display in character spaces, equals 16. #> inline {# lejos.nxt.LCD.DISPLAY_CHAR_WIDTH #} } public final int LCD_LINES { purpose <# The height of the LCD display in character spaces, equals 8. #> inline {# lejos.nxt.LCD.DISPLAY_CHAR_DEPTH #} } public void clear() { purpose <# Clears the LCD display to all white. #> inline {# lejos.nxt.LCD.clearDisplay() #} } public void setPixel(boolean p, int x, int y) { purpose <# Set the pixel at ({\tt x}, {\tt y}). If {\tt p} is true, the pixel is set to black, white otherwise. #> precondition <# $0 \le {\tt x} <$ \verb+LCD_WIDTH+. #> precondition <# $0 \le {\tt y} <$ \verb+LCD_HEIGHT+. #> inline {# lejos.nxt.LCD.setPixel(#x#, #y#, (#p#) ? 1 : 0) #} } public void drawString(String s, int x, int y, boolean invert) { purpose <# Displays a string {\tt s} on the LCD starting at ({\tt x}, {\tt y}). If {\tt invert} is true then it is drawn as white on black, instead of the usual black on white. #> precondition <# $0 \le {\tt x} <$ \verb+LCD_WIDTH+. #> precondition <# $0 \le {\tt y} <$ \verb+LCD_HEIGHT+. #> inline {# lejos.nxt.LCD.drawString(#s#, #x#, #y#, #invert#) #} } public void drawString(String s, int x, int y) { purpose <# Displays a string {\tt s} on the LCD starting at column {\tt x} and line {\tt y}. #> precondition <# $0 \le {\tt x} <$ \verb+LCD_COLUMNS+. #> precondition <# $0 \le {\tt y} <$ \verb+LCD_LINES+. #> inline {# lejos.nxt.LCD.drawString(#s#, #x#, #y#) #} } public void drawInt(int i, int width, int x, int y) { purpose <# Displays integer {\tt 1} on the LCD starting at column {\tt x} and line {\tt y} right justified within at least {\tt width} spaces. #> precondition <# $1 \le {\tt width} \le 11$. #> precondition <# $0 \le {\tt x} <$ \verb+LCD_COLUMNS+. #> precondition <# $0 \le {\tt y} <$ \verb+LCD_LINES+. #> inline {# lejos.nxt.LCD.drawInt(#i#, #width#, #x#, #y#) #} } public void scroll() { purpose <# Scrolls the screen up one text line. #> inline {# lejos.nxt.LCD.scroll() #} } } // end section: Using the LCD public section <#Using buttons#> { purpose <# There are four buttons on the front of an NXT. These rewrites define handers for pressing on or releasing the ENTER, LEFT, RIGHT and ESCAPE buttons. #><# Usually a button should cause an action when it is released, so actions are usually put in an {\tt onRelease} handler, but programs can also do something while the button is pressed by implementing an {\tt onPress} handler. #><# Note: Releasing the ESCAPE button, by default, is the easiest way for users to terminate a program with an endless loop. Think carefully before changing that behaviour. #> public rewrite void onPressEnter() { purpose <# Write a procedure of this type to handle presses on the ENTER button (the orange one). #> prelude {# protected static void mash_nxt_onPressEnter() { #} postlude{# } #} } public rewrite void onReleaseEnter() { purpose <# Write a procedure of this type to handle releases of the ENTER button. #> prelude {# protected static void mash_nxt_onReleaseEnter() { #} postlude{# } #} } public rewrite void onPressLeft() { purpose <# Write a procedure of this type to handle presses on the LEFT button. #> prelude {# protected static void mash_nxt_onPressLeft() { #} postlude{# } #} } public rewrite void onReleaseLeft() { purpose <# Write a procedure of this type to handle releases of the LEFT button. #> prelude {# protected static void mash_nxt_onReleaseLeft() { #} postlude{# } #} } public rewrite void onPressRight() { purpose <# Write a procedure of this type to handle presses on the RIGHT button. #> prelude {# protected static void mash_nxt_onPressRight() { #} postlude{# } #} } public rewrite void onReleaseRight() { purpose <# Write a procedure of this type to handle releases of the RIGHT button. #> prelude {# protected static void mash_nxt_onReleaseRight() { #} postlude{# } #} } public rewrite void onPressEscape() { purpose <# Write a procedure of this type to handle presses on the ESCAPE button. #> prelude {# protected static void mash_nxt_onPressEscape() { #} postlude{# } #} } public rewrite void onReleaseEscape() { purpose <# Write a procedure of this type to handle releases of the ESCAPE button. #> prelude {# protected static void mash_nxt_onReleaseEscape() { #} postlude{# } #} } } // end section: Using buttons public section <#Waiting for fixed times#> { private member { purpose <# Provides a binding to {\tt Thread.sleep} that won't throw exceptions. #> inline {# private static void mash_sleep(int ms) { try { java.lang.Thread.sleep(ms); } catch (java.lang.Exception e) { } } #} } public void sleep(int ms) { purpose <# Makes the program wait for a requested number of {\tt ms} (miliseconds). #> inline {# mash_sleep(#ms#) #} } } // end section: Waiting for fixed times public section <#Terminating a program#> { public void exit() { purpose <# Terminates the program. #> inline {# java.lang.System.exit(0) #} } } // end section: Terminating a program public section <#Math#> { public purpose <# The following are some commonly used numeric constants and functions. #> public final int MAX_INT { purpose <# A constant holding the maximum value an {\tt int} can have, $2^{31}-1$. #> inline {# java.lang.Integer.MAX_VALUE #} } public final int MIN_INT { purpose <# A constant holding the minimum value an {\tt int} can have, $- 2^{31}$. #> inline {# java.lang.Integer.MIN_VALUE #} } public final double PI { purpose <# The closest {\tt double} approximation to $\pi$. #> inline {# java.lang.Math.PI #} } public double abs(double a) { purpose <# Returns the absolute value of {\tt a}. #> inline {# java.lang.Math.abs(#a#) #} } public int abs(int a) { purpose <# Returns the absolute value of {\tt a}. #> inline {# java.lang.Math.abs(#a#) #} } public double ceil(double a) { purpose <# Returns the least double value that is greater than or equal to {\tt a} and equal to an integer. #> inline {# java.lang.Math.ceil(#a#) #} } public double exp(double x) { purpose <# Returns $e^x$, that is Euler's constant $e$ raised to power $x$. #> inline {# java.lang.Math.exp(#x#) #} } public double floor(double a) { purpose <# Returns the greatest double value that is less than or equal to {\tt a} and equal to an integer. #> inline {# java.lang.Math.floor(#a#) #} } public double log(double x) { purpose <# Returns the natural logarithm of $x$. #> inline {# java.lang.Math.log(#x#) #} } public int round(float a) { purpose <# Returns the closest {\tt int} to {\tt a}. #> inline {# java.lang.Math.round(#a#) #} } public double sqrt(double a) { purpose <# Returns the square root of {\tt a}. #> precondition <# {\tt a} $\ge 0.0$. #> inline {# java.lang.Math.sqrt(#a#) #} } public double pow(double a, double b) { purpose <# Returns {\tt a} raised to the power {\tt b}, $a^b$. #> inline {# java.lang.Math.pow(#a#, #b#) #} } public double sin(double a) { purpose <# Returns the trigonometric sine of {\tt a} radians. #> inline {# java.lang.Math.sin(#a#) #} } public double cos(double a) { purpose <# Returns the trigonometric cosine of {\tt a} radians. #> inline {# java.lang.Math.cos(#a#) #} } public double tan(double a) { purpose <# Returns the trigonometric tangent of {\tt a} radians. #> inline {# java.lang.Math.tan(#a#) #} } public double asin(double a) { purpose <# Returns the trigonometric arc sine of {\tt a} in radians. #> inline {# java.lang.Math.asin(#a#) #} } public double acos(double a) { purpose <# Returns the trigonometric arc cosine of {\tt a} in radians. #> inline {# java.lang.Math.acos(#a#) #} } public double atan(double a) { purpose <# Returns the trigonometric arc tangent of {\tt a} in radians. #> inline {# java.lang.Math.atan(#a#) #} } public double max(double a, double b) { purpose <# Returns the greater of {\tt a} and {\tt b}. #> inline {# java.lang.Math.max(#a#, #b#) #} } public int max(int a, int b) { purpose <# Returns the greater of {\tt a} and {\tt b}. #> inline {# java.lang.Math.max(#a#, #b#) #} } public double min(double a, double b) { purpose <# Returns the lesser of {\tt a} and {\tt b}. #> inline {# java.lang.Math.min(#a#, #b#) #} } public int min(int a, int b) { purpose <# Returns the lesser of {\tt a} and {\tt b}. #> inline {# java.lang.Math.min(#a#, #b#) #} } public double random() { purpose <# Returns a random value $x$ such that $0.0 \le x < 1.0$. #> inline {# java.lang.Math.random() #} } } // end section: Math public section <#Strings#> { public purpose <# The following are methods for working with {\tt String}s. #> public int length(String s) { purpose <# Returns the length of {\tt s}. #> inline {# #s#.length() #} } public char charAt(String s, int i) { purpose <# Returns the character at position {\tt i} in {\tt s}. #> precondition <# $0 \le$ {\tt i} $<$ {\tt length(s)}. #> inline {# #s#.charAt(#i#) #} } public boolean equals(String a, String b) { purpose <# Returns {\tt true} if and only if {\tt a} contains the same sequence of characters as in {\tt b}. #> inline {# #a#.equals(#b#) #} } public boolean parseBoolean(String s) { purpose <# Returns {\tt s} converted to a {\tt boolean}. #> inline {# java.lang.Boolean.parseBoolean(#s#) #} } public int parseInt(String s) { purpose <# Returns {\tt s} converted to an {\tt int}. #> inline {# java.lang.Integer.parseInt(#s#) #} } public long parseLong(String s) { purpose <# Returns {\tt s} converted to a {\tt long}. #> inline {# java.lang.Long.parseLong(#s#) #} } public float parseFloat(String s) { purpose <# Returns {\tt s} converted to a {\tt float}. #> inline {# java.lang.Float.parseFloat(#s#) #} } public double parseDouble(String s) { purpose <# Returns {\tt s} converted to a {\tt double}. #> inline {# java.lang.Double.parseDouble(#s#) #} } } // end section: Strings public section <#Threads#> { purpose <# A program may have up to 5 additional threads of execution. #> public rewrite void run1() { purpose <# Implement a {\tt run1()} method that defines the actions of additional thread 1. Do no try to call it directly. To start this thread, call {\tt start1()}. #> prelude {# private static class MaSH_NXT_Thread1 extends Thread { public void run() { mash_nxt_run1(); } } private static MaSH_NXT_Thread1 mash_nxt_thread1 = new MaSH_NXT_Thread1(); private static void mash_nxt_run1() { #} postlude {# } #} } public void start1() { purpose <# Call {\tt start1()} to start additional thread 1. #> precondition <# {\tt run1()} has been implemented. If not, {\tt nxjc} will report errors. #> inline {# mash_nxt_thread1.start(); #} } public rewrite void run2() { purpose <# Implement a {\tt run2()} method that defines the actions of additional thread 2. Do no try to call it directly. To start this thread, call {\tt start2()}. #> prelude {# private static class MaSH_NXT_Thread2 extends Thread { public void run() { mash_nxt_run2(); } } private static MaSH_NXT_Thread2 mash_nxt_thread2 = new MaSH_NXT_Thread2(); private static void mash_nxt_run2() { #} postlude {# } #} } public void start2() { purpose <# Call {\tt start2()} to start additional thread 2. #> precondition <# {\tt run2()} has been implemented. If not, {\tt nxjc} will report errors. #> inline {# mash_nxt_thread2.start(); #} } public rewrite void run3() { purpose <# Implement a {\tt run3()} method that defines the actions of additional thread 3. Do no try to call it directly. To start this thread, call {\tt start3()}. #> prelude {# private static class MaSH_NXT_Thread3 extends Thread { public void run() { mash_nxt_run3(); } } private static MaSH_NXT_Thread3 mash_nxt_thread3 = new MaSH_NXT_Thread3(); private static void mash_nxt_run3() { #} postlude {# } #} } public void start3() { purpose <# Call {\tt start3()} to start additional thread 3. #> precondition <# {\tt run3()} has been implemented. If not, {\tt nxjc} will report errors. #> inline {# mash_nxt_thread3.start(); #} } public rewrite void run4() { purpose <# Implement a {\tt run4()} method that defines the actions of additional thread 4. Do no try to call it directly. To start this thread, call {\tt start4()}. #> prelude {# private static class MaSH_NXT_Thread4 extends Thread { public void run() { mash_nxt_run4(); } } private static MaSH_NXT_Thread4 mash_nxt_thread4 = new MaSH_NXT_Thread4(); private static void mash_nxt_run4() { #} postlude {# } #} } public void start4() { purpose <# Call {\tt start4()} to start additional thread 4. #> precondition <# {\tt run4()} has been implemented. If not, {\tt nxjc} will report errors. #> inline {# mash_nxt_thread4.start(); #} } public rewrite void run5() { purpose <# Implement a {\tt run5()} method that defines the actions of additional thread 5. Do no try to call it directly. To start this thread, call {\tt start5()}. #> prelude {# private static class MaSH_NXT_Thread5 extends Thread { public void run() { mash_nxt_run5(); } } private static MaSH_NXT_Thread5 mash_nxt_thread5 = new MaSH_NXT_Thread5(); private static void mash_nxt_run5() { #} postlude {# } #} } public void start5() { purpose <# Call {\tt start5()} to start additional thread 5. #> precondition <# {\tt run5()} has been implemented. If not, {\tt nxjc} will report errors. #> inline {# mash_nxt_thread5.start(); #} } } // end section: Threads public section <#Sensor listeners#> { purpose <# An alternative to polling sensors is to register a listener that will respond when the sensor changes state. #> public void listenPort1() { purpose <# Starts listening to port 1.\\ If the state of that sensor changes, {\tt onChange1(int, int)} will be called. #> inline {# mash_nxt_whichSensorPort(1).addSensorPortListener( new lejos.nxt.SensorPortListener() { public void stateChanged(lejos.nxt.SensorPort source, int oldValue, int newValue) { mash_nxt_onChange1(oldValue, newValue); } } ) #} } public rewrite void onChange1(int oldValue, int newValue) { purpose <# Write a method with this type to handle changes on sensor port 1. {\tt oldValue} and {\tt newValue} are the old and new {\it raw} sensor values, respectively. #> prelude {# protected static void mash_nxt_onChange1(int #oldValue#, int #newValue#) { #} postlude {# } #} } public void listenPort2() { purpose <# Starts listening to port 2.\\ If the state of that sensor changes, {\tt onChange2(int, int)} will be called. #> inline {# mash_nxt_whichSensorPort(2).addSensorPortListener( new lejos.nxt.SensorPortListener() { public void stateChanged(lejos.nxt.SensorPort source, int oldValue, int newValue) { mash_nxt_onChange2(oldValue, newValue); } } ) #} } public rewrite void onChange2(int oldValue, int newValue) { purpose <# Write a method with this type to handle changes on sensor port 2. {\tt oldValue} and {\tt newValue} are the old and new {\it raw} sensor values, respectively. #> prelude {# protected static void mash_nxt_onChange2(int #oldValue#, int #newValue#) { #} postlude {# } #} } public void listenPort3() { purpose <# Starts listening to port 3.\\ If the state of that sensor changes, {\tt onChange3(int, int)} will be called. #> inline {# mash_nxt_whichSensorPort(3).addSensorPortListener( new lejos.nxt.SensorPortListener() { public void stateChanged(lejos.nxt.SensorPort source, int oldValue, int newValue) { mash_nxt_onChange3(oldValue, newValue); } } ) #} } public rewrite void onChange3(int oldValue, int newValue) { purpose <# Write a method with this type to handle changes on sensor port 3. {\tt oldValue} and {\tt newValue} are the old and new {\it raw} sensor values, respectively. #> prelude {# protected static void mash_nxt_onChange3(int #oldValue#, int #newValue#) { #} postlude {# } #} } public void listenPort4() { purpose <# Starts listening to port 4.\\ If the state of that sensor changes, {\tt onChange4(int, int)} will be called. #> inline {# mash_nxt_whichSensorPort(4).addSensorPortListener( new lejos.nxt.SensorPortListener() { public void stateChanged(lejos.nxt.SensorPort source, int oldValue, int newValue) { mash_nxt_onChange4(oldValue, newValue); } } ) #} } public rewrite void onChange4(int oldValue, int newValue) { purpose <# Write a method with this type to handle changes on sensor port 4. {\tt oldValue} and {\tt newValue} are the old and new {\it raw} sensor values, respectively. #> prelude {# protected static void mash_nxt_onChange4(int #oldValue#, int #newValue#) { #} postlude {# } #} } } // end section: Sensor Listeners } // end of environment nxt