package stamp.peripheral.sensor.rfid;
import stamp.core.*;

/**
 * Class for Parallax RFID reader serial (#28140)
 *
 * When a valid RFID transponder tag is placed within range of the activated reader, the unique ID will be
 * transmitted as a 12-byte ASCII string via the TTL-level SOUT (Serial Output) pin in the following format:
 *
 * MSB LSB
 *  Startbyte Unique ID Unique ID Unique ID Unique ID Unique ID Unique ID Unique ID Unique ID Unique ID Unique ID Stopbyte
 *    0x0A     Digit 1   Digit 2   Digit 3   Digit 4   Digit 5   Digit 6   Digit 7   Digit 8   Digit 9   Digit 10   0x0D
 *
 * The startbyte and stopbyte are used to easily identify that a correct string has been received from the
 * reader (they correspond to a linefeed and carriage return characters, respectively). The middle ten bytes
 * are the actual tag's unique ID. All communication is 8 data bits, no parity, 1 stop bit, non-inverted,
 * least significant bit first (8N1). The baud rate is configured for 2400bps.
 */

public class Rfid_Reader_Serial {

  private Uart rx;
  private int enablePin;
  private StringBuffer buf = new StringBuffer(10);
  private int state = 0;

  /**
   * Constructor.
   *
   * @param rx Uart to receive rfid data (2400 baud)
   * @param enablePin Pin to enable rfid reader, 0 if enable pin permanently grounded
   */
  public Rfid_Reader_Serial(Uart rx, int enablePin) {
    this.rx = rx;
    this.enablePin = enablePin;
    on();
  }

  /**
   * Turn rfid reader on.
   */
  public void on() {
    if (enablePin != 0)
      CPU.writePin(enablePin,false);
  }

  /**
   * Turn rfid reader off.
   */
  public void off() {
    if (enablePin != 0)
      CPU.writePin(enablePin,true);
  }

  /**
   * Poll rfid reader for data.
   *
   * @return StringBuffer holding 10 digits, or null.
   */
  public StringBuffer poll() {
    int c;
    if (!rx.byteAvailable()) return null;
    c = rx.receiveByte();
    switch (state) {
      case 0:  //wait for startbyte
               if (c == 0x0A) {
                 state++;
                 buf.clear();
               }
               return null;
      case 11: //wait for stopbyte
               state = 0;
               if (c != 0x0D) return null;
               return buf;
      default: //receive tag number digits
               if ((c < '0') || (c > '9')) {
                 state = 0;
                 return null;
               }
               buf.append((char)c);
               state++;
               return null;
    }
  }

  /**
   * Check tag against array of valid tags.
   *
   * @param tag Tag to check
   * @param validTags Array with valid tags, last entry must be empty string "".
   * @return True if tag valid, false otherwise.
   */
  public boolean isValid(StringBuffer tag, String[] validTags) {
    int index = 0;
    if (tag == null) return false;
    do {
      if (validTags[index].equals("")) return false;
      if (tag.toString().equals(validTags[index])) return true; //compare strings
      index++;
    } while (true);
  }

}
 