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        } else {
046            nextLine("Cmd: " + parse(l.getOpCode(), l.getAsWord()) + "\n", l.toString());
047        }
048    }
049
050    @Override
051    public synchronized void reply(SerialReply l) { // receive a reply message and log it
052        // check for valid length
053        if (l.getNumDataElements() < 2) {
054            nextLine("Truncated reply of length " + l.getNumDataElements() + ": \"" + l.toString() + "\"\n",
055                    l.toString());
056        } else {
057            nextLine("Rep: " + parse(l.getOpCode(), l.getAsWord()) + "\n", l.toString());
058        }
059    }
060
061    String parse(int opCode, int val) {
062        if (opCode != 0xFE) {
063            // TMCC 2 parsing
064            return "TMCC 2 msg 0x"+Integer.toHexString(opCode)+" 0x"+Integer.toHexString(val);
065        }
066        if ((val & 0xC000) == 0x4000) {
067            // switch command
068            int A = (val / 128) & 0x7F;
069            int C = (val / 32) & 0x03;
070            int D = val & 0x1F;
071            if ((C == 0) && (D == 0)) {
072                return "Throw switch " + A + " THROUGH";
073            } else if ((C == 0) && (D == 0x1F)) {
074                return "Throw switch " + A + " OUT";
075            } else if ((C == 1) && (D == 0x09)) {
076                return "Switch " + A + " set address";
077            } else if (C == 2) {
078                return "Assign switch " + A + " to route " + D + " THROUGH";
079            } else if (C == 3) {
080                return "Assign switch " + A + " to route " + D + " OUT";
081            } else {
082                return "unrecognized switch command with A=" + A + " C=" + C + " D=" + D;
083            }
084        } else if ((val & 0xF000) == 0xD000) {
085            // route command
086            int A = (val / 128) & 0x1F;
087            int C = (val / 32) & 0x03;
088            int D = val & 0x1F;
089            return "route command with A=" + A + " C=" + C + " D=" + D;
090        } else if ((val & 0xC000) == 0x0000) {
091            // engine command
092            int A = (val / 128) & 0x7F;
093            int C = (val / 32) & 0x03;
094            int D = val & 0x1F;
095            switch (C) {
096                case 0:
097                    if (((D & 0x70) == 0x10) && ((D & 0x0F) < 10)) {
098                        return "engine " + A + " numeric action command " + (D & 0x0F);
099                    }
100
101                    switch (D) {
102                        case 0:
103                            return "engine " + A + " forward direction";
104                        case 1:
105                            return "engine " + A + " toggle direction";
106                        case 3:
107                            return "engine " + A + " reverse direction";
108                        case 7:
109                            return "engine " + A + " brake";
110                        case 4:
111                            return "engine " + A + " boost";
112                        case 5:
113                            return "engine " + A + " open front coupler";
114                        case 6:
115                            return "engine " + A + " open rear coupler";
116                        case 28:
117                            return "engine " + A + " blow horn 1";
118                        case 29:
119                            return "engine " + A + " ring bell";
120                        case 30:
121                            return "engine " + A + " letoff sound";
122                        case 31:
123                            return "engine " + A + " blow horn 2";
124                        case 8:
125                            return "engine " + A + " AUX1 off";
126                        case 9:
127                            return "engine " + A + " AUX1 option 1 (CAB AUX1 button)";
128                        case 10:
129                            return "engine " + A + " AUX1 option 2";
130                        case 11:
131                            return "engine " + A + " AUX1 on";
132                        case 12:
133                            return "engine " + A + " AUX2 off";
134                        case 13:
135                            return "engine " + A + " AUX2 option 1 (CAB AUX2 button)";
136                        case 14:
137                            return "engine " + A + " AUX2 option 2";
138                        case 15:
139                            return "engine " + A + " AUX2 on";
140                        default:
141                            return "engine " + A + " action command D=" + D;
142                    }
143
144                case 1:
145                    return "engine " + A + " extended command (C=1) with D=" + D;
146                case 2:
147                    return "change engine " + A + " speed (relative) by " + (D - 5);
148                case 3:
149                default:    // to let the compiler know there are only 3 cases
150                    return "set engine " + A + " speed (absolute) to " + D;
151            }
152        } else if ((val & 0xF800) == 0xC800) {
153            // train command
154            int A = (val / 128) & 0x0F;
155            int C = (val / 32) & 0x03;
156            int D = val & 0x1F;
157            return "train command with A=" + A + " C=" + C + " D=" + D;
158        } else if ((val & 0xC000) == 0x8000) {
159            // accessory command
160            int A = (val / 128) & 0x7F;
161            int C = (val / 32) & 0x03;
162            int D = val & 0x1F;
163            return "accessory command with A=" + A + " C=" + C + " D=" + D;
164        } else if ((val & 0xF800) == 0xC000) {
165            // group command
166            int A = (val / 128) & 0x0F;
167            int C = (val / 32) & 0x03;
168            int D = val & 0x1F;
169            return "group command with A=" + A + " C=" + C + " D=" + D;
170        } else {
171            return "unexpected command " + Integer.toHexString(val & 0xFF);
172        }
173    }
174
175}