001package jmri.jmrix.cmri.serial.serialdriver.configurexml;
002
003import java.util.List;
004import java.util.StringTokenizer;
005
006import jmri.jmrix.AbstractSerialConnectionConfig;
007import jmri.jmrix.cmri.CMRISystemConnectionMemo;
008import jmri.jmrix.cmri.serial.SerialNode;
009import jmri.jmrix.cmri.serial.SerialTrafficController;
010import jmri.jmrix.cmri.serial.serialdriver.ConnectionConfig;
011import jmri.jmrix.cmri.serial.serialdriver.SerialDriverAdapter;
012import jmri.jmrix.configurexml.AbstractSerialConnectionConfigXml;
013import jmri.jmrix.cmri.serial.cmrinetmetrics.CMRInetMetricsCollector;
014import org.jdom2.Element;
015
016/**
017 * Handle XML persistence of layout connections by persisting the
018 * SerialDriverAdapter (and connections). Note this is named as the XML version
019 * of a ConnectionConfig object, but it's actually persisting the
020 * SerialDriverAdapter.
021 * <p>
022 * This class is invoked from {@link jmri.jmrix.configurexml.JmrixConfigPaneXml}
023 * on write, as that class is the one actually registered. Reads are brought
024 * here directly via the class attribute in the XML.
025 *
026 * @author Bob Jacobsen Copyright: Copyright (c)
027 * @author Chuck Catania Copyright: Copyright (c) 2014, 2015, 2016, 2017
028 *
029 */
030public class ConnectionConfigXml extends AbstractSerialConnectionConfigXml {
031
032    public ConnectionConfigXml() {
033        super();
034    }
035
036    CMRInetMetricsCollector metricsCollector;
037
038    /**
039     * Write out the SerialNode objects too
040     *
041     * @param e Element being extended
042     */
043    @Override
044    protected void extendElement(Element e) {
045        // Create a polling list from the configured nodes
046        StringBuilder polllist = new StringBuilder("");
047        SerialTrafficController tcPL = ((CMRISystemConnectionMemo) adapter.getSystemConnectionMemo()).getTrafficController();
048        SerialNode plNode = (SerialNode) tcPL.getNode(0);
049        int index = 1;
050        while (plNode != null) {
051            if (index != 1) {
052                polllist.append(",");
053            }
054            polllist.append(Integer.toString(plNode.getNodeAddress()));
055            plNode = (SerialNode) tcPL.getNode(index);
056            index++;
057        }
058
059        Element l = new Element("polllist");
060        l.setAttribute("pollseq", polllist.toString());
061        e.addContent(l);
062
063        SerialTrafficController tc = ((CMRISystemConnectionMemo) adapter.getSystemConnectionMemo()).getTrafficController();
064        SerialNode node = (SerialNode) tc.getNode(0);
065        index = 1;
066
067        while (node != null) {
068            // add node as an element
069            Element n = new Element("node");
070            n.setAttribute("name", Integer.toString(node.getNodeAddress()));
071            e.addContent(n);
072            // add parameters to the node as needed
073            n.addContent(makeParameter("nodetype", Integer.toString(node.getNodeType())));
074            n.addContent(makeParameter("bitspercard", Integer.toString(node.getNumBitsPerCard())));
075            n.addContent(makeParameter("transmissiondelay", Integer.toString(node.getTransmissionDelay())));
076            n.addContent(makeParameter("num2lsearchlights", Integer.toString(node.getNum2LSearchLights())));
077            n.addContent(makeParameter("pulsewidth", Integer.toString(node.getPulseWidth())));
078
079            StringBuilder value = new StringBuilder();
080            for (int i = 0; i < node.getLocSearchLightBits().length; i++) {
081                value.append(Integer.toHexString(node.getLocSearchLightBits()[i] & 0xF));
082            }
083            n.addContent(makeParameter("locsearchlightbits", value.toString()));
084            value = new StringBuilder();
085            for (int i = 0; i < node.getCardTypeLocation().length; i++) {
086                value.append(Integer.toHexString(node.getCardTypeLocation()[i] & 0xF));
087            }
088            n.addContent(makeParameter("cardtypelocation", value.toString()));
089            log.debug("Node {} Card Type Written = {}", node.nodeAddress, value);
090
091            // CMRInet Options
092            value = new StringBuilder("");
093            for (int i = 0; i < SerialNode.NUMCMRINETOPTS; i++) {
094                value.append(Integer.toHexString((node.getCMRInetOpts(i) & 0xF)));
095            }
096            n.addContent(makeParameter("cmrinetoptions", value.toString().toUpperCase()));
097            log.debug("Node {} NET Options Written = {}", node.nodeAddress, value);
098
099            // cpNode Options  Classic CMRI nodes do not have options
100            if (node.getNodeType() == SerialNode.CPNODE || node.getNodeType() == SerialNode.CPMEGA) {
101                value = new StringBuilder();
102                for (int i = 0; i < SerialNode.NUMCPNODEOPTS; i++) {
103                    value.append(Integer.toHexString((node.getcpnodeOpts(i) & 0xF)));
104                }
105                n.addContent(makeParameter("cpnodeoptions", value.toString().toUpperCase()));
106                log.debug("Node {} NODE Options Written = {}", node.nodeAddress, value);
107            }
108
109            // node description
110            n.addContent(makeParameter("cmrinodedesc", node.getcmriNodeDesc()));
111
112            // look for the next node
113            node = (SerialNode) tc.getNode(index);
114            index++;
115        }
116    }
117
118    protected Element makeParameter(String name, String value) {
119        Element p = new Element("parameter");
120        p.setAttribute("name", name);
121        p.addContent(value);
122        return p;
123    }
124
125    @Override
126    protected void getInstance() {
127        if (adapter == null) {
128            adapter = new SerialDriverAdapter();
129        }
130    }
131
132    @Override
133    protected void getInstance(Object object) {
134        adapter = ((AbstractSerialConnectionConfig) object).getAdapter();
135    }
136
137    @Override
138    protected void unpackElement(Element shared, Element perNode) {
139        // --------------------------------------
140        // Load the poll list sequence if present
141        // --------------------------------------
142        List<Element> pl = shared.getChildren("polllist");
143        if (!pl.isEmpty()) {
144            Element ps = pl.get(0);
145            if (ps != null) {
146                String pseq = ps.getAttributeValue("pollseq");
147                if (pseq != null) {
148                    StringTokenizer nodes = new StringTokenizer(pseq, " ,");
149                    SerialTrafficController tcPL = ((CMRISystemConnectionMemo) adapter.getSystemConnectionMemo()).getTrafficController();
150                    while (nodes.hasMoreTokens()) {
151                        tcPL.cmriNetPollList.add(Integer.parseInt(nodes.nextToken()));
152                    }
153                    log.debug("Poll List = {}", tcPL.cmriNetPollList);
154                }
155            }
156        }
157
158        // Load the node specific parameters
159        int pollListSize = ((CMRISystemConnectionMemo) adapter.getSystemConnectionMemo()).getTrafficController().cmriNetPollList.size();
160        int nextPollPos = pollListSize + 1;
161
162        List<Element> l = shared.getChildren("node");
163        for (int i = 0; i < l.size(); i++) {
164            Element n = l.get(i);
165            int addr = Integer.parseInt(n.getAttributeValue("name"));
166            int type = Integer.parseInt(findParmValue(n, "nodetype"));
167            int bpc = Integer.parseInt(findParmValue(n, "bitspercard"));
168            int delay = Integer.parseInt(findParmValue(n, "transmissiondelay"));
169            int num2l = Integer.parseInt(findParmValue(n, "num2lsearchlights"));
170            int pulseWidth = 500;
171            if ((findParmValue(n, "pulsewidth")) != null) {
172                pulseWidth = Integer.parseInt(findParmValue(n, "pulsewidth"));
173            }
174
175            String slb = findParmValue(n, "locsearchlightbits");
176            String ctl = findParmValue(n, "cardtypelocation");
177            String opts = "";
178
179            // create node (they register themselves)
180            SerialNode node = new SerialNode(addr, type, ((CMRISystemConnectionMemo) adapter.getSystemConnectionMemo()).getTrafficController());
181            node.setNumBitsPerCard(bpc);
182            node.setTransmissionDelay(delay);
183            node.setNum2LSearchLights(num2l);
184            node.setPulseWidth(pulseWidth);
185
186            // From the loaded poll list, assign the poll list position to the node
187            boolean assigned = false;
188            if (pollListSize > 0) {
189                for (int pls = 0; pls < pollListSize; pls++) {
190                    if (((CMRISystemConnectionMemo) adapter.getSystemConnectionMemo()).getTrafficController().cmriNetPollList.get(pls) == node.getNodeAddress()) {
191                        node.setPollListPosition(pls + 1);
192                        assigned = true;
193                    }
194                }
195                if (!assigned) {
196                    node.setPollListPosition(nextPollPos++);
197                }
198            }
199
200            // CMRInet Options
201            //----------------
202            if (findParmValue(n, "cmrinetoptions") != null) {
203                opts = findParmValue(n, "cmrinetoptions");
204                // Convert and load the  value into the node options array
205                for (int j = 0; j < SerialNode.NUMCMRINETOPTS; j++) {
206                    node.setCMRInetOpts(j, (opts.charAt(j) - '0'));
207                }
208                log.debug("Node {} NET Options Read = {}", node.nodeAddress, opts);
209
210            } else {
211                // This must be the first time the nodes were loaded into a cpNode
212                // supported version.  Set the Auto Poll option to avoid confusion
213                // with installed configurations.
214                for (int j = 0; j < SerialNode.NUMCMRINETOPTS; j++) {
215                    node.setCMRInetOpts(j, 0);
216                }
217                node.setOptNet_AUTOPOLL(1);
218                log.debug("Node {} AUTO POLL Set ", node.nodeAddress);
219
220            }
221
222            for (int j = 0; j < slb.length(); j++) {
223                node.setLocSearchLightBits(j, (slb.charAt(j) - '0'));
224            }
225
226            for (int j = 0; j < ctl.length(); j++) {
227                node.setCardTypeLocation(j, (ctl.charAt(j) - '0'));
228            }
229
230            if (type == SerialNode.CPNODE || type == SerialNode.CPMEGA) {
231                // cpNode Options
232                if (findParmValue(n, "cpnodeoptions") != null) {
233                    opts = findParmValue(n, "cpnodeoptions");
234                    // Convert and load the  value into the node options array
235                    for (int j = 0; j < SerialNode.NUMCPNODEOPTS; j++) {
236                        node.setcpnodeOpts(j, (opts.charAt(j) - '0'));
237                    }
238                }
239
240                log.debug("Node {} NODE Options Read = {}", node.nodeAddress, opts);
241            }
242
243            if (findParmValue(n, "cmrinodedesc") != null) {
244                node.setcmriNodeDesc(findParmValue(n, "cmrinodedesc"));
245            } else {
246                log.debug("No Description - Node {}", addr);
247            }
248
249            // Trigger initialization of this Node to reflect these parameters
250            ((CMRISystemConnectionMemo) adapter.getSystemConnectionMemo()).getTrafficController().initializeSerialNode(node);
251        }
252    }
253
254    @Override
255    protected void register() {
256        this.register(new ConnectionConfig(adapter));
257    }
258
259    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ConnectionConfigXml.class);
260}