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 (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)"; 095 case 10: 096 return "TMCC2 - Engine " + A + " - AUX1 Option 2"; 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 On/Off"; 103 case 14: 104 return "TMCC2 - Engine " + A + " - AUX2 Option 2"; 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)"; 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 On/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 return "Unrecognized Train(TR) Command with A= " + A + " C= " + C + " D= " + D; 345 346 347 } else if ((val & 0xC000) == 0x8000) { 348 // TMCC1 Accessory Commands 349 int A = (val / 128) & 0x7F; // A is TMCC Adddress Code 350 int C = (val / 32) & 0x03; // C is TMCC Command Code 351 int D = val & 0x1F; // D is TMCC Data Code 352 switch (C) { 353 case 0: // If C (TMCC Command Code) == 0 354 switch (D) { 355 case 0: 356 case 1: 357 case 2: 358 case 3: 359 case 4: 360 case 5: 361 case 6: 362 case 7: 363 case 8: 364 return "Aux 1 - ACC " + A + " - OFF"; 365 case 9: 366 return "Aux 1 - ACC " + A + " - OPTION 1"; 367 case 10: 368 return "Aux 1 - ACC " + A + " - OPTION 2"; 369 case 11: 370 return "Aux 1 - ACC " + A + " - ON"; 371 case 12: 372 return "Aux 2 - ACC " + A + " - OFF"; 373 case 13: 374 return "Aux 2 - ACC " + A + " - OPTION 1"; 375 case 14: 376 return "Aux 2 - ACC " + A + " - OPTION 2"; 377 case 15: 378 return "Aux 2 - ACC " + A + " - ON"; 379 default: 380 return "Unrecognized Accessory(ACC) Command (Case C=0) - with A= " + A + " C= " + C + " D= " + D; 381 } 382 383 case 1: // If C (TMCC Command Code) == 1 384 switch (D) { 385 case 0: 386 return "ALL ACC OFF"; 387 case 11: 388 return "Accessory ID " + A + " - Set"; 389 case 15: 390 return "ALL ACC ON"; 391// } else if ((C == 1) && (D == 0x??)) { 392// return "Assign Aux 1 to Group D " + A + " - 0-9"; 393// } else if ((C == 1) && (D == 0x??)) { 394// return "Assign Aux 2 to Group D " + A + " - 0-9""; 395 default: 396 return "Unrecognized Accessory(ACC) Command (Case C=1) - with A= " + A + " C= " + C + " D= " + D; 397 } 398 399 default: 400 return "Unrecognized Accessory(ACC) Command (Case C) - with A= " + A + " C= " + C + " D= " + D; 401 } 402 403 404 } else if ((val & 0xF800) == 0xC000) { 405 // TMCC1 Group Commands 406 int A = (val / 128) & 0x0F; // A is TMCC Adddress Code 407 int C = (val / 32) & 0x03; // C is TMCC Command Code 408 int D = val & 0x1F; // D is TMCC Data Code 409 switch (C) { 410 case 0: // If C (TMCC Command Code) == 0 411 switch (D) { 412 case 0: 413 case 1: 414 case 2: 415 case 3: 416 case 4: 417 case 5: 418 case 6: 419 case 7: 420 case 8: 421 return "GROUP - ACC " + A + " - OFF"; 422 case 9: 423 return "GROUP - ACC " + A + " - OPTION 1"; 424 case 10: 425 return "GROUP - ACC " + A + " - OPTION 2"; 426 case 11: 427 return "GROUP - ACC " + A + " - ON"; 428 default: 429 return "Unrecognized Group(GR) Command (Case C=0) - with A= " + A + " C= " + C + " D= " + D; 430 } 431 432 case 1: // If C (TMCC Command Code) == 1 433 switch (D) { 434 case 12: 435 return "GROUP - ACC " + A + " - CLEAR"; 436 default: 437 return "Unrecognized Group(GR) Command (Case C=1) - with A= " + A + " C= " + C + " D= " + D; 438 } 439 440 default: 441 return "Unrecognized Group(GR) Command (Case C) - with A= " + A + " C= " + C + " D= " + D; 442 } 443 } 444 445 if (val == 0xFFFF) { 446 return "TMCC1 - HALT - Emergency System Stop; ALL"; 447 } 448 449 } 450 451 452 // TMCC Error parsing 453 if (opCode == 0x00) { 454 int C = (val / 32) & 0x03; // C is TMCC Command Code 455 int D = val & 0x1F; // D is TMCC Data Code 456 switch (C) { 457 case 0: // If C (TMCC Command Code) == 0 458 switch (D) { 459 case 0: 460 return "Address Must be Between 1-98 for TMCC"; 461 case 1: 462 return "CV Must Equal 1 for Programming TMCC Loco/Engine, Switch, Accessory ID#s"; 463 case 2: 464 return "CV Must Equal 2 for Programming TMCC Feature Type"; 465 case 3: 466 return "Value Entered is Not a TMCC1 Feature Type"; 467 case 4: 468 return "Value Entered is Not a TMCC2 Feature Type"; 469 default: 470 return "Unrecognized TMCC Error (Case C=0) - with C= " + C + " D= " + D; 471 } 472 default: 473 return "Unrecognized TMCC Error (Case C) - with C= " + C + " D= " + D; 474 } 475 } 476 477 return "TMCC - CV#, Loco ID#/Address/Feature Value - Out of Range"; 478 479 } 480} 481