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

lejos.hardware.sensor.RFIDSensor Maven / Gradle / Ivy

Go to download

leJOS (pronounced like the Spanish word "lejos" for "far") is a tiny Java Virtual Machine. In 2013 it was ported to the LEGO EV3 brick.

The newest version!
package lejos.hardware.sensor;

import lejos.hardware.port.I2CPort;
import lejos.hardware.port.Port;
import lejos.utility.Delay;

/**
 * Support for the Codatex RFID Sensor.
 * This device requires delays between various commands for them to
 * function correctly, it also enters a sleep mode and requires to be woken up.
 * The methods in this class fall into two categories.
 * Basic commands
 * These pretty much match one to one with the device command set. They do not
 * incorporate any delays, or wake up code. They can be used by user programs
 * but if they are then appropriate delays etc. must be used. They are provided
 * to allow more sophisticated user programs access to the low level device.
 *
 * High level commands
 * These provide higher level access to the device and are often implemented via
 * several i2c commands. They do include delays and wake up logic.
 *
 * @author andy
 */
public class RFIDSensor extends I2CSensor
{
    /*
     * Notes
     * This sensor is a little tricky to deal with. It will enter a sleep mode
     * if not used for a while and so will need to be woken up. Plus it seems
     * very sensitive to timing of requests (hence the use of various delays).
     */
    // Command Registers and bytes
    private static final int REG_CMD = 0x41;
    private static final byte CMD_STOP = 0;
    private static final byte CMD_SINGLEREAD = 1;
    private static final byte CMD_CONTINUOUSREAD = 2;
    private static final byte CMD_BOOTLOADER = (byte)0x81;
    private static final byte CMD_STARTFIRMWARE = (byte)0x83;

    // Data registers
    private static final int REG_STATUS = 0x32;
    private static final int REG_DATA = 0x42;
    private static final int LEN_DATA = 5;
    private static final int REG_SERIALNO = 0xA0;
    private static final int LEN_SERIALNO = 16;

    private static final int DEFAULT_ADDRESS = 4;

    // Various delays
    private static final int DELAY_WAKEUP = 5;
    private static final int DELAY_FIRMWARE = 100;
    private static final int DELAY_ACQUIRE = 250;
    private static final int DELAY_READ = 200;

    private byte buf1[] = new byte[1];
    private long nextRead = now();

    private void init()
    {
        // We seem to need to give the device a bit of a kick to get it going
        // doing a read seems to do the job...
        wakeUp();
        readTransponder(false);
    }
    /**
     * Create a class to provide access to the device. Perform device
     * initialization.
     * @param port The sensor port to use for this device.
     */
    public RFIDSensor(I2CPort port)
    {
        super(port, DEFAULT_ADDRESS);
        init();
    }
    
    /**
     * Create a class to provide access to the device. Perform device
     * initialization.
     * @param port The sensor port to use for this device.
     */
    public RFIDSensor(Port port)
    {
        super(port, DEFAULT_ADDRESS, TYPE_LOWSPEED_9V);
        init();
    }

    /**
     * Helper function, return current time, used as basis of required inter
     * command delays.
     * @return
     */
    private long now()
    {
        return System.currentTimeMillis();
    }

    /**
     * Helper function wait until a specific time has arrived
     */
    private void waitUntil(long target)
    {
        long d = target - now();
        if (d > 0)
            Delay.msDelay(d);
    }


    /**
     * The sensor will go into a power save mode after a short time. This means
     * that we will need to wake it up before issuing commands. Includes
     * the required Delay.msDelay.
     */
    public void wakeUp()
    {
        // Simply send a dummy command to the device
        sendData(0, (byte)0);
        Delay.msDelay(DELAY_WAKEUP);
    }


    /**
     * We over-ride the default implementation to ensure that the device is
     * awake before we talk to it.
     * @param register The register to read the string from.
     * @param len
     * @return The requested string.
     */
    protected String fetchString(byte register, int len)
    {
        wakeUp();
        return super.fetchString(register, len);
    }

    /**
     * Start the firmware on the RFID device.
     * NOTES: It seems that you need to issue this command (or some other
     * firmware command), prior to attempting to read the version number etc.
     * Does not wake up the device or contain any delays.
     */
    public void startFirmware()
    {
        sendData(REG_CMD, CMD_STARTFIRMWARE);
    }

    /**
     * Enter boot loader mode.
     * Does not wake up the device or include any delays.
     *
     */
    public void startBootLoader()
    {
        sendData(REG_CMD, CMD_BOOTLOADER);
    }

    /**
     * Obtain the serial number of the RFID Sensor.
     * NOTES: To obtain the serial number the device must be in boot loader
     * mode. This function will switch into this mode and then return to
     * normal mode on completion.
     * @return the 12 byte serial number if ok or null if there is an error
     */
    public byte [] getSerialNo()
    {
        wakeUp();
        // must be in boot loader mode
        startBootLoader();
        Delay.msDelay(DELAY_FIRMWARE);
        byte [] ret = new byte[LEN_SERIALNO];
        getData(REG_SERIALNO, ret, ret.length);
        startFirmware();
        return ret;
    }

    /**
     * Read the status from the device.
     * Does not wake up the device or include any delays.
     * @return 1 data available 0 no data < 0 error
     */
    public int getStatus()
    {
        getData(REG_STATUS, buf1, buf1.length);
        return (int)buf1[0];
    }

    /**
     * Start a single read from the device.
     * Does not wake up the device or include any delays.
     */
    public void startSingleRead()
    {
        sendData(REG_CMD, CMD_SINGLEREAD);
    }

    /**
     * Start continually reading from the device.
     * Does not wake up the device or include any delays.
     */
    public void startContinuousRead()
    {
        sendData(REG_CMD, CMD_CONTINUOUSREAD);
    }

    /**
     * Send a stop command to the device.
     * Places the device into sleep mode.
     */
    public void stop()
    {
        sendData(REG_CMD, CMD_STOP);
    }

    /**
     * Read a transponder id.
     * Reads the transponder using either continuous or single shot mode. If
     * using single shot mode the tag must me available now. If using continuous
     * mode then after the first call, the tag can be presented at any time
     * and a subsequent read will return the results.
     * @param continuous Should we use continuous mode
     * @return null if error or no data available, otherwise an array of five id bytes
     */
    public byte [] readTransponder(boolean continuous)
    {
        // Wait until a new read is valid
        waitUntil(nextRead);
        wakeUp();
        if (continuous)
        {
            // If not ready, start a new command
            if (getStatus() <= 0)
            {
                startContinuousRead();
                Delay.msDelay(DELAY_ACQUIRE);
            }
        }
        else
        {
            startSingleRead();
            Delay.msDelay(DELAY_ACQUIRE);
        }
        // make a note of when it is safe to do another read.
        nextRead = now() + DELAY_READ;
        // Get the data
        boolean valid = false;
        byte [] ret = new byte[LEN_DATA];
        for(int i = 0; i < ret.length; i++)
        {
            getData(REG_DATA+i, buf1, buf1.length);
            ret[i] = buf1[0];
            if (buf1[0] != 0)
                valid = true;
        }
        return (valid ? ret : null);
    }

    public long readTransponderAsLong(boolean continuous)
    {
        byte [] id = readTransponder(continuous);
        if (id == null) return 0;
        long ret = 0;
        for(int i = id.length - 1; i >= 0; i--)
        {
            ret <<= 8;
            ret |= ((long)id[i] & 0xff);
        }
        return ret;
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy