Package org.nfctools.spi.tama

Source Code of org.nfctools.spi.tama.TamaReader

/**
* Copyright 2011-2012 Adrian Stabiszewski, as@nfctools.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*       http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.nfctools.spi.tama;

import java.io.IOException;

import org.nfctools.NfcTimeoutException;
import org.nfctools.io.ByteArrayReader;
import org.nfctools.utils.NfcUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Reader for the TAMA message format. This reader reads messages in the TAMA format and returns only the payload of a
* message (packet data) including the 0xD5 response byte. All ACK frames are silently ignored, but the first ACK frame
* must arrive within a timeout of 2 seconds. Any ERROR frames will be thrown as TamaExceptions containing the error
* code.
*
* If no data is available from the underlying ByteArrayReader this reader sleeps for 1ms.
*
* TODO check the checksum and throw a checksum exception
*
* TODO make the timeout configurable
*
* @see TamaException
*
*/
public class TamaReader implements ByteArrayReader {

  protected Logger log = LoggerFactory.getLogger(getClass());
  private final ByteArrayReader reader;

  private byte[] buffer = new byte[1024];
  private int bufPos = 0;
  private boolean useDataFrameTimeout = false;
  private long dataFrameTimeout = 0;

  public TamaReader(ByteArrayReader reader) {
    this.reader = reader;
  }

  @Override
  public void setTimeout(long millis) {
    dataFrameTimeout = millis;
    useDataFrameTimeout = millis >= 0;
    reader.setTimeout(millis);
  }

  @Override
  public int read(byte[] data, int offset, int length) throws IOException {
    byte[] response = readResponse();
    if (response.length > length - offset)
      throw new IllegalArgumentException("buffer too small for response, needed " + response.length + " bytes");

    System.arraycopy(response, 0, data, offset, response.length);
    return response.length;
  }

  public byte[] readResponse() throws IOException {
    long timeoutTillFirstAckFrame = 2000;
    boolean useAckFrameTimeout = true;
    long timeoutCounter = System.currentTimeMillis();
    long timeoutCounterForDataFrame = System.currentTimeMillis();
    while (true) {
      if (log.isTraceEnabled())
        log.trace("reading... @" + bufPos);
      int read = reader.read(buffer, bufPos, buffer.length - bufPos);
      if (read <= 0) {
        try {
          Thread.sleep(1);
        }
        catch (InterruptedException e) {
        }
      }
      if (read >= 0) {
        bufPos += read;
        if (log.isTraceEnabled())
          log.trace("data read: " + read + "  " + NfcUtils.convertBinToASCII(buffer, 0, bufPos) + "/"
              + bufPos);

        if (bufPos >= 6) // we need at least 6 bytes to identify a message
        {
          for (int x = 0; x < bufPos; x++) {
            if (x + 6 <= bufPos) // Check for ACK frame
            {
              if (TamaUtils.isACKFrame(buffer, x)) {
                byte[] resp = new byte[6];
                System.arraycopy(buffer, x, resp, 0, resp.length); // Copy data into response array
                if (log.isDebugEnabled())
                  log.debug("Ack frame:" + NfcUtils.convertBinToASCII(resp));
                removeFrameFromBuffer(x, resp);

                useAckFrameTimeout = false;
                timeoutCounterForDataFrame = System.currentTimeMillis();
                // Ignore ACK Frames
              }
            }

            if (x + 8 <= bufPos) // Check for ERROR frame
            {
              if (TamaUtils.isErrorFrame(buffer, x)) {
                byte[] resp = new byte[8];
                System.arraycopy(buffer, x, resp, 0, resp.length); // Copy data into response array
                removeFrameFromBuffer(x, resp);
                int status = TamaUtils.getErrorCodeFromStatus(resp[5]);
                throw new TamaException(status);
              }
            }

            if (x + 5 <= bufPos) // Check for DATA frame
            {
              int msgLength = (buffer[x + 3] & 0xFF) + 7;

              if ((buffer[x] == 0x00) && (buffer[x + 1] == 0x00) && (buffer[x + 2] == (byte)0xFF)
                  && (msgLength + x <= bufPos) && buffer[x + 3] == (byte)-buffer[x + 4]) {
                byte[] resp = new byte[msgLength];
                System.arraycopy(buffer, x, resp, 0, msgLength);
                if (log.isDebugEnabled())
                  log.debug("Data frame:" + NfcUtils.convertBinToASCII(resp));
                removeFrameFromBuffer(x, resp);
                return TamaUtils.unpackPayload(resp);
              }
            }
          }
        }
      }
      if (useDataFrameTimeout && System.currentTimeMillis() - timeoutCounterForDataFrame > dataFrameTimeout) {
        resetBuffer();
        throw new NfcTimeoutException();
      }

      if ((useAckFrameTimeout) && (System.currentTimeMillis() - timeoutCounter > timeoutTillFirstAckFrame)) {
        resetBuffer();
        throw new NfcTimeoutException("No complete message within timeout. Msg: ["
            + NfcUtils.convertBinToASCII(buffer, 0, bufPos) + "] Length: " + bufPos);
      }
    }
  }

  private void resetBuffer() {
    bufPos = 0;

  }

  private void removeFrameFromBuffer(int x, byte[] resp) {
    System.arraycopy(buffer, x + resp.length, buffer, 0, bufPos - (resp.length + x)); // Move data in the buffer
    bufPos -= (resp.length + x);
  }
}
TOP

Related Classes of org.nfctools.spi.tama.TamaReader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.