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}