001package jmri.jmrix.rfid.protocol.seeedstudio; 002 003import jmri.jmrix.AbstractMRReply; 004import jmri.jmrix.rfid.RfidProtocol; 005import org.slf4j.Logger; 006import org.slf4j.LoggerFactory; 007 008/** 009 * Common routines to extract the Tag information and validate checksum for 010 * implementations that use the SeeedStudio protocol. 011 * <hr> 012 * This file is part of JMRI. 013 * <p> 014 * JMRI is free software; you can redistribute it and/or modify it under the 015 * terms of version 2 of the GNU General Public License as published by the Free 016 * Software Foundation. See the "COPYING" file for a copy of this license. 017 * <p> 018 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 019 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 020 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 021 * 022 * @author Matthew Harris Copyright (C) 2014 023 */ 024public class SeeedStudioRfidProtocol extends RfidProtocol { 025 026 private static final int SPECIFICMAXSIZE = 14; 027 028 /** 029 * Constructor for SeeedStudio RFID Protocol. Used when a single reader is 030 * connected directly to a port, not via a concentrator. 031 */ 032 public SeeedStudioRfidProtocol() { 033 super(); 034 } 035 036 /** 037 * Constructor for SeeedStudio RFID Protocol. Supports the use of 038 * concentrators where a character range is used to determine the specific 039 * reader port. 040 * 041 * @param concentratorFirst character representing first concentrator port 042 * @param concentratorLast character representing last concentrator port 043 * @param portPosition position of port character in reply string 044 */ 045 public SeeedStudioRfidProtocol(char concentratorFirst, char concentratorLast, int portPosition) { 046 super(concentratorFirst, concentratorLast, portPosition); 047 } 048 049 public static final int getMaxSize() { 050 return SPECIFICMAXSIZE; 051 } 052 053 @Override 054 public String initString() { 055 // None required for SeeedStudio 056 return ""; 057 } 058 059 @Override 060 public String getTag(AbstractMRReply msg) { 061 StringBuilder sb = new StringBuilder(10); 062 063 for (int i = 1; i < 11; i++) { 064 sb.append((char) msg.getElement(i)); 065 } 066 067 return sb.toString(); 068 } 069 070 @Override 071 public boolean providesChecksum() { 072 return true; 073 } 074 075 @Override 076 public String getCheckSum(AbstractMRReply msg) { 077 StringBuilder sb = new StringBuilder(2); 078 079 for (int i = 11; i < 13; i++) { 080 sb.append((char) msg.getElement(i)); 081 } 082 083 return sb.toString(); 084 } 085 086 @Override 087 public boolean isValid(AbstractMRReply msg) { 088 return (((!isConcentrator && msg.getElement(0) == 0x02 089 && (msg.getElement(SPECIFICMAXSIZE - 1) & 0xFF) == 0x03) 090 || (isConcentrator 091 && msg.getElement(portPosition) >= concentratorFirst 092 && msg.getElement(portPosition) <= concentratorLast 093 && (msg.getElement(SPECIFICMAXSIZE - 1) & 0xFF) == 0x3E)) 094 && isCheckSumValid(msg)); 095 } 096 097 public boolean isCheckSumValid(AbstractMRReply msg) { 098 byte[] tag = convertHexString(getTag(msg)); 099 int checksum = 0; 100 for (int i = 0; i < 5; i++) { 101 checksum = checksum ^ tag[i]; 102 log.debug("read {}", tag[i]); 103 } 104 log.debug("Checksum: {} converted: {}", getCheckSum(msg), convertHexString(getCheckSum(msg))[0]); 105 return checksum == convertHexString(getCheckSum(msg))[0]; 106 } 107 108 @Override 109 public boolean endOfMessage(AbstractMRReply msg) { 110 if (msg.getNumDataElements() == SPECIFICMAXSIZE) { 111 if (((msg.getElement(SPECIFICMAXSIZE - 1) & 0xFF) == 0x03 112 || (msg.getElement(SPECIFICMAXSIZE - 1) & 0xFF) == 0x3E) 113 && (msg.getElement(SPECIFICMAXSIZE - 2) & 0xFF) == 0x0A 114 && (msg.getElement(SPECIFICMAXSIZE - 3) & 0xFF) == 0x0D) { 115 return true; 116 } 117 if (log.isDebugEnabled()) { 118 log.debug("Not a correctly formed message"); 119 } 120 return true; 121 } 122 return false; 123 } 124 125 @Override 126 public String toMonitorString(AbstractMRReply msg) { 127 // check for valid message 128 if (isValid(msg)) { 129 StringBuilder sb = new StringBuilder(); 130 sb.append("Reply from SeeedStudio reader."); 131 if (isConcentrator) { 132 sb.append(" Reply from port "); 133 sb.append(getReaderPort(msg)); 134 } 135 sb.append(" Tag read "); 136 sb.append(getTag(msg)); 137 sb.append(" checksum "); 138 sb.append(getCheckSum(msg)); 139 sb.append(" valid? "); 140 sb.append(isCheckSumValid(msg) ? "yes" : "no"); 141 return sb.toString(); 142 } else { 143 return super.toMonitorString(msg); 144 } 145 } 146 147 private static final Logger log = LoggerFactory.getLogger(SeeedStudioRfidProtocol.class); 148 149}