package lejos.nxt; import lejos.robotics.Colors; import lejos.util.Delay; /** * Abstraction for a NXT input port. * */ public class SensorPort implements LegacySensorPort, I2CPort, ListenerCaller { /** * Power types. */ public static final int POWER_STD = 0; public static final int POWER_RCX9V = 1; public static final int POWER_9V = 2; // Sensor port I/O pin ids public static final int SP_DIGI0 = 0; public static final int SP_DIGI1 = 1; public static final int SP_ANA = 2; // Sensor port pin modes public static final int SP_MODE_OFF = 0; public static final int SP_MODE_INPUT = 1; public static final int SP_MODE_OUTPUT = 2; public static final int SP_MODE_ADC = 3; // Digital I/O pins used to control the sensor operation public static final int DIGI_UNUSED = -1; public static final int DIGI_OFF = 0; public static final int DIGI_0_ON = (1 << SP_DIGI0); public static final int DIGI_1_ON = (1 << SP_DIGI1); private static final byte[] powerType = { POWER_STD, // NO_SENSOR POWER_STD, // SWITCH POWER_RCX9V, // TEMPERATURE POWER_RCX9V, // REFLECTION POWER_RCX9V, // ANGLE POWER_STD, // LIGHT_ACTIVE POWER_STD, // LIGHT_INACTIVE POWER_STD, // SOUND_DB POWER_STD, // SOUND_DBA POWER_STD, // CUSTOM POWER_STD, // LOWSPEED, POWER_9V, // LOWSPEED_9V POWER_STD, // Unused POWER_STD, // COLOR_FULL POWER_STD, // COLOR_RED POWER_STD, // COLOR_GREEN POWER_STD, // COLOR_BLUE POWER_STD, // COLOR_NONE }; private static final byte[] controlPins = { DIGI_UNUSED, // NO_SENSOR DIGI_UNUSED, // SWITCH DIGI_UNUSED, // TEMPERATURE DIGI_UNUSED, // REFLECTION DIGI_UNUSED, // ANGLE DIGI_0_ON, // LIGHT_ACTIVE DIGI_OFF, // LIGHT_INACTIVE DIGI_0_ON, // SOUND_DB DIGI_1_ON, // SOUND_DBA DIGI_UNUSED, // CUSTOM DIGI_UNUSED, // LOWSPEED, DIGI_UNUSED, // LOWSPEED_9V DIGI_UNUSED, // Unused DIGI_OFF, // COLOR_FULL DIGI_OFF, // COLOR_RED DIGI_OFF, // COLOR_GREEN DIGI_OFF, // COLOR_BLUE DIGI_OFF, // COLOR_NONE }; /** * Port labeled 1 on NXT. */ public static final SensorPort S1 = new SensorPort(0); /** * Port labeled 2 on NXT. */ public static final SensorPort S2 = new SensorPort(1); /** * Port labeled 3 on NXT. */ public static final SensorPort S3 = new SensorPort(2); /** * Port labeled 4 on NXT. */ public static final SensorPort S4 = new SensorPort(3); /** * Array containing all three ports [0..3]. */ public static final SensorPort[] PORTS = { SensorPort.S1, SensorPort.S2, SensorPort.S3, SensorPort.S4 }; private int iPortId; private short iNumListeners = 0; private SensorPortListener[] iListeners; private int iPreviousValue; private int type, mode; /** * The SensorReader class provides a way of performing type dependent way * to obtain data froma sensor. This base class simply returns no data. */ protected class SensorReader { /** * Used to notify the reader that the type of the sensor has changed. * @param type */ public void setType(int type){} /** * Used to notify the reader that the operating mode of the sensor has * changed. * @param mode */ public void setMode(int mode){} /** * Read a normalised/calibrated value from the sensor. * @return < 0 error, >= 0 sensor value */ public int readValue(){ return -1; } /** * Read a raw value from the sensor. * @return < 0 error >= 0 Raw sensor value. */ public int readRawValue() { return -1; } /** * Return a variable number of sensor values * @param values An array in which to return the sensor values. * @return The number of values returned. */ public int readValues(int[] values) { return -1; } /** * Return a variable number of raw sensor values * @param values An array in which to return the sensor values. * @return The number of values returned. */ public int readRawValues(int[] values) { return -1; } /** * Reset the sensor. */ public void reset() {} } protected class StandardReader extends SensorReader { /** * Returns value compatible with Lego firmware. * @return the computed value */ @Override public int readValue() { int rawValue = readSensorValue(iPortId); if (mode == MODE_BOOLEAN) return (rawValue < 600 ? 1 : 0); if (mode == MODE_PCTFULLSCALE) return ((1023 - rawValue) * 100 / 1023); return rawValue; } /** * Reads the raw value of the sensor. * @return the raw sensor value */ @Override public final int readRawValue() { return readSensorValue(iPortId); } } /** * Lego Color Sensor driver. * This driver provides access to the Lego Color sensor. It allows the reading * raw and processed color values. The sensor has a tri-color led and this can * be set to output red/green/blue or off. It also has a full mode in which * four samples are read (off/red/green/blue) very quickly. These samples can * then be combined using the calibration data provided by the device to * determine the "Lego" color currently being viewed. * @author andy */ protected class ColorSensorReader extends SensorReader { /** * Sensor types supported by this driver. The type is used to control the * operation of the tri color led. */ /** * Indexes into the output arrays for specific color values. */ public static final int RGB_RED = 0; public static final int RGB_GREEN = 1; public static final int RGB_BLUE = 2; public static final int RGB_BLANK = 3; protected Colors.Color[] colorMap = Colors.Color.values(); // pin usage for clock and data lines. protected static final int CLOCK = SensorPort.SP_DIGI0; protected static final int DATA = SensorPort.SP_DIGI1; protected boolean initialized = false; protected int type = TYPE_NO_SENSOR; // data ranges and limits protected static final int ADVOLTS = 3300; protected static final int ADMAX = 1023; protected static final int MINBLANKVAL = (214 / (ADVOLTS / ADMAX)); protected static final int SENSORMAX = ADMAX; protected int[][] calData = new int[3][4]; protected int[] calLimits = new int[2]; protected int[] rawValues = new int[RGB_BLANK + 1]; protected int[] values = new int[RGB_BLANK + 1]; /** * Create a new Color Sensor instance and bind it to a port. */ public ColorSensorReader() { initialized = false; } /** * initialize the raw and processed RGB values */ protected void initValues() { for (int i = 0; i < values.length; i++) { values[i] = 0; rawValues[i] = 0; } } /** * Change the type of the sensor * @param type new sensor type. */ @Override public void setType(int type) { if (type != TYPE_NO_SENSOR) { if (this.type != type) { this.type = type; initialized = false; checkInitialized(); } } else reset(); } /** * Reset the sensor. */ @Override public void reset() { // It would seem that the only way to reset the sensor is to either // power it off, or set it to the color none type. setType(TYPE_COLORNONE); type = TYPE_NO_SENSOR; } /** * Set the clock pin to the specified value * @param val the new value(0/1) for the pin. */ protected void setClock(int val) { setSensorPin(CLOCK, val); } /** * Set the data pin to the specified value * @param val new value(0/1) for the pin. */ protected void setData(int val) { setSensorPin(DATA, val); } /** * get the current digital value from the data pin. * @return current pin value */ protected boolean getData() { return getSensorPin(DATA) != 0; } /** * Read the current analogue value from the data pin * @return current value of the pin. */ protected int readData() { return readSensorPin(DATA); } /** * perform a reset of the device. */ protected void resetSensor() { // Set both ports to 1 setClock(1); setData(1); setSensorPinMode(CLOCK, SensorPort.SP_MODE_OUTPUT); setSensorPinMode(DATA, SensorPort.SP_MODE_OUTPUT); Delay.msDelay(1); // Take clock down setClock(0); Delay.msDelay(1); // Raise it setClock(1); Delay.msDelay(1); // Take clock down for 100ms setClock(0); Delay.msDelay(100); } /** * Send the new operating mode to the sensor. * The value is sent to the sensor by using the clock pin to clock a series * of 8 bits out to the device. * @param mode */ protected void sendMode(int mode) { for (int i = 0; i < 8; i++) { // Raise clock setClock(1); // Set the data setData(mode & 1); Delay.usDelay(30); // Drop the clock setClock(0); mode >>= 1; Delay.usDelay(30); } } /** * Read a data byte from the sensor. * The data is read by reading the digital value of the data pin while * using the clock pin to request each of the 8 bits. * @return The read byte. */ protected int readByte() { int val = 0; for (int i = 0; i < 8; i++) { setClock(1); Delay.usDelay(4); val >>= 1; if (getData()) val |= 0x80; setClock(0); Delay.usDelay(4); } return val; } /** * Incrementally calculate the CRC value of the read data. * @param crc current crc * @param val new value * @return new crc */ protected int calcCRC(int crc, int val) { for (int i = 0; i < 8; i++) { if (((val ^ crc) & 1) != 0) crc = ((crc >>> 1) ^ 0xa001); else crc >>>= 1; val >>>= 1; } return crc & 0xffff; } /** * Read the calibration data from the sensor. * This consists of two tables. The first contians 3 rows of data with * each row having 4 columns. The data is sent one row at a time. Each * row contains a calibration constant for red/green/blue/blank readings. * The second table contains 2 threshold values that are used (based on the * background light reading) to select the row to use from the first table. * Finally there is a CRC value which is used to ensure correct reading * of the data. * @return true if ok false if error */ protected boolean readCalibration() { setSensorPinMode(DATA, SensorPort.SP_MODE_INPUT); int crcVal = 0x5aa5; int input; for (int i = 0; i < calData.length; i++) for (int col = 0; col < calData[i].length; col++) { int val = 0; int shift = 0; for (int k = 0; k < 4; k++) { input = readByte(); crcVal = calcCRC(crcVal, input); val |= input << shift; shift += 8; } calData[i][col] = val; //RConsole.println("entry " + i + " col " + col + " value " + val); } for (int i = 0; i < calLimits.length; i++) { int val = 0; int shift = 0; for (int k = 0; k < 2; k++) { input = readByte(); crcVal = calcCRC(crcVal, input); val |= input << shift; shift += 8; } //RConsole.println("limit " + i + " value " + val); calLimits[i] = val; } int crc = (short) (readByte() << 8); crc += (short) readByte(); setSensorPinMode(DATA, SensorPort.SP_MODE_ADC); Delay.msDelay(1); return crc == crcVal; } /** * Initialize the sensor and set the operating mode. * @param mode Operating mode. * @return true if ok false if error. */ protected boolean initSensor(int mode) { resetSensor(); sendMode(mode); return readCalibration(); } /** * Check to see if a sensor is attached. * Read the standard sensor analogue pin to see if a the sensor is * present. If it is it will pull this pin down. * @return true if sensor is connected false otherwise. */ protected boolean checkPresent() { int ANAValue = readSensorPin(SensorPort.SP_ANA); return (ANAValue <= 50); } /** * Check to see if a sensor is attached and working, * Read the standard sensor analogue pin to see if a the sensor is * present. If it is it will pull this pin down. If the sensor is * detected but it has not been initialized then initialize it. * @return true if sensor is connected and working false otherwise. */ protected boolean checkInitialized() { // is there a sensor attached? int ANAValue = readSensorPin(SensorPort.SP_ANA); if (ANAValue > 50) initialized = false; else if (!initialized) initialized = initSensor(type); return initialized; } /** * Check the state of an initialized sensor. * Once initialized this method will check that the sensor is not reporting * an error state. The sensor can do this by pulling the clock pin high * @return true if ok false if error. */ protected boolean checkSensor() { setSensorPinMode(CLOCK, SensorPort.SP_MODE_INPUT); Delay.msDelay(2); if (getSensorPin(CLOCK) != 0) initialized = false; return initialized; } /** * Read a value from the sensor when in fill color mode. * When in full color mode the readings are taken by toggling the clock * line to move from one reading to the next. This method performs this * operation. It also samples the analogue value twice and returns the * average reading. * @param newClock New value for the clock pin * @return the new reading */ protected int readFullColorValue(int newClock) { //delayUS(40); int val = readSensorPin(DATA);//readData(); //delayUS(40); int val2 = readSensorPin(DATA);//readData(); //val = (val + readData())/2; setClock(newClock); return (val + val2) / 2; } /** * Read the device * @return true if ok false if error */ protected boolean readSensor() { if (!checkInitialized()) return false; if (type == TYPE_COLORFULL) { if (!checkSensor()) return false; setSensorPinMode(CLOCK, SensorPort.SP_MODE_OUTPUT); rawValues[RGB_BLANK] = readFullColorValue(1); rawValues[RGB_RED] = readFullColorValue(0); rawValues[RGB_GREEN] = readFullColorValue(1); rawValues[RGB_BLUE] = readFullColorValue(0); return true; } else { if (!checkSensor()) return false; rawValues[type - TYPE_COLORRED] = readData(); return true; } } /** * Return a single raw value from the device. * When in single color mode this returns the raw sensor reading. * Values range from 0 to 1023 but usually don't get over 600. * @return the raw value or < 0 if there is an error. */ @Override public int readRawValue() { if (type < TYPE_COLORRED) return -1; if (!readSensor()) return -1; return rawValues[type - TYPE_COLORRED]; } /** * When in full color mode this returns all four raw color values from the * device by doing four very quick reads and flashing all colors. * The raw values theoretically range from 0 to 1023 but in practice they usually * do not go higher than 600. You can access the index of each color * using RGB_RED, RGB_GREEN, RGB_BLUE and RGB_BLANK. e.g. to retrieve the Blue value: * <code>vals[ColorLightSensor.RGB_BLUE]</code> * * @param vals array of four color values. * @return < 0 if there is an error the number of values if ok */ @Override public int readRawValues(int[] vals) { if (type != TYPE_COLORFULL) return -1; if (!readSensor()) return -1; System.arraycopy(rawValues, 0, vals, 0, rawValues.length); return rawValues.length; } /** * This method accepts a set of raw values (in full color mode) and processes * them using the calibration data to return standard RGB values between 0 and 255 * @param vals array to return the newly calibrated data. */ protected void calibrate(int[] vals) { // First select the calibration table to use... int calTab; int blankVal = rawValues[RGB_BLANK]; if (blankVal < calLimits[1]) calTab = 2; else if (blankVal < calLimits[0]) calTab = 1; else calTab = 0; // Now adjust the raw values for (int col = RGB_RED; col <= RGB_BLUE; col++) if (rawValues[col] > blankVal) vals[col] = ((rawValues[col] - blankVal) * calData[calTab][col]) >>> 16; else vals[col] = 0; // finally adjust the blank value if (blankVal > MINBLANKVAL) blankVal -= MINBLANKVAL; else blankVal = 0; blankVal = (blankVal * 100) / (((SENSORMAX - MINBLANKVAL) * 100) / ADMAX); vals[RGB_BLANK] = (blankVal * calData[calTab][RGB_BLANK]) >>> 16; } /** * Return a set of calibrated data. * If in single color mode the returned data is a simple percentage. If in * full color mode the data is a set of calibrated red/blue/green/blank * readings that range from 0 to 255. You can access the index of each color * using RGB_RED, RGB_GREEN, RGB_BLUE and RGB_BLANK. e.g. to retrieve the Blue value: * <code>vals[ColorLightSensor.RGB_BLUE]</code> * * @param vals 4 element array for the results * @return < 0 of error, the number of values if ok */ @Override public int readValues(int[] vals) { if (type != TYPE_COLORFULL) return -1; if (!readSensor()) return -1; calibrate(vals); return RGB_BLANK+1; } /** * Return a single processed value. * If in single color mode this returns a single reading as a percentage. If * in full color mode it returns a Lego color value that identifies the * color of the object in view. * @return processed color value. */ @Override public int readValue() { if (!readSensor()) return -1; if (type >= TYPE_COLORRED) return (rawValues[type - TYPE_COLORRED] * 100) / SENSORMAX; else { calibrate(values); int red = values[RGB_RED]; int blue = values[RGB_BLUE]; int green = values[RGB_GREEN]; int blank = values[RGB_BLANK]; // we have calibrated values, now use them to determine the color if ((red < 55 && green < 55 && blue < 55) || (blank < 30 && red < 100 && green < 100 && blue < 100)) return Colors.BLACK; if (red > blue && red > green) { // red dominant color if (((blue >> 1) + (blue >> 2) + blue < green) && (green << 1) + green > red) return Colors.YELLOW; if ((green << 1) < red) return Colors.RED; if (blue < 70 || green < 70 || (blank < 100 && red < 100)) return Colors.BLACK; return Colors.WHITE; } else if (green > blue) { // green dominant if ((blue << 1) < red) return Colors.YELLOW; if ((red + (red >> 2) + (red >> 3) < green) || (blue + (blue >> 2) + (blue >> 3) < green)) return Colors.GREEN; if (red < 70 || blue < 70 || (blank < 100 && green < 100)) return Colors.BLACK; return Colors.WHITE; } else { // Blue is dominant if ((red + (red >> 3) + (red >> 4) < blue) || (green + green >> 3) + (green >> 4) < blue) return Colors.BLUE; if (red < 70 || green < 70 || (blank < 100 && blue < 100)) return Colors.BLACK; return Colors.WHITE; } } } } private SensorReader offReader = new SensorReader(); private SensorReader standardReader = new StandardReader(); private SensorReader colorReader = null; private SensorReader curReader = offReader; /** * Enable the use of the Color Light Sensor on this port. * The code for this sensor is relatively large, so it is not presnt by * default. Calling this function will enable this code. * NOTE: Calling this function will reset the port. If you are using higher * level inetrfaces (like the ColorLightSensor class, then this call will * be made automatically.). */ public void enableColorSensor() { if (colorReader != null) return; colorReader = new ColorSensorReader(); reset(); } protected SensorPort(int aId) { iPortId = aId; reset(); } /** * Reset this port and attempt to reset any attached device. */ public void reset() { // reset all known sensor types standardReader.reset(); if (colorReader != null) colorReader.reset(); // force re-selection of reader type = -1; mode = MODE_RAW; curReader = offReader; setType(TYPE_NO_SENSOR); } /** * Return the ID of the port. One of 0, 1, 2 or 3. * @return The Id of this sensor */ public final int getId() { return iPortId; } /** * Adds a port listener. * <p> * <b> * NOTE 1: You can add at most 8 listeners.<br> * NOTE 2: Synchronizing inside listener methods could result * in a deadlock. * </b> * @param aListener Listener for call backs * @see lejos.nxt.SensorPortListener */ public synchronized void addSensorPortListener(SensorPortListener aListener) { if (iListeners == null) iListeners = new SensorPortListener[8]; iListeners[iNumListeners++] = aListener; ListenerThread.get().addSensorToMask(iPortId, this); } /** * Activates an RCX sensor. This method should be called * if you want to get accurate values from an RCX * sensor. In the case of RCX light sensors, you should see * the LED go on when you call this method. */ public final void activate() { setPowerType(1); } /** * Passivates an RCX sensor. */ public final void passivate() { setPowerType(0); } /** * Returns mode compatible with Lego firmware. * @return the current mode */ public int getMode() { return mode; } /** * Returns type compatible with Lego firmware. * @return The type of the sensor */ public int getType() { return type; } /** * Sets type and mode compatible with Lego firmware. * @param type the sensor type * @param mode the sensor mode */ public void setTypeAndMode(int type, int mode) { setType(type); setMode(mode); } /** * Sets type compatible with Lego firmware. * @param newType the sensor type */ public void setType(int newType) { if (newType == type) return; if (newType < powerType.length) { // Work out what reader we need for the new type SensorReader newReader; // Determine what reader to use. if (newType >= TYPE_COLORFULL) newReader = colorReader; else if (newType >= TYPE_SWITCH) newReader = standardReader; else newReader = offReader; if (newReader == null) newReader = offReader; // if we are changing readers tell the old one we are done. if (newReader != curReader) curReader.setType(TYPE_NO_SENSOR); // Set the power and pins for the new type. int control = controlPins[newType]; setPowerType(powerType[newType]); // Set the state of the digital I/O pins setSensorPinMode(SP_DIGI0, SP_MODE_OUTPUT); setSensorPinMode(SP_DIGI1, SP_MODE_OUTPUT); if (control == DIGI_UNUSED) control = DIGI_OFF; setSensorPin(SP_DIGI0, ((control & DIGI_0_ON) != 0 ? 1 : 0)); setSensorPin(SP_DIGI1, ((control & DIGI_1_ON) != 0 ? 1 : 0)); // Switch to the new type this.type = newType; curReader = newReader; newReader.setType(newType); newReader.setMode(mode); } } /** * Sets mode compatible with Lego firmware. * @param mode the mode to set. */ public void setMode(int mode) { this.mode = mode; curReader.setMode(mode); } /** * Reads the raw value of the sensor. * @return the raw sensor value */ public final int readRawValue() { return curReader.readRawValue(); } /** * Returns value compatible with Lego firmware. * @return the computed value */ public int readValue() { return curReader.readValue(); } /** * Return a variable number of sensor values * @param values An array in which to return the sensor values. * @return The number of values returned. */ public int readValues(int[] values) { return curReader.readValues(values); } /** * Return a variable number of raw sensor values * @param values An array in which to return the sensor values. * @return The number of values returned. */ public int readRawValues(int[] values) { return curReader.readRawValues(values); } /** * Reads the boolean value of the sensor. * @return the boolean state of the sensor */ public final boolean readBooleanValue() { int rawValue = readRawValue(); return (rawValue < 600); } /** * <i>Low-level API</i> for reading sensor values. * Currently always returns the raw ADC value. * @param aPortId Port ID (0..4). * @param aRequestType ignored. */ static native int readSensorValue(int aPortId); /** * Low-level method to set the input power setting for a sensor. * Values are: 0 - no power, 1 RCX active power, 2 power always on. * * @param type Power type to use */ public void setPowerType(int type) { setPowerTypeById(iPortId, type); } /** * Low-level method to set the input power setting for a sensor. * Values are: 0 - no power, 1 RCX active power, 2 power always on. **/ static native void setPowerTypeById(int aPortId, int aPortType); /** * Call Port Listeners. Used by ListenerThread. */ public synchronized void callListeners() { int newValue = readSensorValue(iPortId); for (int i = 0; i < iNumListeners; i++) iListeners[i].stateChanged(this, iPreviousValue, newValue); iPreviousValue = newValue; } /** * Low-level method to enable I2C on the port. * @param aPortId The port number for this device * @param mode I/O mode to use */ public static native void i2cEnableById(int aPortId, int mode); /** * Low-level method to disable I2C on the port. * * @param aPortId The port number for this device */ public static native void i2cDisableById(int aPortId); /** * Low-level method to test if I2C connection is busy. * @param aPortId The port number for this device * @return > 0 if busy 0 if not */ public static native int i2cBusyById(int aPortId); /** * Low-level method to start an I2C transaction. * @param aPortId The port number for this device * @param address The I2C address of the device * @param internalAddress The internal address to use for this operation * @param numInternalBytes The number of bytes in the internal address * @param buffer The buffer for write operations * @param numBytes Number of bytes to write or read * @param transferType 1==write 0==read * @return < 0 if there is an error */ public static native int i2cStartById(int aPortId, int address, int internalAddress, int numInternalBytes, byte[] buffer, int numBytes, int transferType); /** * Complete and I2C operation and retrieve any data read. * @param aPortId The Port number for the device * @param buffer The buffer to be used for read operations * @param numBytes Number of bytes to read * @return < 0 if the is an error, or number of bytes transferred */ public static native int i2cCompleteById(int aPortId, byte[] buffer, int numBytes); /** * Low-level method to enable I2C on the port. * @param mode The operating mode for the device */ public void i2cEnable(int mode) { i2cEnableById(iPortId, mode); } /** * Low-level method to disable I2C on the port. * */ public void i2cDisable() { i2cDisableById(iPortId); } /** * Low-level method to test if I2C connection is busy. * @return > 0 if the device is busy 0 if it is not */ public int i2cBusy() { return i2cBusyById(iPortId); } /** * Low-level method to start an I2C transaction. * @param address Address of the device * @param internalAddress Internal register address for this operation * @param numInternalBytes Size of the internal address * @param buffer Buffer for write operations * @param numBytes Number of bytes to read/write * @param transferType 1==write 0 ==read * @return < 0 error */ public int i2cStart(int address, int internalAddress, int numInternalBytes, byte[] buffer, int numBytes, int transferType) { return i2cStartById(iPortId, address, internalAddress, numInternalBytes, buffer, numBytes, transferType); } /** * Complete an I2C operation and transfer any read bytes * @param buffer Buffer for read data * @param numBytes Number of bytes to read * @return < 0 error otherwise number of bytes read. */ public int i2cComplete(byte[] buffer, int numBytes) { return i2cCompleteById(iPortId, buffer, numBytes); } /** * Low level method to set the operating mode for a sensor pin. * @param port The port number to use * @param pin The pin id * @param mode The new mode */ static native void setSensorPinMode(int port, int pin, int mode); /** * Set the output state of a sensor pin * @param port The port to use * @param pin The pin id * @param val The new output value (0/1) */ static native void setSensorPin(int port, int pin, int val); /** * Read the current state of a sensor port pin * @param port The port to read * @param pin The pin id. * @return The current pin state (0/1) */ static native int getSensorPin(int port, int pin); /** * Read the current ADC value from a sensor port pin * @param port The port to use. * @param pin The id of the pin to read (SP_DIGI1/SP_ANA) * @return The return from the ADC */ static native int readSensorPin(int port, int pin); /** * Low level method to set the operating mode for a sensor pin. * @param pin The pin id * @param mode The new mode */ public void setSensorPinMode(int pin, int mode) { setSensorPinMode(iPortId, pin, mode); } /** * Set the output state of a sensor pin * @param pin The pin id * @param val The new output value (0/1) */ public void setSensorPin(int pin, int val) { setSensorPin(iPortId, pin, val); } /** * Read the current state of a sensor port pin * @param pin The pin id. * @return The current pin state (0/1) */ public int getSensorPin(int pin) { return getSensorPin(iPortId, pin); } /** * Read the current ADC value from a sensor port pin * @param pin The id of the pin to read (SP_DIGI1/SP_ANA) * @return The return from the ADC */ public int readSensorPin(int pin) { return readSensorPin(iPortId, pin); } }