001package jmri.jmrix.rfid.protocol.em18; 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 EM-18 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 * @author Oscar A. Pruitt Copyright (C) 2015 024 * @since 4.1.2 025 */ 026public class Em18RfidProtocol extends RfidProtocol { 027 028 private static final int SPECIFICMAXSIZE = 12; 029 030 /** 031 * Constructor for EM-18 RFID Protocol. Used when a single reader is 032 * connected directly to a port, not via a concentrator. 033 */ 034 public Em18RfidProtocol() { 035 super(); 036 } 037 038 /** 039 * Constructor for EM-18 RFID Protocol. Supports the use of concentrators 040 * where a character range is used to determine the specific reader port. 041 * 042 * @param concentratorFirst character representing first concentrator port 043 * @param concentratorLast character representing last concentrator port 044 * @param portPosition position of port character in reply string 045 */ 046 public Em18RfidProtocol(char concentratorFirst, char concentratorLast, int portPosition) { 047 super(concentratorFirst, concentratorLast, portPosition); 048 } 049 050 public static final int getMaxSize() { 051 return SPECIFICMAXSIZE; 052 } 053 054 @Override 055 public String initString() { 056 // None required for EM-18 057 return ""; 058 } 059 060 @Override 061 public String getTag(AbstractMRReply msg) { 062 StringBuilder sb = new StringBuilder(10); 063 064 for (int i = 0; i < 10; i++) { 065 sb.append((char) msg.getElement(i)); 066 } 067 068 return sb.toString(); 069 } 070 071 @Override 072 public boolean providesChecksum() { 073 return true; 074 } 075 076 @Override 077 public String getCheckSum(AbstractMRReply msg) { 078 StringBuilder sb = new StringBuilder(2); 079 080 for (int i = 10; i < 12; i++) { 081 sb.append((char) msg.getElement(i)); 082 } 083 084 return sb.toString(); 085 } 086 087 @Override 088 public boolean isValid(AbstractMRReply msg) { 089 return (((!isConcentrator && msg.getElement(0) != 0x02 090 && (msg.getElement(SPECIFICMAXSIZE - 1) & 0xFF) != 0x03) 091 || (isConcentrator 092 && msg.getElement(portPosition) >= concentratorFirst 093 && msg.getElement(portPosition) <= concentratorLast 094 && (msg.getElement(SPECIFICMAXSIZE - 1) & 0xFF) != 0x3E)) 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 } 123 return false; 124 } 125 126 @Override 127 public String toMonitorString(AbstractMRReply msg) { 128 // check for valid message 129 if (isValid(msg)) { 130 StringBuilder sb = new StringBuilder(); 131 sb.append("Reply from EM-18 reader."); 132 if (isConcentrator) { 133 sb.append(" Reply from port "); 134 sb.append(getReaderPort(msg)); 135 } 136 sb.append(" Tag read "); 137 sb.append(getTag(msg)); 138 sb.append(" checksum "); 139 sb.append(getCheckSum(msg)); 140 sb.append(" valid? "); 141 sb.append(isCheckSumValid(msg) ? "yes" : "no"); 142 return sb.toString(); 143 } else { 144 return super.toMonitorString(msg); 145 } 146 } 147 148 private static final Logger log = LoggerFactory.getLogger(Em18RfidProtocol.class); 149 150}