001package jmri.jmrix.rfid.protocol.olimex;
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 Olimex MOD-RFID1356MIFARE 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 B. Milhaupt    Copyright (C) 2017
024 * @since 4.9.4
025 */
026public class OlimexRfid1356mifareProtocol extends RfidProtocol {
027
028    public static final int SPECIFICMAXSIZE = 13;
029    public final String initialize = "mt100\r\ne0\r\n"; // NOI18N
030
031    public static final int getMaxSize() {
032        return SPECIFICMAXSIZE;
033    }
034
035    @Override
036    public String initString() {
037        // Continuous scanning, single report per seen tag
038        return initialize;
039    }
040
041    @Override
042    public String getTag(AbstractMRReply msg) {
043        StringBuilder sb = new StringBuilder(10);
044
045        for (int i = 3; i < SPECIFICMAXSIZE-2; i++) {
046            sb.append((char) msg.getElement(i));
047        }
048
049        return sb.toString();
050    }
051
052    @Override
053    public String getCheckSum(AbstractMRReply msg) {
054        return "";
055    }
056
057    @Override
058    public boolean isValid(AbstractMRReply msg) {
059        /* Typical message of "tag receive":
060            \r\n-C4178b55\r\n
061        */
062        return ((!isConcentrator && msg.getElement(2) == 0x2D)
063                || (isConcentrator
064                && msg.getElement(portPosition) >= concentratorFirst
065                && msg.getElement(portPosition) <= concentratorLast))
066                && msg.getElement(SPECIFICMAXSIZE - 1) == 0x0A;
067    }
068
069    @Override
070    public boolean endOfMessage(AbstractMRReply msg) {
071        if (msg.getNumDataElements() == SPECIFICMAXSIZE) {
072            /* Check end of expected response to tag read message:
073                \r\n-C4178b55\r\n
074            */
075            if (((msg.getElement(SPECIFICMAXSIZE - 1) & 0xFF) == 0x0A)
076                    && ((msg.getElement(SPECIFICMAXSIZE - 2) & 0xFF) == 0x0D)
077                    && ((msg.getElement(SPECIFICMAXSIZE - 3) & 0xFF) != 0x0D)
078                    && ((msg.getElement(SPECIFICMAXSIZE - 3) & 0xFF) != 0x0A)) {
079                return true;
080            }
081            /* Check end of message of expected response to init message:
082                mt100
083                OK>e0
084                OK>
085
086            or, in hex:
087                6Dh 74h 31h 30h 30h  0Dh0Ah
088                4Fh 4Bh 0Ah  0Dh3Eh 07h 65h 30h  0Dh0Ah
089                4Fh 4Bh 0Ah  0Dh3Eh 07h
090            */
091
092            int i;
093            for (i = 0; i < initialize.length(); ++ i) {
094                if (msg.getElement(i) != initialize.charAt(i)) {
095                    return false;
096                }
097            }
098            if (msg.getElement(i) != 'O') return false;
099            if (msg.getElement(i+1) != 'K') return false;
100            if (msg.getElement(i+2) != '\n') return false;
101            if (msg.getElement(i+3) != '\r') return false;
102            if (msg.getElement(i+4) != '>') return false;
103            if (msg.getElement(i+5) != 0x07) return false;
104            if (msg.getElement(i+6) != 'e') return false;
105            if (msg.getElement(i+7) != '0') return false;
106            if (msg.getElement(i+8) != '\n') return false;
107            if (msg.getElement(i+9) != '\r') return false;
108            if (msg.getElement(i+10) != 'O') return false;
109            if (msg.getElement(i+11) != 'K') return false;
110
111            if (log.isDebugEnabled()) {
112                log.debug("Not a correctly formed message"); // NOI18N
113            }
114            return true;
115        }
116        return false;
117    }
118
119    @Override
120    public String toMonitorString(AbstractMRReply msg) {
121        // check for valid message
122        if (isValid(msg)) {
123            StringBuilder sb = new StringBuilder();
124            sb.append("Reply from Olimex MOD-RFID1356MIFARE reader.");
125            if (isConcentrator) {
126                sb.append(" Reply from port ");
127                sb.append(getReaderPort(msg));
128            }
129            sb.append(" Tag read ");
130            sb.append(getTag(msg));
131            return sb.toString();
132        } else {
133            return super.toMonitorString(msg);
134        }
135    }
136
137    private static final Logger log = LoggerFactory.getLogger(OlimexRfid1356mifareProtocol.class.getName());
138
139}