001package jmri.jmrix.tmcc.serialmon;
002
003import jmri.jmrix.tmcc.SerialListener;
004import jmri.jmrix.tmcc.SerialMessage;
005import jmri.jmrix.tmcc.SerialReply;
006import jmri.jmrix.tmcc.TmccSystemConnectionMemo;
007
008/**
009 * Frame displaying (and logging) TMCC serial command messages.
010 *
011 * @author Bob Jacobsen Copyright (C) 2001, 2006
012 */
013public class SerialMonFrame extends jmri.jmrix.AbstractMonFrame implements SerialListener {
014
015    private TmccSystemConnectionMemo _memo = null;
016
017    public SerialMonFrame(TmccSystemConnectionMemo memo) {
018        super();
019        _memo = memo;
020    }
021
022    @Override
023    protected String title() {
024        return Bundle.getMessage("MonitorXTitle", "TMCC");
025    }
026
027    @Override
028    protected void init() {
029        // connect to TrafficController
030        _memo.getTrafficController().addSerialListener(this);
031    }
032
033    @Override
034    public void dispose() {
035        _memo.getTrafficController().removeSerialListener(this);
036        super.dispose();
037    }
038
039    @Override
040    public synchronized void message(SerialMessage l) { // receive a message and log it
041        // check for valid length
042        if (l.getNumDataElements() < 3) {
043            nextLine("Truncated message of length " + l.getNumDataElements() + "\n",
044                    l.toString());
045            return;
046        } else {
047            nextLine("Cmd: " + parse(l.getAsWord()) + "\n", l.toString());
048        }
049    }
050
051    @Override
052    public synchronized void reply(SerialReply l) { // receive a reply message and log it
053        // check for valid length
054        if (l.getNumDataElements() < 2) {
055            nextLine("Truncated reply of length " + l.getNumDataElements() + ": \"" + l.toString() + "\"\n",
056                    l.toString());
057            return;
058        } else {
059            nextLine("Rep: " + parse(l.getAsWord()) + "\n", l.toString());
060        }
061    }
062
063    String parse(int val) {
064        if ((val & 0xC000) == 0x4000) {
065            // switch command
066            int A = (val / 128) & 0x7F;
067            int C = (val / 32) & 0x03;
068            int D = val & 0x1F;
069            if ((C == 0) && (D == 0)) {
070                return "Throw switch " + A + " THROUGH";
071            } else if ((C == 0) && (D == 0x1F)) {
072                return "Throw switch " + A + " OUT";
073            } else if ((C == 1) && (D == 0x09)) {
074                return "Switch " + A + " set address";
075            } else if (C == 2) {
076                return "Assign switch " + A + " to route " + D + " THROUGH";
077            } else if (C == 3) {
078                return "Assign switch " + A + " to route " + D + " OUT";
079            } else {
080                return "unrecognized switch command with A=" + A + " C=" + C + " D=" + D;
081            }
082        } else if ((val & 0xF000) == 0xD000) {
083            // route command
084            int A = (val / 128) & 0x1F;
085            int C = (val / 32) & 0x03;
086            int D = val & 0x1F;
087            return "route command with A=" + A + " C=" + C + " D=" + D;
088        } else if ((val & 0xC000) == 0x0000) {
089            // engine command
090            int A = (val / 128) & 0x7F;
091            int C = (val / 32) & 0x03;
092            int D = val & 0x1F;
093            switch (C) {
094                case 0:
095                    if (((D & 0x70) == 0x10) && ((D & 0x0F) < 10)) {
096                        return "engine " + A + " numeric action command " + (D & 0x0F);
097                    }
098
099                    switch (D) {
100                        case 0:
101                            return "engine " + A + " forward direction";
102                        case 1:
103                            return "engine " + A + " toggle direction";
104                        case 3:
105                            return "engine " + A + " reverse direction";
106                        case 7:
107                            return "engine " + A + " brake";
108                        case 4:
109                            return "engine " + A + " boost";
110                        case 5:
111                            return "engine " + A + " open front coupler";
112                        case 6:
113                            return "engine " + A + " open rear coupler";
114                        case 28:
115                            return "engine " + A + " blow horn 1";
116                        case 29:
117                            return "engine " + A + " ring bell";
118                        case 30:
119                            return "engine " + A + " letoff sound";
120                        case 31:
121                            return "engine " + A + " blow horn 2";
122                        case 8:
123                            return "engine " + A + " AUX1 off";
124                        case 9:
125                            return "engine " + A + " AUX1 option 1 (CAB AUX1 button)";
126                        case 10:
127                            return "engine " + A + " AUX1 option 2";
128                        case 11:
129                            return "engine " + A + " AUX1 on";
130                        case 12:
131                            return "engine " + A + " AUX2 off";
132                        case 13:
133                            return "engine " + A + " AUX2 option 1 (CAB AUX2 button)";
134                        case 14:
135                            return "engine " + A + " AUX2 option 2";
136                        case 15:
137                            return "engine " + A + " AUX2 on";
138                        default:
139                            return "engine " + A + " action command D=" + D;
140                    }
141
142                case 1:
143                    return "engine " + A + " extended command (C=1) with D=" + D;
144                case 2:
145                    return "change engine " + A + " speed (relative) by " + (D - 5);
146                case 3:
147                default:    // to let the compiler know there are only 3 cases
148                    return "set engine " + A + " speed (absolute) to " + D;
149            }
150        } else if ((val & 0xF800) == 0xC800) {
151            // train command
152            int A = (val / 128) & 0x0F;
153            int C = (val / 32) & 0x03;
154            int D = val & 0x1F;
155            return "train command with A=" + A + " C=" + C + " D=" + D;
156        } else if ((val & 0xC000) == 0x8000) {
157            // accessory command
158            int A = (val / 128) & 0x7F;
159            int C = (val / 32) & 0x03;
160            int D = val & 0x1F;
161            return "accessory command with A=" + A + " C=" + C + " D=" + D;
162        } else if ((val & 0xF800) == 0xC000) {
163            // group command
164            int A = (val / 128) & 0x0F;
165            int C = (val / 32) & 0x03;
166            int D = val & 0x1F;
167            return "group command with A=" + A + " C=" + C + " D=" + D;
168        } else {
169            return "unexpected command " + Integer.toHexString(val & 0xFF);
170        }
171    }
172
173}