/* ** file: rcx.mashenv ** modified: Thu Jun 9 12:50:35 EST 2011 ** author: Andrew Rock */ environment rcx { purpose <# This environment supports programming a Lego Mindstorms RCX robot, via the Lejos system. #> 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. #> prelude {# public class #PROGRAM_NAME# { #} postlude {# } #} } 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 java.lang.Exception { #OPEN_DEBUGGER# #} postlude {# #CLOSE_DEBUGGER# } #} } 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) #} } public section <#Setting up sensors#> { public final int TOUCH { purpose <# Constant to select sensor type touch. #> inline {# josx.platform.rcx.SensorConstants.SENSOR_TYPE_TOUCH #} } public final int LIGHT { purpose <# Constant to select sensor type light. #> inline {# josx.platform.rcx.SensorConstants.SENSOR_TYPE_LIGHT #} } public final int ROTATION { purpose <# Constant to select sensor type rotation. #> inline {# josx.platform.rcx.SensorConstants.SENSOR_TYPE_ROT #} } private member { purpose <# Pick a sensor port. #> inline {# private static josx.platform.rcx.Sensor mash_rcx_whichSensorPort( int port) { if (port == 1) { return josx.platform.rcx.Sensor.S1; } else if (port == 2) { return josx.platform.rcx.Sensor.S2; } else if (port == 3) { return josx.platform.rcx.Sensor.S3; } else { return null; } } #} } private member { purpose <# Pick a sensor mode. #> inline {# private static int mash_rcx_whichSensorMode(int type) { if (type == TOUCH) { return josx.platform.rcx.SensorConstants.SENSOR_MODE_BOOL; } else if (type == LIGHT) { return josx.platform.rcx.SensorConstants.SENSOR_MODE_PCT; } else if (type == ROTATION) { return josx.platform.rcx.SensorConstants.SENSOR_MODE_ANGLE; } else { return 0; } } #} } private member { purpose <# Set up a sensor. #> inline {# private static void mash_rcx_setUpSensor(int port, int type) { josx.platform.rcx.Sensor s = mash_rcx_whichSensorPort(port); s.setTypeAndMode(type, mash_rcx_whichSensorMode(type)); s.activate(); } #} } public void setUpSensor(int port, int type) { purpose <# Sets up the {\tt port} to be sensor of the given {\tt type}. #> precondition <# {\tt port} is 1, 2, or 3. #> precondition <# {\tt type} is {\tt TOUCH}, {\tt LIGHT}, or {\tt ROTATION}. #> inline {# mash_rcx_setUpSensor(#port#, #type#) #} } } public section <#Using touch sensors#> { private member { purpose <# Wait For push. #> inline {# private static void mash_rcx_waitForPush(int port) { josx.platform.rcx.Sensor s = mash_rcx_whichSensorPort(port); while (s.readBooleanValue()) { } while (!s.readBooleanValue()) { } } #} } 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, or 3. #> precondition <# The port has been set up as a touch sensor. #> inline {# mash_rcx_waitForPush(#port#) #} } private member { purpose <# Wait For let go. #> inline {# private static void mash_rcx_waitForLetGo(int port) { josx.platform.rcx.Sensor s = mash_rcx_whichSensorPort(port); while (!s.readBooleanValue()) { } while (s.readBooleanValue()) { } } #} } 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, or 3. #> precondition <# The port has been set up as a touch sensor. #> inline {# mash_rcx_waitForLetGo(#port#) #} } public boolean isPushed(int port) { purpose <# Returns {\tt true} if and only if the button on {\tt port} is currently pushed. #> precondition <# {\tt port} is 1, 2, or 3. #> precondition <# The port has been set up as a touch sensor. #> inline {# mash_rcx_whichSensorPort(#port#).readBooleanValue() #} } } public section <#Using light sensors#> { private member { purpose <# Wait For lighter. #> inline {# private static void mash_rcx_waitForLighter(int port, int dif) { josx.platform.rcx.Sensor s = mash_rcx_whichSensorPort(port); int init = s.readValue(); while (s.readValue() < init + dif) { } } #} } 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, or 3. #> precondition <# The port has been set up as a light sensor. #> 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_rcx_waitForLighter(#port#, #dif#) #} } private member { purpose <# Wait For light. #> inline {# private static void mash_rcx_waitForLight(int port, int light) { josx.platform.rcx.Sensor s = mash_rcx_whichSensorPort(port); int init = s.readValue(); while (s.readValue() < light) { } } #} } 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, or 3. #> precondition <# The port has been set up as a light sensor. #> precondition <# {\tt light} is between 0 and 100, inclusive. #> inline {# mash_rcx_waitForLight(#port#, #light#) #} } private member { purpose <# Wait For darker. #> inline {# private static void mash_rcx_waitForDarker(int port, int dif) { josx.platform.rcx.Sensor s = mash_rcx_whichSensorPort(port); int init = s.readValue(); while (s.readValue() > init - dif) { } } #} } 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, or 3. #> precondition <# The port has been set up as a light sensor. #> 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_rcx_waitForDarker(#port#, #dif#) #} } private member { purpose <# Wait For dark. #> inline {# private static void mash_rcx_waitForDark(int port, int light) { josx.platform.rcx.Sensor s = mash_rcx_whichSensorPort(port); int init = s.readValue(); while (s.readValue() > light) { } } #} } 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, or 3. #> precondition <# The port has been set up as a light sensor. #> precondition <# {\tt light} is between 0 and 100, inclusive. #> inline {# mash_rcx_waitForDark(#port#, #light#) #} } public int getLight(int port) { purpose <# Returns the current light sensor reading on {\tt port}. #> precondition <# {\tt port} is 1, 2, or 3. #> precondition <# The port has been set up as a light sensor. #> inline {# mash_rcx_whichSensorPort(#port#).readValue() #} } } public section <#Using rotation sensors#> { private member { purpose <# Wait For rotation. #> inline {# private static void mash_rcx_waitForRotation(int port, int rotation) { josx.platform.rcx.Sensor s = mash_rcx_whichSensorPort(port); int init = s.readValue(); while (java.lang.Math.abs(s.readValue() - init) < java.lang.Math.abs(rotation)) { } } #} } 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}. #> precondition <# {\tt port} is 1, 2, or 3. #> precondition <# The port has been set up as a rotation sensor. #> inline {# mash_rcx_waitForRotation(#port#, #rotation#) #} } public int getRotation(int port) { purpose <# Returns the current rotation sensor reading on {\tt port}. #> precondition <# {\tt port} is 1, 2, or 3. #> precondition <# The port has been set up as a rotation sensor. #> inline {# mash_rcx_whichSensorPort(#port#).readValue() #} } public void resetRotation(int port) { purpose <# Sets the counter in the rotation sensor on {\tt port} to zero. #> precondition <# {\tt port} is 1, 2, or 3. #> precondition <# The port has been set up as a rotation sensor. #> inline {# mash_rcx_whichSensorPort(#port#).setPreviousValue(0) #} } } public section <#Output port constants#> { public final int A { purpose <# Constant to select port A. #> inline {# 4 #} } public final int B { purpose <# Constant to select port B. #> inline {# 5 #} } public final int C { purpose <# Constant to select port C. #> inline {# 6 #} } private member { purpose <# Pick a motor. #> inline {# private static josx.platform.rcx.Motor mash_rcx_whichMotorPort( int port) { if (port == A) { return josx.platform.rcx.Motor.A; } else if (port == B) { return josx.platform.rcx.Motor.B; } else if (port == C) { return josx.platform.rcx.Motor.C; } else { return null; } } #} } } public section <#Using motors#> { private member { purpose <# Motor forwards. #> inline {# private static void mash_rcx_motorForward(int port, int power) { josx.platform.rcx.Motor m = mash_rcx_whichMotorPort(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 7, inclusive. #> inline {# mash_rcx_motorForward(#port#, #power#) #} } private member { purpose <# Motor backwards. #> inline {# private static void mash_rcx_motorBackward(int port, int power) { josx.platform.rcx.Motor m = mash_rcx_whichMotorPort(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 7, inclusive. #> inline {# mash_rcx_motorBackward(#port#, #power#) #} } public void motorStop(int port) { purpose <# Stop the motor on {\tt port}. #> precondition <# {\tt port} is {\tt A}, {\tt B}, or {\tt C}. #> inline {# mash_rcx_whichMotorPort(#port#).stop() #} } public void motorFloat(int port) { purpose <# Float the motor on {\tt port}. #> precondition <# {\tt port} is {\tt A}, {\tt B}, or {\tt C}. #> inline {# mash_rcx_whichMotorPort(#port#).flt() #} } } 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 7, inclusive. #> inline {# mash_rcx_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_rcx_whichMotorPort(#port#).stop() #} } } 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 <#Making sounds#> { public void systemSound(int i) { purpose <# Play system sound number {\tt i}. The system sounds are as follows. #><# { \centering \begin{tabular}{ll} {\tt i} & \emph{description} \\ 0 & short beep \\ 1 & double beep \\ 2 & descending arpeggio \\ 3 & ascending arpeggio \\ 4 & long, low beep \\ 5 & quick ascending arpeggio \end{tabular} } ##
i description
0 short beep
1 double beep
2 descending arpeggio
3 ascending arpeggio
4 long, low beep
5 quick ascending arpeggio
#> precondition <# $0 \le$ {\tt i} $\le 5$. #> inline {# josx.platform.rcx.Sound.systemSound(true, #i#) #} } public void playTone(int frequency, int duration) { purpose <# Plays a tone, given its {\tt frequency} (Hertz) and {\tt duration} (centiseconds). #> precondition <# $31 \le$ {\tt frequency} $\le 2100$. #> precondition <# $0 \le$ {\tt duration} $\le 256$. #> inline {# josx.platform.rcx.Sound.playTone(#frequency#, #duration#) #} } } public section <#Using the LCD#> { public void showNumber(int a) { purpose <# Displays a number in the LCD. Does not require {\tt refresh()}. #> precondition <# $0 \le$ {\tt a} $\le 9999$. #> inline {# josx.platform.rcx.LCD.showNumber(#a#) #} } public void clear() { purpose <# Clears the LCD, but the effect will not show until {\tt refresh()} is called. #> inline {# josx.platform.rcx.LCD.clear() #} } public void refresh() { purpose <# Refreshes the LCD, causing the changes to be displayed. #> inline {# josx.platform.rcx.LCD.refresh() #} } public void putChar(char c, int i) { purpose <# Puts a character {\tt c} into the LCD at position {\tt i}. #> precondition <# $0 \le$ {\tt i} $\le 4$. #> inline {# josx.platform.rcx.TextLCD.printChar(#c#, 4 - (#i#)) #} } } public section <#Using infra-red communications#> { private member { purpose <# Buffer for infra-red transmission. #> inline {# private static byte[] mash_rcx_packet = {(byte)0xf7, (byte)0x00}; #} } private member { purpose <# Send the byte. #> inline {# private static void mash_rcx_sendByte(byte b) { mash_rcx_packet[1] = b; josx.platform.rcx.Serial.sendPacket(mash_rcx_packet, 0, 2); } #} } public void sendByte(int i) { purpose <# Send one byte of information to another RCX, by infra-red transmission. The value to send, {\tt i}, will be truncated if it can't fit in a byte. #> inline {# mash_rcx_sendByte((byte) #i#) #} } private member { purpose <# Buffer for infra-red reception. #> inline {# private static byte[] mash_rcx_buffer = new byte[10]; #} } private member { purpose <# Receive the byte. #> inline {# public static byte mash_rcx_receiveByte() { while (josx.platform.rcx.Serial.isPacketAvailable()) { josx.platform.rcx.Serial.readPacket(mash_rcx_buffer); } while (!josx.platform.rcx.Serial.isPacketAvailable()) { } josx.platform.rcx.Serial.readPacket(mash_rcx_buffer); return mash_rcx_buffer[1]; } #} } public int receiveByte() { purpose <# Waits for and returns a new byte sent by another RCX via infra-red transmission. #> inline {# ((int) mash_rcx_receiveByte()) #} } } 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 }