001package jmri.jmrix.dcc4pc;
002
003import java.util.ArrayList;
004
005import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
006import org.slf4j.Logger;
007import org.slf4j.LoggerFactory;
008
009/**
010 * Implement BoardManager for Dcc4Pc systems.
011 *
012 * @author Kevin Dickerson Copyright (C) 2009
013 */
014public class Dcc4PcBoardManager implements Dcc4PcListener {
015
016    public Dcc4PcBoardManager(Dcc4PcTrafficController tc, Dcc4PcSensorManager senManager) {
017        this.tc = tc;
018        this.senManager = senManager;
019        resetBusSpeeds();
020        for (int x = MINRC; x < MAXRC; x++){
021            addBoard(x);
022        }
023    }
024
025    /**
026     * Start from 8 kbps on both sides: a board that lost power has gone back
027     * to 8 kbps, but the interface may still be at the speed a previous
028     * session set, or the other way round.
029     */
030    private void resetBusSpeeds() {
031        tc.sendDcc4PcMessage(Dcc4PcMessage.busResetSpeeds(), null);
032        for (int x = MINRC; x < MAXRC; x++){
033            tc.sendDcc4PcMessage(Dcc4PcMessage.busSetSpeed(x, 0), null);
034        }
035    }
036
037    /**
038     * The interface's port has been reopened after a failure. Reset the bus
039     * speeds as at startup, and look again for boards not found yet.
040     */
041    void rediscover() {
042        resetBusSpeeds();
043        boardsToDiscover.clear();
044        for (int x = MINRC; x < MAXRC; x++){
045            addBoard(x);
046        }
047    }
048    
049    private static final int MINRC = 0;
050    private static final int MAXRC = 4;
051    
052    ArrayList<Integer> boardsToDiscover = new ArrayList<>();
053
054    Dcc4PcTrafficController tc;
055    Dcc4PcSensorManager senManager;
056
057    public void notifyReply(Dcc4PcReply m) {
058        // is this a list of sensors?
059    }
060
061    public void notifyMessage(Dcc4PcMessage m) {
062        // messages are ignored
063    }
064   
065    protected void addBoard(int newBoard){
066        if(!senManager.isBoardCreated(newBoard) && !boardsToDiscover.contains(newBoard)){
067            boardsToDiscover.add(newBoard);
068            Dcc4PcMessage m = Dcc4PcMessage.getInfo(newBoard);
069            m.setTimeout(1000);
070            m.setRetries(2);
071            tc.sendDcc4PcMessage(m, this);  
072        }
073    }
074    
075    @Override
076    @SuppressFBWarnings(value="DLS_DEAD_LOCAL_STORE", justification="See issue #6132")
077    public void reply(Dcc4PcReply r) {
078        if (log.isDebugEnabled()) {
079            log.debug("Reply details sm: {}", r.toHexString());
080        }
081        if(r.getBoard() == -1){
082            return;
083        }
084        if(r.getNumDataElements()==0 && r.getElement(0) == 0x00) {
085            //Simple acknowledgement reply, no further action required
086            return;
087        }
088        int board = r.getBoard();
089        if (r.isError()) {
090            boardsToDiscover.remove((Integer)board);
091        } else {
092            if (r.getMessageType()==Dcc4PcMessage.INFO) {
093                log.debug("Get Info for board {}: {}", board, r.toString());
094                String version;
095                int inputs;
096                int encoding;
097
098                int i = 0;
099                StringBuilder buf = new StringBuilder();
100                while (i < 4) {
101                    buf.append((char) r.getElement(i));
102                    i++;
103                }
104                //skip supported speeds for now
105                String str = buf.toString(); // DLS_DEAD_LOCAL_STORE here: str is unused
106                //We have a reader, now to find out other information about it
107                if (str.equals("RCRD")) {
108                    i = i + 2;
109                    str = str + " ver ";
110                    str = str + r.getElement(i) + ".";
111                    version = r.getElement(i) + "." + r.getElement(i + 1);
112                    i++;
113                    str = str + r.getElement(i) + ", Inputs : ";
114                    i++;
115                    inputs = r.getElement(i);
116                    str = str + r.getElement(i) + ", Encoding : ";
117                    i++;
118                    encoding = r.getElement(i);
119                    if ((r.getElement(i) & 0x01) == 0x01) {
120                        str = str + "Supports Cooked RailCom Encoding";
121                    } else {
122                        str = str + "Supports Raw RailCom Encoding";
123                    }
124
125                    senManager.addActiveBoard(board, version, inputs, encoding);
126
127                    Dcc4PcMessage m = Dcc4PcMessage.getDescription(board);
128                    m.setTimeout(2000);
129                    tc.sendDcc4PcMessage(m, this);
130                    boardsToDiscover.remove((Integer)board);
131                }
132            } else if (r.getMessageType()==Dcc4PcMessage.DESC) {
133                log.debug("Get Description for board {}: {}", board, r.toString());
134
135                senManager.setBoardDescription(board, r.toString());
136                Dcc4PcMessage m = Dcc4PcMessage.getEnabledInputs(board);
137                m.setTimeout(2000);
138                m.setRetries(2);
139                log.debug("Sending {}", m);
140                tc.sendDcc4PcMessage(m, this);
141            } else if (r.getMessageType()==Dcc4PcMessage.CHILDENABLEDINPUTS) {
142                log.debug("Make Sensors for board {}: {}", board, r.toString());
143                senManager.createSensorsForBoard(r);
144            }
145        }
146    }
147
148    @Override
149    public void handleTimeout(Dcc4PcMessage m) {
150        if (log.isDebugEnabled()) {
151            log.debug("timeout received to our last message {}", m.toString());
152        }
153        log.debug("Timeout to message {} for board {}", m.toString(), m.getBoard());
154    }
155
156    @Override
157    public void message(Dcc4PcMessage m) {
158
159    }
160    
161    private static final Logger log = LoggerFactory.getLogger(Dcc4PcBoardManager.class);
162}