001package jmri.jmris.srcp.parser;
002
003import jmri.InstanceManager;
004import jmri.ProgrammingMode;
005import org.slf4j.Logger;
006import org.slf4j.LoggerFactory;
007
008/* This class provides an interface between the JavaTree/JavaCC
009 * parser for the SRCP protocol and the JMRI back end.
010 * @author Paul Bender Copyright (C) 2010
011 */
012public class SRCPVisitor extends SRCPParserDefaultVisitor {
013
014    private String outputString = null;
015
016    public String getOutputString() {
017        return outputString;
018    }
019
020    // note that the isSupported function has the side
021    // effect of setting an error message to outputString if
022    // it returns false.
023    private boolean isSupported(int bus, String devicegroup) {
024        // get the system memo coresponding to the bus.
025        // and ask it what is supported
026        try {
027            jmri.SystemConnectionMemo memo
028                    = InstanceManager.getList(jmri.SystemConnectionMemo.class).get(bus - 1);
029            if (memo != null) {
030                log.debug("devicegroup {}", devicegroup);
031                if (devicegroup.equals("FB")) {
032                    if (memo.provides(jmri.SensorManager.class)) {
033                        return true;
034                    } else {
035                        // respond this isn't supported
036                        outputString = "422 ERROR unsupported device group";
037                    }
038                } else if (devicegroup.equals("GA")) {
039                    if (memo.provides(jmri.TurnoutManager.class)) {
040                        return true;
041                    } else {
042                        // respond this isn't supported
043                        outputString = "422 ERROR unsupported device group";
044                    }
045                } else if (devicegroup.equals("GL")) {
046                    if (memo.provides(jmri.ThrottleManager.class)) {
047                        return true;
048                    } else {
049                        // respond this isn't supported
050                        outputString = "422 ERROR unsupported device group";
051                    }
052                } else if (devicegroup.equals("POWER")) {
053                    if (memo.provides(jmri.PowerManager.class)) {
054                        return true;
055                    } else {
056                        // respond this isn't supported
057                        outputString = "422 ERROR unsupported device group";
058                    }
059                } else if (devicegroup.equals("SM")) {
060                    if (memo.provides(jmri.GlobalProgrammerManager.class)) {
061                        return true;
062                    } else {
063                        // respond this isn't supported
064                        outputString = "422 ERROR unsupported device group";
065                    }
066                } else {
067                    // respond this isn't supported
068                    outputString = "422 ERROR unsupported device group";
069
070                }
071            } else {
072                // no memo registered for this bus.
073                outputString = "416 ERROR no data";
074            }
075        } catch (java.lang.IndexOutOfBoundsException obe) {
076            outputString = "412 ERROR wrong value";
077        }
078        return false;
079    }
080
081    @Override
082    public Object visit(ASTgo node, Object data) {
083        log.debug("Go {}", node.jjtGetValue());
084        jmri.jmris.srcp.JmriSRCPServiceHandler handle = (jmri.jmris.srcp.JmriSRCPServiceHandler) data;
085        // The GO command should switch the server into runmode, but
086        // only if the client has set the protocol version.  (if no mode
087        // is set, the default is command mode).
088        if (handle.getClientVersion().startsWith("0.8")) {
089            handle.setRunMode();
090            outputString = "200 OK GO " + ((jmri.jmris.srcp.JmriSRCPServiceHandler) data).getSessionNumber();
091        } else {
092            outputString = "402 ERROR insufficient data";
093        }
094        return data;
095    }
096
097    @Override
098    public Object visit(ASThandshake_set node, Object data) {
099        log.debug("Handshake Mode SET ");
100        jmri.jmris.srcp.JmriSRCPServiceHandler handle = (jmri.jmris.srcp.JmriSRCPServiceHandler) data;
101        if (node.jjtGetChild(0).getClass() == ASTprotocollitteral.class) {
102            String version = (String) ((SimpleNode) node.jjtGetChild(1)).jjtGetValue();
103            if (version.startsWith("0.8")) {
104                handle.setClientVersion(version);
105                outputString = "201 OK PROTOCOL SRCP";
106            } else {
107                outputString = "400 ERROR unsupported protocol";
108            }
109        } else if (node.jjtGetChild(0).getClass() == ASTconnectionlitteral.class) {
110            String mode = (String) ((SimpleNode) node.jjtGetChild(1)).jjtGetValue();
111            outputString = "202 OK CONNECTIONMODEOK";
112            if (mode.equals("COMMAND")) {
113                handle.setCommandMode(true);
114            } else if (mode.equals("INFO")) {
115                handle.setCommandMode(false);
116            } else {
117                outputString = "401 ERROR unsupported connection mode";
118            }
119        } else {
120            outputString = "500 ERROR out of resources";
121        }
122        return data;
123    }
124
125    @Override
126    public Object visit(ASTget node, Object data) {
127        log.debug("Get {}", ((SimpleNode) node.jjtGetChild(1)).jjtGetValue());
128        int bus = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(0)).jjtGetValue()));
129        if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("POWER")
130                && isSupported(bus, "POWER")) {
131            // This is a message asking for the power status
132            try {
133                ((jmri.jmris.ServiceHandler) data).getPowerServer().sendStatus(
134                        InstanceManager.getDefault(jmri.PowerManager.class).getPower());
135            } catch (java.io.IOException ie) {
136                // silently ignore
137            }
138        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("GA")
139                && isSupported(bus, "GA")) {
140            // This is a message asking for the status of a "General Accessory".
141            int address = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(2)).jjtGetValue()));
142            // our implementation ignores the port, but maybe we shouldn't to
143            // follow the letter of the standard.
144            //int port = Integer.parseInt(((String)((SimpleNode)node.jjtGetChild(3)).jjtGetValue()));
145            try {
146                ((jmri.jmris.srcp.JmriSRCPTurnoutServer) ((jmri.jmris.ServiceHandler) data).getTurnoutServer()).sendStatus(bus, address);
147            } catch (java.io.IOException ie) {
148            }
149        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("FB")
150                && isSupported(bus, "FB")) {
151            // This is a message asking for the status of a FeedBack sensor.
152            int address = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(2)).jjtGetValue()));
153            try {
154                ((jmri.jmris.srcp.JmriSRCPSensorServer) ((jmri.jmris.ServiceHandler) data).getSensorServer()).sendStatus(bus, address);
155            } catch (java.io.IOException ie) {
156            }
157        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("SM")
158                && isSupported(bus, "SM")) {
159            // This is a Service Mode read request.
160            ProgrammingMode modeno = ProgrammingMode.REGISTERMODE;
161            if (node.jjtGetChild(3).getClass() == ASTcv.class) {
162                modeno = ProgrammingMode.DIRECTBYTEMODE;
163            } else if (node.jjtGetChild(3).getClass() == ASTcvbit.class) {
164                modeno = ProgrammingMode.DIRECTBITMODE;
165            }
166
167            int cv = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(4)).jjtGetValue()));
168            //try {
169            ((jmri.jmris.srcp.JmriSRCPProgrammerServer) ((jmri.jmris.ServiceHandler) data).getProgrammerServer()).readCV(modeno, cv);
170            //} catch(java.io.IOException ie) {
171            //}
172
173        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("GL")
174                && isSupported(bus, "GL")) {
175            // This is a Generic Loco request
176            // the 3rd child is the address of the locomotive we are
177            // requesting status of.
178            int address=Integer.parseInt(((String) ((SimpleNode)node.jjtGetChild(2)).jjtGetValue()));
179            // This is a Throttle Status request
180            try {
181                ((jmri.jmris.srcp.JmriSRCPThrottleServer)(((jmri.jmris.ServiceHandler) data).getThrottleServer())).sendStatus(bus,address);
182            } catch (java.io.IOException ie) {
183            }
184
185        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("TIME")) {
186            // This is a Time request
187            try {
188                ((jmri.jmris.ServiceHandler) data).getTimeServer().sendTime();
189            } catch (java.io.IOException ie) {
190            }
191
192        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("SERVER")) {
193            // for the GET <bus> SERVER request, we return the current server
194            // state.  In JMRI, we always return "Running".
195            outputString = "100 INFO 0 SERVER RUNNING";
196        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("DESCRIPTION")) {
197            // for the GET <bus> DESCRIPTION request, what we return depends on
198            // the number of arguments passed.
199            SimpleNode descriptionnode = (SimpleNode) node.jjtGetChild(1);
200            int children = descriptionnode.jjtGetNumChildren();
201            if (children == 0) {
202                // with no arguments, we send a list of supported groups.
203                if (bus == 0) {
204                    // the groups supported by bus 0 are fixed
205                    outputString = "100 INFO 0 DESCRIPTION SERVER SESSION TIME";
206                } else {
207                    outputString = "100 INFO " + bus;
208                    // get the system memo coresponding to the bus.
209                    // and ask it what is supported
210                    try {
211                        jmri.SystemConnectionMemo memo
212                                = InstanceManager.getList(jmri.SystemConnectionMemo.class).get(bus - 1);
213                        if (memo != null) {
214                            outputString = outputString + " DESCRIPTION";
215                            if (memo.provides(jmri.SensorManager.class)) {
216                                outputString = outputString + " FB";
217                            }
218                            if (memo.provides(jmri.TurnoutManager.class)) {
219                                outputString = outputString + " GA";
220                            }
221                            if (memo.provides(jmri.ThrottleManager.class)) {
222                                outputString = outputString + " GL";
223                            }
224                            if (memo.provides(jmri.PowerManager.class)) {
225                                outputString = outputString + " POWER";
226                            }
227                            if (memo.provides(jmri.GlobalProgrammerManager.class)) {
228                                outputString = outputString + " SM";
229                            }
230                        } else {
231                            // no memo registered for this bus.
232                            outputString = "416 ERROR no data";
233                        }
234                    } catch (java.lang.IndexOutOfBoundsException obe) {
235                        outputString = "412 ERROR wrong value";
236                    }
237                }
238            } else if (children == 1) {
239                // with one argument, we respond with data only for device groups
240                // that have no addresses.
241                String devicegroup = (String) ((SimpleNode) descriptionnode.jjtGetChild(0)).jjtGetValue();
242                outputString = "100 INFO " + bus;
243                log.debug("devicegroup {}", devicegroup);
244                if (devicegroup.equals("FB") && isSupported(bus, devicegroup)) {
245                    outputString = "419 ERROR list too short";
246                } else if (devicegroup.equals("GA") && isSupported(bus, devicegroup)) {
247                    outputString = "419 ERROR list too short";
248                } else if (devicegroup.equals("GL") && isSupported(bus, devicegroup)) {
249                    outputString = "419 ERROR list too short";
250                } else if (devicegroup.equals("POWER") && isSupported(bus, devicegroup)) {
251                    // we are supposed to return the init string,
252                    // and the POWER group has no parameters, so
253                    // just return POWER
254                    outputString = outputString + " POWER";
255                } else if (devicegroup.equals("SM") && isSupported(bus, devicegroup)) {
256                    outputString = "419 ERROR list too short";
257                } else {
258                    // respond this isn't supported
259                    outputString = "422 ERROR unsupported device group";
260                }  // end if(chidren==1)
261            } else if (children == 2) {
262                outputString = "100 INFO " + bus;
263                // get the system memo coresponding to the bus.
264                // and ask it what is supported
265                // with 2 arguments, we send a description of a specific device.
266                jmri.SystemConnectionMemo memo
267                        = InstanceManager.getList(jmri.SystemConnectionMemo.class).get(bus - 1);
268                if (memo != null) {
269                    String devicegroup = (String) ((SimpleNode) descriptionnode.jjtGetChild(0)).jjtGetValue();
270                    String address = (String) ((SimpleNode) descriptionnode.jjtGetChild(1)).jjtGetValue();
271                    if (devicegroup.equals("FB") && isSupported(bus, devicegroup)) {
272                        jmri.SensorManager mgr = memo.get(jmri.SensorManager.class);
273                        try {
274                            String searchName = mgr.createSystemName(address,
275                                    memo.getSystemPrefix());
276                            if (mgr.getBySystemName(searchName) != null) {
277                                // add the initialization parameter list.
278                                // we don't expect parameters, so just return
279                                // the bus and address.
280                                outputString = outputString + " FB " + address;
281                            } else {
282                                // the device wasn't found.
283                                outputString = "412 ERROR wrong value";
284                            }
285                        } catch (jmri.JmriException je) {
286                            // the device wasn't found.
287                            outputString = "412 ERROR wrong value";
288                        }
289                    } else if (devicegroup.equals("GA") && isSupported(bus, devicegroup)) {
290                        jmri.TurnoutManager mgr = memo.get(jmri.TurnoutManager.class);
291                        try {
292                            String searchName = mgr.createSystemName(address, memo.getSystemPrefix());
293                            if (mgr.getBySystemName(searchName) != null) {
294                                // add the initialization parameter list.
295                                // the only other required parameter is
296                                // the protocol, and we treat all of our
297                                // turnouts as NMRA-DCC turnouts, so return
298                                // the fixed "N" protocol value.
299                                // other valid options are:
300                                //    "M" (Mareklin/Motorola format)
301                                //    "S" (Selectrix Format)
302                                //    "P" (Protocol by server)
303                                outputString = outputString + " GA " + address + " N";
304                            } else {
305                                // the device wasn't found.
306                                outputString = "412 ERROR wrong value";
307                            }
308                        } catch (jmri.JmriException je) {
309                            // the device wasn't found.
310                            outputString = "412 ERROR wrong value";
311                        }
312                    } else if (devicegroup.equals("GL") && isSupported(bus, devicegroup)) {
313                        // outputString=outputString + " GL " +address;
314                        // this one needs some tought on how to proceed,
315                        // since the throttle manager differs from
316                        // other JMRI managers.
317                        // for now, just say no data.
318                        outputString = "416 ERROR no data";
319                    } else if (devicegroup.equals("POWER") && isSupported(bus, devicegroup)) {
320                        outputString = "418 ERROR list too long";
321                    } else if (devicegroup.equals("SM") && isSupported(bus, devicegroup)) {
322                        //outputString=outputString + " SM " +address;
323                        // this one needs some tought on how to proceed                                 // since we have both service mode and ops mode
324                        // programmers, but the service mode programmer is
325                        // not addressed on DCC systems.
326                        // for now, just say no data.
327                        outputString = "416 ERROR no data";
328                    }
329                } // end if(children==2)
330            } else {
331                outputString = "418 ERROR list too long";
332            } // end of DESCRIPTION device group.
333        } else {
334            outputString = "422 ERROR unsupported device group";
335        }
336        return data;
337    }
338
339    @Override
340    public Object visit(ASTset node, Object data) {
341        SimpleNode target = (SimpleNode) node.jjtGetChild(1);
342
343        log.debug("Set {}", target.jjtGetValue());
344        int bus = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(0)).jjtGetValue()));
345
346        if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("POWER")
347                && isSupported(bus, "POWER")) {
348            try {
349                ((jmri.jmris.ServiceHandler) data).getPowerServer().parseStatus(
350                        ((String) ((SimpleNode) node.jjtGetChild(2)).jjtGetValue()));
351            } catch (java.io.IOException ie) {
352            } catch (jmri.JmriException je) {
353                // We shouldn't have any errors here.
354                // If we do, something is horibly wrong.
355            }
356        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("GA")
357                && isSupported(bus, "GA")) {
358            int address = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(2)).jjtGetValue()));
359            int port = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(3)).jjtGetValue()));
360            // we expect to get both the value and delay, but JMRI only cares about
361            // the port which indicates which output of a pair we are using.
362            // leave the values below commented out, unless we decide to use them
363            // later.
364            //int value = Integer.parseInt(((String)((SimpleNode)node.jjtGetChild(4)).jjtGetValue()));
365            //int delay = Integer.parseInt(((String)((SimpleNode)node.jjtGetChild(5)).jjtGetValue()));
366
367            try {
368                ((jmri.jmris.srcp.JmriSRCPTurnoutServer) ((jmri.jmris.ServiceHandler) data).getTurnoutServer()).parseStatus(bus, address, port);
369            } catch (jmri.JmriException je) {
370                // We shouldn't have any errors here.
371                // If we do, something is horibly wrong.
372            } catch (java.io.IOException ie) {
373            }
374        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("FB")
375                && isSupported(bus, "FB")) {
376            int address = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(2)).jjtGetValue()));
377            int value = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(3)).jjtGetValue()));
378            try {
379                ((jmri.jmris.srcp.JmriSRCPSensorServer) ((jmri.jmris.ServiceHandler) data).getSensorServer()).parseStatus(bus, address, value);
380            } catch (java.io.IOException ie) {
381            }
382        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("SM")
383                && isSupported(bus, "SM")) {
384            // This is a Service Mode write request
385            ProgrammingMode modeno = ProgrammingMode.REGISTERMODE;
386            if (node.jjtGetChild(3).getClass() == ASTcv.class) {
387                modeno = ProgrammingMode.DIRECTBYTEMODE;
388            } else if (node.jjtGetChild(3).getClass() == ASTcvbit.class) {
389                modeno = ProgrammingMode.DIRECTBITMODE;
390            }
391            int cv = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(4)).jjtGetValue()));
392            int value = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(5)).jjtGetValue()));
393
394            //try {
395            ((jmri.jmris.srcp.JmriSRCPProgrammerServer) ((jmri.jmris.ServiceHandler) data).getProgrammerServer()).writeCV(modeno, cv, value);
396            //} catch(java.io.IOException ie) {
397            //}
398
399        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("GL")
400                && isSupported(bus, "GL")) {
401            // This is a Generic Loco request
402            int address = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(2)).jjtGetValue()));
403            String drivemode = (String) ((SimpleNode) node.jjtGetChild(3)).jjtGetValue();
404
405            int speedstep = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(4)).jjtGetValue()));
406
407            int maxspeedstep = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(5)).jjtGetValue()));
408            ((jmri.jmris.srcp.JmriSRCPThrottleServer) ((jmri.jmris.ServiceHandler) data).getThrottleServer()).setThrottleSpeedAndDirection(bus,address,(float)speedstep/(float)maxspeedstep,drivemode.equals("0"));
409            // setup the array list of function values.
410
411            int numFunctions = node.jjtGetNumChildren() - 6;
412            java.util.ArrayList<Boolean> functionList = new java.util.ArrayList<>();
413            for(int i = 0; i < numFunctions;i++){
414                // the functions start at the 7th child (index 6) of the node.
415                String functionMode = (String) ((SimpleNode) node.jjtGetChild(i+6)).jjtGetValue();
416                functionList.add(Boolean.valueOf(functionMode.equals("1")));
417            }
418            ((jmri.jmris.srcp.JmriSRCPThrottleServer) ((jmri.jmris.ServiceHandler) data).getThrottleServer()).setThrottleFunctions(bus,address,functionList);
419
420        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("TIME")) {
421            // This is a Time request
422            try {
423                jmri.jmris.srcp.JmriSRCPTimeServer ts = (jmri.jmris.srcp.JmriSRCPTimeServer) (((jmri.jmris.ServiceHandler) data).getTimeServer());
424                int julDay = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(2)).jjtGetValue()));
425                int hour = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(3)).jjtGetValue()));
426                int minute = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(4)).jjtGetValue()));
427                int second = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(4)).jjtGetValue()));
428
429                // set the time
430                ts.parseTime(julDay, hour, minute, second);
431                // and start the clock.
432                ts.startTime();
433                ts.sendTime();
434            } catch (java.io.IOException ie) {
435            }
436        } else {
437            outputString = "422 ERROR unsupported device group";
438        }
439        return data;
440    }
441
442    @Override
443    public Object visit(ASTterm node, Object data) {
444        SimpleNode target = (SimpleNode) node.jjtGetChild(1);
445        int bus = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(0)).jjtGetValue()));
446        log.debug("TERM {} {}", bus, target.jjtGetValue());
447        if (target.jjtGetValue().equals("SERVER")) {
448            // for the TERM <bus> SERVER request, the protocol requries that
449            // we terminate all connections and reset the state to the initial
450            // state.  Since we may have a local GUI controlling things, we
451            // ignore the request, but send the proper return value to the
452            // requesting client.
453            outputString = "200 OK";
454            return data;
455        } else if (target.jjtGetValue().equals("SESSION")) {
456            // for the TERM <bus> SERVER request, the protocol requries that
457            // we terminate all connections and reset the state to the initial
458            // state.  Since we may have a local GUI controlling things, we
459            // ignore the request, but send the proper return value to the
460            // requesting client.
461            outputString = "102 INFO " + bus + " SESSION " + ((jmri.jmris.srcp.JmriSRCPServiceHandler) data).getSessionNumber();  // we need to set session IDs.
462            return data;
463        } else if(target.jjtGetValue().equals("GL")) {
464               // terminate a locomotive
465               int address = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(2)).jjtGetValue()));
466               try {
467                  ((jmri.jmris.srcp.JmriSRCPThrottleServer)(((jmri.jmris.ServiceHandler) data).getThrottleServer())).releaseThrottle(bus,address);
468               } catch (java.io.IOException ioe){
469                 log.error("Error writing to network port");
470               }
471               return data;
472        }
473
474        return node.childrenAccept(this, data);
475    }
476
477    @Override
478    public Object visit(ASTreset node, java.lang.Object data) {
479        log.debug("RESET {}", ((SimpleNode) node.jjtGetChild(1)).jjtGetValue());
480        if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("SERVER")) {
481            // for the RESET <bus> SERVER request, the protocol requries that
482            // we re-initialize the server.  Since we may have a local GUI
483            // controlling things, we ignore the request, but send a prohibited
484            // response to the requesting client.
485            outputString = "413 ERROR temporarily prohibited";
486            return data;
487        } else {
488            outputString = "422 ERROR unsupported device group";
489        }
490        return node.childrenAccept(this, data);
491    }
492
493    @Override
494    public Object visit(ASTinit node, java.lang.Object data) {
495        int bus = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(0)).jjtGetValue()));
496        log.debug("INIT {}", ((SimpleNode) node.jjtGetChild(1)).jjtGetValue());
497        if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("POWER")
498                && isSupported(bus, "POWER")) {
499            /* Power really has nothing to do in JMRI */
500            outputString = "200 OK";
501        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("GA")
502                && isSupported(bus, "GA")) {
503            /* Initilize a new accessory */
504            int address = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(2)).jjtGetValue()));
505            String protocol = ((String) ((SimpleNode) node.jjtGetChild(3)).jjtGetValue());
506            try {
507                ((jmri.jmris.srcp.JmriSRCPTurnoutServer) ((jmri.jmris.ServiceHandler) data).getTurnoutServer()).initTurnout(bus, address, protocol);
508            } catch (jmri.JmriException je) {
509                // We shouldn't have any errors here.
510                // If we do, something is horibly wrong.
511            } catch (java.io.IOException ie) {
512            }
513
514        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("GL")
515                && isSupported(bus, "GL")) {
516            /* Initilize a new locomotive */
517            int address = Integer.parseInt(((String)((SimpleNode)node.jjtGetChild(2)).jjtGetValue()));
518            SimpleNode protocolNode = (SimpleNode)node.jjtGetChild(3);
519            String protocol = (String)(protocolNode.jjtGetValue());
520            switch(protocol){
521            case "N": // NMRA DCC
522                 int protocolversion = Integer.parseInt(((String)((SimpleNode)protocolNode.jjtGetChild(0)).jjtGetValue()));
523                 int speedsteps = Integer.parseInt(((String)((SimpleNode)protocolNode.jjtGetChild(1)).jjtGetValue()));
524                 int functions = Integer.parseInt(((String)((SimpleNode)protocolNode.jjtGetChild(2)).jjtGetValue()));
525                 try {
526                   ((jmri.jmris.srcp.JmriSRCPThrottleServer)(((jmri.jmris.ServiceHandler) data).getThrottleServer())).initThrottle(bus,address,protocolversion==2,speedsteps,functions);
527                 } catch (java.io.IOException ie) {
528                 }
529                 break;
530            case "A": // analog operation
531                      // the documentation says this is reserved for address 0.
532                      // but this could be used if we ever build support for
533                      // analog non-dcc throttles.
534            case "P": // protocol by server.  The documentation indicates
535                      // the server gets to choose the type of decoder,
536                      // but otherwise is silent on what parameters this
537                      // should take.
538            case "F": // Fleischmann
539            case "L": // LocoNet
540            case "M": // Maerklin/Motorola
541            case "S": // Selectrix
542            case "Z": // zimo
543            default:
544               outputString = "420 ERROR unsupported device protocol";
545               return data;
546            }
547        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("TIME")) {
548            /* Initilize fast clock ratio */
549            try {
550                /* the two parameters form a ration of modeltime:realtime */
551                int modeltime = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(2)).jjtGetValue()));
552                int realtime = Integer.parseInt(((String) ((SimpleNode) node.jjtGetChild(3)).jjtGetValue()));
553                jmri.jmris.srcp.JmriSRCPTimeServer ts = (jmri.jmris.srcp.JmriSRCPTimeServer) (((jmri.jmris.ServiceHandler) data).getTimeServer());
554                ts.parseRate(modeltime, realtime);
555                ts.sendRate();
556            } catch (java.io.IOException ie) {
557            }
558        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("SM")
559                && isSupported(bus, "SM")) {
560            /* Initilize service mode */
561            outputString = "200 OK";
562        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("FB")
563                && isSupported(bus, "FB")) {
564            /* Initilize feedback on a particular bus */
565            outputString = "200 OK";
566        }
567
568        return data;
569    }
570
571    @Override
572    public Object visit(ASTwait_cmd node, Object data) {
573        log.debug("Received WAIT CMD {}", node.jjtGetValue());
574        if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("TIME")) {
575            long julday = Long.parseLong((String) ((SimpleNode) node.jjtGetChild(2)).jjtGetValue());
576            int Hour = Integer.parseInt((String) ((SimpleNode) node.jjtGetChild(3)).jjtGetValue());
577            int Minute = Integer.parseInt((String) ((SimpleNode) node.jjtGetChild(4)).jjtGetValue());
578            int Second = Integer.parseInt((String) ((SimpleNode) node.jjtGetChild(5)).jjtGetValue());
579            ((jmri.jmris.srcp.JmriSRCPTimeServer) ((jmri.jmris.ServiceHandler) data).getTimeServer()).setAlarm(julday, Hour, Minute, Second);
580
581        } else if (((SimpleNode) node.jjtGetChild(1)).jjtGetValue().equals("FB")) {
582            outputString = "425 ERROR not supported";
583        } else {
584            outputString = "423 ERROR unsupported operation";
585        }
586        return data;
587    }
588
589    private final static Logger log = LoggerFactory.getLogger(SRCPVisitor.class);
590
591}