001/* 
002 * DCCppRegisterManager.java
003 */
004package jmri.jmrix.dccpp;
005
006import org.slf4j.Logger;
007import org.slf4j.LoggerFactory;
008
009/**
010 * Defines and Manages the Registers (~ slots) for DCC++ Base Station
011 *
012 * @author Mark Underwood Copyright (C) 2015
013 * @author Harald Barth Copyright (C) 2019
014 *
015 */
016
017/* A few notes on implementation
018 *
019 * This class is used by the DCCppCommandStation to allocate/free and keep
020 * track of the registers in the BaseStation.  This is assuming the BaseStation
021 * doesn't provide its own method of allocating registers.  It would be better
022 * if the BaseStation handled this, since there may be more than just JMRI
023 * asking for slots.
024 */
025public class DCCppRegisterManager {
026
027    protected int maxMainRegisters = 0;
028    protected DCCppRegister registers[];
029
030    // Constructors
031    public DCCppRegisterManager(int maxMainRegisters) {
032        log.debug("DCCppRegisterManager({}) called.", maxMainRegisters);
033        this.maxMainRegisters = maxMainRegisters;
034        registers = new DCCppRegister[maxMainRegisters];
035        for (int i = 0; i < maxMainRegisters; i++) {
036            registers[i] = new DCCppRegister();
037        }
038    }
039
040    public DCCppRegisterManager() {
041        this(DCCppConstants.MAX_MAIN_REGISTERS);
042    }
043
044    // Member functions
045    public int requestRegister(int addr) {
046        int free = DCCppConstants.NO_REGISTER_FREE;
047
048        for (int i = 0; i < maxMainRegisters; i++) {
049            if (registers[i].getAddress() == addr) {
050                registers[i].allocate();
051                log.debug("requestRegister({}) returns {}", addr, i);
052                return (i);
053            }
054            // This might be a free spot
055            if (free == DCCppConstants.NO_REGISTER_FREE && registers[i].isFree()) {
056                free = i;
057            }
058        }
059        // If we've made it here, there isn't a register that already matches.
060        // Look if we found a free one on the way through the list above
061        // if not, there is no available slot.  Bummer.
062        if (free != DCCppConstants.NO_REGISTER_FREE) {
063            registers[free].allocate();
064            registers[free].setAddress(addr);
065        }
066        log.debug("requestRegister({}) returns {}", addr, free);
067        return (free);
068    }
069
070    public void releaseRegister(int addr) {
071        for (int i = 0; i < maxMainRegisters; i++) {
072            if (registers[i].getAddress() == addr) {
073                registers[i].release();
074            }
075        }
076    }
077
078    // NOTE: queryRegisterNum does not increment the use count.
079    public int getRegisterNum(int addr) {
080        for (int i = 0; i < maxMainRegisters; i++) {
081            if (registers[i].getAddress() == addr) {
082                return (i + 1);
083            }
084        }
085        // Optional:  If a nonexistent register is requested, create one?
086        return (DCCppConstants.NO_REGISTER_FREE);
087    }
088
089    public int getRegisterAddress(int num) {
090        return (registers[num - 1].getAddress());
091    }
092    /*
093     * We need to register for logging
094     */
095    private final static Logger log = LoggerFactory.getLogger(DCCppRegisterManager.class);
096
097}
098
099class DCCppRegister {
100
101    private int user_count;
102    private int address;
103
104    public DCCppRegister() {
105        user_count = 0;
106        address = DCCppConstants.REGISTER_UNALLOCATED;
107    }
108
109    public int getUserCount() {
110        return (user_count);
111    }
112
113    public void setUserCount(int i) {
114        user_count = i;
115    } // Don't use this...
116
117    public void incUserCount() {
118        user_count++;
119    }
120
121    public void decUserCount() {
122        if (user_count > 0) {
123            user_count--;
124        }
125        if (user_count == 0) {
126            address = DCCppConstants.REGISTER_UNALLOCATED;
127        }
128    }
129
130    public int getAddress() {
131        return (address);
132    }
133
134    public void setAddress(int a) {
135        address = a;
136    }
137
138    public boolean isAllocated() {
139        return (user_count > 0);
140    }
141
142    public boolean isFree() {
143        return (user_count == 0);
144    }
145
146    public void allocate() {
147        this.incUserCount();
148    }
149
150    public void release() {
151        this.decUserCount();
152    }
153}