001package jmri.jmrix.rfid.protocol.coreid; 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 CORE-ID / ID-Innovations 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 CoreIdRfidProtocol extends RfidProtocol { 025 026 private static final int SPECIFICMAXSIZE = 16; 027 028 /** 029 * Constructor for CORE-ID RFID Protocol. Used when a single reader is 030 * connected directly to a port, not via a concentrator. 031 */ 032 public CoreIdRfidProtocol() { 033 super(); 034 } 035 036 /** 037 * Constructor for CORE-ID RFID Protocol. Supports the use of concentrators 038 * where a character range is used to determine the specific reader port. 039 * 040 * @param concentratorFirst character representing first concentrator port 041 * @param concentratorLast character representing last concentrator port 042 * @param portPosition position of port character in reply string 043 */ 044 public CoreIdRfidProtocol(char concentratorFirst, char concentratorLast, int portPosition) { 045 super(concentratorFirst, concentratorLast, portPosition); 046 } 047 048 public static final int getMaxSize() { 049 return SPECIFICMAXSIZE; 050 } 051 052 @Override 053 public String initString() { 054 // None required for CORE-ID 055 return ""; 056 } 057 058 @Override 059 public String getTag(AbstractMRReply msg) { 060 StringBuilder sb = new StringBuilder(10); 061 062 for (int i = 1; i < 11; i++) { 063 sb.append((char) msg.getElement(i)); 064 } 065 066 return sb.toString(); 067 } 068 069 @Override 070 public boolean providesChecksum() { 071 return true; 072 } 073 074 @Override 075 public String getCheckSum(AbstractMRReply msg) { 076 StringBuilder sb = new StringBuilder(2); 077 078 for (int i = 11; i < 13; i++) { 079 sb.append((char) msg.getElement(i)); 080 } 081 082 return sb.toString(); 083 } 084 085 @Override 086 public boolean isValid(AbstractMRReply msg) { 087 return (((!isConcentrator && msg.getElement(0) == 0x02 088 && (msg.getElement(SPECIFICMAXSIZE - 1) & 0xFF) == 0x03) 089 || (isConcentrator 090 && msg.getElement(portPosition) >= concentratorFirst 091 && msg.getElement(portPosition) <= concentratorLast 092 && (msg.getElement(SPECIFICMAXSIZE - 1) & 0xFF) == 0x3E)) 093 && (msg.getElement(SPECIFICMAXSIZE - 2) & 0xFF) == 0x0A 094 && (msg.getElement(SPECIFICMAXSIZE - 3) & 0xFF) == 0x0D 095 && isCheckSumValid(msg)); 096 } 097 098 public boolean isCheckSumValid(AbstractMRReply msg) { 099 byte[] tag = convertHexString(getTag(msg)); 100 int checksum = 0; 101 for (int i = 0; i < 5; i++) { 102 checksum = checksum ^ tag[i]; 103 log.debug("read {}", tag[i]); 104 } 105 log.debug("Checksum: {} converted: {}", getCheckSum(msg), convertHexString(getCheckSum(msg))[0]); 106 return checksum == convertHexString(getCheckSum(msg))[0]; 107 } 108 109 @Override 110 public boolean endOfMessage(AbstractMRReply msg) { 111 if (msg.getNumDataElements() == SPECIFICMAXSIZE) { 112 if (((msg.getElement(SPECIFICMAXSIZE - 1) & 0xFF) == 0x03 113 || (msg.getElement(SPECIFICMAXSIZE - 1) & 0xFF) == 0x3E) 114 && (msg.getElement(SPECIFICMAXSIZE - 2) & 0xFF) == 0x0A 115 && (msg.getElement(SPECIFICMAXSIZE - 3) & 0xFF) == 0x0D) { 116 return true; 117 } 118 if (log.isDebugEnabled()) { 119 log.debug("Not a correctly formed message"); 120 } 121 return true; 122 } else if (isConcentrator && (msg.getNumDataElements() == 1) && (msg.getElement(0) & 0xFF) == 0x3E) { 123 log.debug("Init message from Concentrator: {}", msg); 124 return true; 125 } 126 return false; 127 } 128 129 @Override 130 public String toMonitorString(AbstractMRReply msg) { 131 // check for valid message 132 if (isValid(msg)) { 133 StringBuilder sb = new StringBuilder(); 134 sb.append("Reply from CORE-ID reader."); 135 if (isConcentrator) { 136 sb.append(" Reply from port "); 137 sb.append(getReaderPort(msg)); 138 } 139 sb.append(" Tag read "); 140 sb.append(getTag(msg)); 141 sb.append(" checksum "); 142 sb.append(getCheckSum(msg)); 143 sb.append(" valid? "); 144 sb.append(isCheckSumValid(msg) ? "yes" : "no"); 145 return sb.toString(); 146 } else { 147 return super.toMonitorString(msg); 148 } 149 } 150 151 private static final Logger log = LoggerFactory.getLogger(CoreIdRfidProtocol.class); 152 153}