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 * with additions and edits by 013 * @author Timothy Jump Copyright (C) 2025 014 */ 015public class SerialMonFrame extends jmri.jmrix.AbstractMonFrame implements SerialListener { 016 017 private TmccSystemConnectionMemo _memo = null; 018 019 public SerialMonFrame(TmccSystemConnectionMemo memo) { 020 super(); 021 _memo = memo; 022 } 023 024 @Override 025 protected String title() { 026 return Bundle.getMessage("MonitorXTitle", "TMCC"); 027 } 028 029 @Override 030 protected void init() { 031 // connect to TrafficController 032 _memo.getTrafficController().addSerialListener(this); 033 } 034 035 @Override 036 public void dispose() { 037 _memo.getTrafficController().removeSerialListener(this); 038 super.dispose(); 039 } 040 041 @Override 042 public synchronized void message(SerialMessage l) { // receive a message and log it 043 // check for valid length 044 if (l.getNumDataElements() < 3) { 045 nextLine("Truncated message of length " + l.getNumDataElements() + "\n", 046 l.toString()); 047 } else { 048 nextLine("Cmd: " + parse(l.getOpCode(), l.getAsWord()) + "\n", l.toString()); 049 } 050 } 051 052 @Override 053 public synchronized void reply(SerialReply l) { // receive a reply message and log it 054 // check for valid length 055 if (l.getNumDataElements() < 2) { 056 nextLine("Truncated reply of length " + l.getNumDataElements() + ": \"" + l.toString() + "\"\n", 057 l.toString()); 058 } else { 059 nextLine("Rep: " + parse(l.getOpCode(), l.getAsWord()) + "\n", l.toString()); 060 } 061 } 062 063 String parse(int opCode, int val) { 064 // TMCC 2 parsing 065 if (opCode == 0xF8 || opCode == 0xF9 || opCode == 0xFB) { 066 // TMCC2 Engine Commands 067 int A = (val / 512) & 0x7F; // A is TMCC Adddress Code 068 int C = (val / 32) & 0x03; // C is TMCC Command Code 069 int D = val & 0x1F; // D is TMCC Data Code 070 if ((val & 0x0100) == 0x0100) { 071 switch (C) { 072 case 0: // If C (TMCC Command Code) == 0 073 switch (D) { 074 case 0: 075 return "TMCC2 - Engine " + A + " - Forward Direction"; 076 case 1: 077 return "TMCC2 - Engine " + A + " - Toggle Direction"; 078 case 2: 079 080 case 3: 081 return "TMCC2 - Engine " + A + " - Reverse Direction"; 082 case 4: 083 return "TMCC2 - Engine " + A + " - Boost"; 084 case 5: 085 return "TMCC2 - Engine " + A + " - Open Front Coupler"; 086 case 6: 087 return "TMCC2 - Engine " + A + " - Open Rear Coupler"; 088 case 7: 089 return "TMCC2 - Engine " + A + " - Brake"; 090 case 8: 091 return "TMCC2 - Engine " + A + " - AUX1 Off"; 092 case 9: 093 return "TMCC2 - Engine " + A + " - AUX1 Option 1 (CAB AUX1 button)"; 094 case 10: 095 return "TMCC2 - Engine " + A + " - AUX1 Option 2"; 096 case 11: 097 return "TMCC2 - Engine " + A + " - AUX1 On"; 098 case 12: 099 return "TMCC2 - Engine " + A + " - AUX2 Off"; 100 case 13: 101 return "TMCC2 - Engine " + A + " - AUX2 Option 1 (CAB AUX2 button) Headlight On/Off"; 102 case 14: 103 return "TMCC2 - Engine " + A + " - AUX2 Option 2"; 104 case 15: 105 return "TMCC2 - Engine " + A + " - AUX2 On"; 106 case 16: 107 return "TMCC2 - Engine " + A + " - Num 0 - Engine Reset - Needed to toggle ERR 100 Speed Steps - TMCC2 Feature Type 0 "; 108 case 17: 109 return "TMCC2 - Engine " + A + " - Num 1 - Sound Volume Increase - TMCC2 Feature Type 1"; 110 case 18: 111 return "TMCC2 - Engine " + A + " - Num 2 - Crew Talk - TMCC2 Feature Type 2"; 112 case 19: 113 return "TMCC2 - Engine " + A + " - Num 3 - Sound On w/Start-Up Sequence/RPM Increase"; 114 case 20: 115 return "TMCC2 - Engine " + A + " - Num 4 - Sound Volume Decrease"; 116 case 21: 117 return "TMCC2 - Engine " + A + " - Num 5 - Sound Off w/Shut-Down Sequence"; 118 case 22: 119 return "TMCC2 - Engine " + A + " - Num 6 - Steam Release/RPM Decrease"; 120 case 23: 121 return "TMCC2 - Engine " + A + " - Num 7 - Tower Com Announcement"; 122 case 24: 123 return "TMCC2 - Engine " + A + " - Num 8 - Feature Off (Smoke/Aux Lighting)"; 124 case 25: 125 return "TMCC2 - Engine " + A + " - Num 9 - Feature On (Smoke/Aux Lighting)"; 126 case 26: 127 128 case 27: 129 130 case 28: 131 return "TMCC2 - Engine " + A + " - Blow Whistle/Horn 1"; 132 case 29: 133 return "TMCC2 - Engine " + A + " - Ring Bell"; 134 case 30: 135 return "TMCC2 - Engine " + A + " - Letoff Sound"; 136 case 31: 137 return "TMCC2 - Engine " + A + " - Blow Horn 2"; 138 default: 139 return "TMCC2 - Engine " + A + " - Unassigned FnKey TMCC2 (Case C=0) - with A= " + A + " C= " + C + " D= " + D; 140 } 141 142 case 1: // If C (TMCC Command Code) == 1 143 switch (D & 0x17) { 144 case 0: 145 return "TMCC2 - Engine " + A + " - Momentum Low"; 146 case 1: 147 return "TMCC2 - Engine " + A + " - Momentum Medium"; 148 case 2: 149 return "TMCC2 - Engine " + A + " - Momentum High"; 150 case 3: 151 return "TMCC2 - Engine ID " + A + " - Set"; 152 default: 153 return "TMCC2 - Engine " + A + " - Unassigned FnKey TMCC2 (Case C=1) - with A= " + A + " C= " + C + " D= " + D; 154 } 155 156 //$FALL-THROUGH$ 157 case 2: // If C (TMCC Command Code) == 2 158 return "TMCC2 - Engine " + A + " - Change Speed (Relative) by " + (D - 5); 159 160 case 3: // If C (TMCC Command Code) == 3 161 default: // to let the compiler know there are only 3 cases 162 return "TMCC2 (32 Speed Steps) - Engine " + A + " - Speed (Absolute) = " + D; 163 } 164 } 165 166 return "TMCC2 (200 Speed Steps) - Engine " + A + " - Speed (Absolute) = " + (val & 0xFF); 167 } 168 169 170 // TMCC 1 parsing 171 if (opCode == 0xFE) { 172 if ((val & 0xC000) == 0x4000) { 173 // TMCC1 Switch Commands 174 int A = (val / 128) & 0x7F; // A is TMCC Adddress Code 175 int C = (val / 32) & 0x03; // C is TMCC Command Code 176 int D = val & 0x1F; // D is TMCC Data Code 177 switch (C) { 178 case 0: // If C (TMCC Command Code) == 0 179 switch (D) { 180 case 0: 181 return "Throw Switch " + A + " - THROUGH/CLOSED"; 182 case 31: 183 return "Throw Switch " + A + " - OUT/THROWN"; 184 default: 185 return "Unrecognized Switch(SW) Command (Case C=0) - with A= " + A + " C= " + C + " D= " + D; 186 } 187 188 case 1: // If C (TMCC Command Code) == 1 189 switch (D) { 190 case 11: 191 return "Switch ID " + A + " - Set"; 192 default: 193 return "Unrecognized Switch(SW) Command (Cases C=1) - with A= " + A + " C= " + C + " D= " + D; 194 } 195 196 //$FALL-THROUGH$ 197 case 2: // If C (TMCC Command Code) == 2 198 return "Assign switch " + A + " to route " + D + " - THROUGH"; 199 200 case 3: // If C (TMCC Command Code) == 3 201 return "Assign switch " + A + " to route " + D + " - OUT"; 202 default: 203 return "Unrecognized Switch(SW) Command (Cases C= 2-3) - with A= " + A + " C= " + C + " D= " + D; 204 } 205 206 207 } else if ((val & 0xF000) == 0xD000) { 208 // TMCC1 Route Commands 209 int A = (val / 128) & 0x1F; // A is TMCC Adddress Code 210 int C = (val / 32) & 0x03; // C is TMCC Command Code 211 int D = val & 0x1F; // D is TMCC Data Code 212 switch (C) { 213 case 0: // If C (TMCC Command Code) == 0 214 switch (D) { 215 case 15: 216 return "Route " + A + " - THROW"; 217 default: 218 return "Unrecognized Route(RTE) Command (Cases C=0) - with A= " + A + " C= " + C + " D= " + D; 219 } 220 221 case 1: // If C (TMCC Command Code) == 0 222 switch (D) { 223 case 12: 224 return "Route " + A + " - CLEAR"; 225 default: 226 return "Unrecognized Route(RTE) Command (Cases C=1) - with A= " + A + " C= " + C + " D= " + D; 227 228 } 229 230 default: 231 return "Unrecognized Route(RTE) Command (Cases C) - with A= " + A + " C= " + C + " D= " + D; 232 } 233 234 } else if ((val & 0xC000) == 0x0000) { 235 // TMCC1 Engine Commands 236 int A = (val / 128) & 0x7F; // A is TMCC Adddress Code 237 int C = (val / 32) & 0x03; // C is TMCC Command Code 238 int D = val & 0x1F; // D is TMCC Data Code 239 switch (C) { 240 case 0: // If C (TMCC Command Code) == 0 241 switch (D) { 242 case 0: 243 return "TMCC1 - Engine " + A + " - Forward Direction"; 244 case 1: 245 return "TMCC1 - Engine " + A + " - Toggle Direction"; 246 case 2: 247 248 case 3: 249 return "TMCC1 - Engine " + A + " - Reverse Direction"; 250 case 4: 251 return "TMCC1 - Engine " + A + " - Boost"; 252 case 5: 253 return "TMCC1 - Engine " + A + " - Open Front Coupler"; 254 case 6: 255 return "TMCC1 - Engine " + A + " - Open Rear Coupler"; 256 case 7: 257 return "TMCC1 - Engine " + A + " - Brake"; 258 case 8: 259 260 case 9: 261 return "TMCC1 - Engine " + A + " - AUX1 Option 1 (CAB AUX1 button)"; 262 case 10: 263 264 case 11: 265 266 case 12: 267 268 case 13: 269 return "TMCC1 - Engine " + A + " - AUX2 Option 1 (CAB AUX2 button) Headlight On/Off"; 270 case 14: 271 272 case 15: 273 274 case 16: 275 return "TMCC1 - Engine " + A + " - Num 0 - Engine Reset (Needed to toggle ERR 100 Speed Steps)"; 276 case 17: 277 return "TMCC1 - Engine " + A + " - Num 1 - Sound Volume Increase"; 278 case 18: 279 return "TMCC1 - Engine " + A + " - Num 2 - Crew Talk"; 280 case 19: 281 return "TMCC1 - Engine " + A + " - Num 3 - Sound On w/Start-Up Sequence"; 282 case 20: 283 return "TMCC1 - Engine " + A + " - Num 4 - Sound Volume Decrease - TMCC1 Feature Type 4"; 284 case 21: 285 return "TMCC1 - Engine " + A + " - Num 5 - Sound Off w/Shut-Down Sequence - TMCC1 Feature Type 5"; 286 case 22: 287 return "TMCC1 - Engine " + A + " - Num 6 - Steam Release/RPM Decrease - TMCC1 Feature Type 6"; 288 case 23: 289 return "TMCC1 - Engine " + A + " - Num 7 - Tower Com Announcement"; 290 case 24: 291 return "TMCC1 - Engine " + A + " - Num 8 - Feature Off (Smoke/Aux Lighting) - TMCC1 Feature Type 8"; 292 case 25: 293 return "TMCC1 - Engine " + A + " - Num 9 - Feature On (Smoke/Aux Lighting)"; 294 case 26: 295 296 case 27: 297 298 case 28: 299 return "TMCC1 - Engine " + A + " - Blow Whistle/Horn 1"; 300 case 29: 301 return "TMCC1 - Engine " + A + " - Ring Bell"; 302 case 30: 303 return "TMCC1 - Engine " + A + " - Letoff Sound"; 304 case 31: 305 return "TMCC1 - Engine " + A + " - Blow Horn 2"; 306 default: 307 return "TMCC1 - Engine " + A + " - Unassigned FnKey TMCC1 (Case C=0) - with A= " + A + " C= " + C + " D= " + D; 308 } 309 310 case 1: // If C (TMCC Command Code) == 1 311 switch (D & 0x17) { 312 case 0: 313 return "TMCC1 - Engine " + A + " - Momentum Low"; 314 case 1: 315 return "TMCC1 - Engine " + A + " - Momentum Medium"; 316 case 2: 317 return "TMCC1 - Engine " + A + " - Momentum High"; 318 case 3: 319 return "TMCC1 - Engine ID " + A + " - Set"; 320 default: 321 return "TMCC1 - Engine " + A + " - Unassigned FnKey TMCC1 (Case C=1) - with A= " + A + " C= " + C + " D= " + D; 322 } 323 324 //$FALL-THROUGH$ 325 case 2: // If C (TMCC Command Code) == 2 326 return "TMCC1 - Engine " + A + " - Change Speed (Relative) by " + (D - 5); 327 328 case 3: // If C (TMCC Command Code) == 3 329 default: // to let the compiler know there are only 3 cases 330 return "TMCC1 (32 Speed Steps) - Engine " + A + " - Speed (Absolute) = " + D; 331 } 332 333 334 } else if ((val & 0xF800) == 0xC800) { 335 // TMCC1 Train Commands 336 int A = (val / 128) & 0x0F; // A is TMCC Adddress Code 337 int C = (val / 32) & 0x03; // C is TMCC Command Code 338 int D = val & 0x1F; // D is TMCC Data Code 339 return "Unrecognized Train(TR) Command with A= " + A + " C= " + C + " D= " + D; 340 341 342 } else if ((val & 0xC000) == 0x8000) { 343 // TMCC1 Accessory Commands 344 int A = (val / 128) & 0x7F; // A is TMCC Adddress Code 345 int C = (val / 32) & 0x03; // C is TMCC Command Code 346 int D = val & 0x1F; // D is TMCC Data Code 347 switch (C) { 348 case 0: // If C (TMCC Command Code) == 0 349 switch (D) { 350 case 0: 351 case 1: 352 case 2: 353 case 3: 354 case 4: 355 case 5: 356 case 6: 357 case 7: 358 case 8: 359 return "Aux 1 - ACC " + A + " - OFF"; 360 case 9: 361 return "Aux 1 - ACC " + A + " - OPTION 1"; 362 case 10: 363 return "Aux 1 - ACC " + A + " - OPTION 2"; 364 case 11: 365 return "Aux 1 - ACC " + A + " - ON"; 366 case 12: 367 return "Aux 2 - ACC " + A + " - OFF"; 368 case 13: 369 return "Aux 2 - ACC " + A + " - OPTION 1"; 370 case 14: 371 return "Aux 2 - ACC " + A + " - OPTION 2"; 372 case 15: 373 return "Aux 2 - ACC " + A + " - ON"; 374 default: 375 return "Unrecognized Accessory(ACC) Command (Case C=0) - with A= " + A + " C= " + C + " D= " + D; 376 } 377 378 case 1: // If C (TMCC Command Code) == 1 379 switch (D) { 380 case 0: 381 return "ALL ACC OFF"; 382 case 11: 383 return "Accessory ID " + A + " - Set"; 384 case 15: 385 return "ALL ACC ON"; 386// } else if ((C == 1) && (D == 0x??)) { 387// return "Assign Aux 1 to Group D " + A + " - 0-9"; 388// } else if ((C == 1) && (D == 0x??)) { 389// return "Assign Aux 2 to Group D " + A + " - 0-9""; 390 default: 391 return "Unrecognized Accessory(ACC) Command (Case C=1) - with A= " + A + " C= " + C + " D= " + D; 392 } 393 394 default: 395 return "Unrecognized Accessory(ACC) Command (Case C) - with A= " + A + " C= " + C + " D= " + D; 396 } 397 398 399 } else if ((val & 0xF800) == 0xC000) { 400 // TMCC1 Group Commands 401 int A = (val / 128) & 0x0F; // A is TMCC Adddress Code 402 int C = (val / 32) & 0x03; // C is TMCC Command Code 403 int D = val & 0x1F; // D is TMCC Data Code 404 switch (C) { 405 case 0: // If C (TMCC Command Code) == 0 406 switch (D) { 407 case 0: 408 case 1: 409 case 2: 410 case 3: 411 case 4: 412 case 5: 413 case 6: 414 case 7: 415 case 8: 416 return "GROUP - ACC " + A + " - OFF"; 417 case 9: 418 return "GROUP - ACC " + A + " - OPTION 1"; 419 case 10: 420 return "GROUP - ACC " + A + " - OPTION 2"; 421 case 11: 422 return "GROUP - ACC " + A + " - ON"; 423 default: 424 return "Unrecognized Group(GR) Command (Case C=0) - with A= " + A + " C= " + C + " D= " + D; 425 } 426 427 case 1: // If C (TMCC Command Code) == 1 428 switch (D) { 429 case 12: 430 return "GROUP - ACC " + A + " - CLEAR"; 431 default: 432 return "Unrecognized Group(GR) Command (Case C=1) - with A= " + A + " C= " + C + " D= " + D; 433 } 434 435 default: 436 return "Unrecognized Group(GR) Command (Case C) - with A= " + A + " C= " + C + " D= " + D; 437 } 438 } 439 } 440 441 442 // TMCC Error parsing 443 if (opCode == 0x00) { 444 int C = (val / 32) & 0x03; // C is TMCC Command Code 445 int D = val & 0x1F; // D is TMCC Data Code 446 switch (C) { 447 case 0: // If C (TMCC Command Code) == 0 448 switch (D) { 449 case 0: 450 return "Address Must be Between 1-98 for TMCC"; 451 case 1: 452 return "CV Must Equal 1 for Programming TMCC Loco/Engine, Switch, Accessory ID#s"; 453 case 2: 454 return "CV Must Equal 2 for Programming TMCC Feature Type"; 455 case 3: 456 return "Value Entered is Not a TMCC1 Feature Type"; 457 case 4: 458 return "Value Entered is Not a TMCC2 Feature Type"; 459 default: 460 return "Unrecognized TMCC Error (Case C=0) - with C= " + C + " D= " + D; 461 } 462 default: 463 return "Unrecognized TMCC Error (Case C) - with C= " + C + " D= " + D; 464 } 465 } 466 467 return "TMCC - CV#, Loco ID#/Address/Feature Value - Out of Range"; 468 469 } 470} 471