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