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