001package jmri.jmrix.tmcc; 002 003import jmri.DccLocoAddress; 004import jmri.LocoAddress; 005import jmri.SpeedStepMode; 006import jmri.jmrix.AbstractThrottle; 007 008/** 009 * An implementation of DccThrottle. 010 * <p> 011 * Addresses of 99 and below are considered short addresses, and over 100 are 012 * considered long addresses. 013 * 014 * @author Bob Jacobsen Copyright (C) 2001, 2006 015 * with edits/additions by 016 * @author Timothy Jump Copyright (C) 2025 017 */ 018public class SerialThrottle extends AbstractThrottle { 019 020 /** 021 * Constructor. 022 * 023 * @param memo the connected SerialTrafficController 024 * @param address Loco ID 025 */ 026 public SerialThrottle(TmccSystemConnectionMemo memo, DccLocoAddress address) { 027 super(memo, 69); // supports 69 functions 028 tc = memo.getTrafficController(); 029 030 // cache settings. It would be better to read the 031 // actual state, but I don't know how to do this 032 synchronized(this) { 033 this.speedSetting = 0; 034 } 035 // Functions default to false 036 this.address = address; 037 this.isForward = true; 038 this.speedStepMode = SpeedStepMode.TMCC1_32; 039 } 040 041 private final DccLocoAddress address; 042 private final SerialTrafficController tc; 043 044 /** 045 * {@inheritDoc} 046 */ 047 @Override 048 public LocoAddress getLocoAddress() { 049 return address; 050 } 051 052 // Relating SERIAL_FUNCTION_CODES_TMCC1 to SpeedStepMode.TMCC1_32 and TMCC1_100; 053 // and SERIAL_FUNCTION_CODES_TMCC2 to SpeedStepMode.TMCC2_32 and TMCC2_200. 054 private long getFnValue(int number) { 055 if (getSpeedStepMode() == jmri.SpeedStepMode.TMCC1_32 || getSpeedStepMode() == jmri.SpeedStepMode.TMCC1_100) { 056 if (number < SERIAL_FUNCTION_CODES_TMCC1.length) { 057 return SERIAL_FUNCTION_CODES_TMCC1[number]; 058 } else { 059 return 0; 060 } 061 } else if (getSpeedStepMode() == jmri.SpeedStepMode.TMCC2_32) { 062 if (number < SERIAL_FUNCTION_CODES_TMCC2_32.length) { 063 return SERIAL_FUNCTION_CODES_TMCC2_32[number]; 064 } else { 065 return 0; 066 } 067 } else if (getSpeedStepMode() == jmri.SpeedStepMode.TMCC2_200) { 068 if (number < SERIAL_FUNCTION_CODES_TMCC2_200.length) { 069 return SERIAL_FUNCTION_CODES_TMCC2_200[number]; 070 } else { 071 return 0; 072 } 073 } 074 return 0; 075 } 076 077 078 /** 079 * {@inheritDoc} 080 */ 081 @Override 082 public void setFunction(int func, boolean value) { 083 updateFunction(func, value); 084 if (func>=0 && func < SERIAL_FUNCTION_CODES_TMCC1.length) { 085 if ( getFnValue(func) > 0xFFFF ) { 086 // TMCC 2 format 087 if (getFnValue(func) > 0xFFFFFF ) { 088 int first = (int)(getFnValue(func) >> 24); 089 int second = (int)(getFnValue(func) & 0xFFFFFF); 090 // doubles are only sent once, not repeating 091 sendOneWordOnce(first + address.getNumber() * 512); 092 sendOneWordOnce(second + address.getNumber() * 512); 093 } else { 094 // single message 095 sendFnToLayout((int)getFnValue(func) + address.getNumber() * 512, func); 096 } 097 } else { 098 // TMCC 1 format 099 sendFnToLayout((int)getFnValue(func) + address.getNumber() * 128, func); 100 } 101 } else { 102 super.setFunction(func, value); 103 } 104 } 105 106 // the argument is a long containing 3 bytes. 107 // The first byte is the message opcode 108 private void sendOneWordOnce(int word) { 109 SerialMessage m = new SerialMessage(word); 110 tc.sendSerialMessage(m, null); 111 } 112 113 // TMCC 1 Function Keys to trigger with TMCC1_32 and TMCC1_100 speed steps. 114 private final static long[] SERIAL_FUNCTION_CODES_TMCC1 = new long[] { 115 116 // TMCC1 Remote - Buttons 117 0x00000D, 0x00001D, 0x00001C, 0x000005, 0x000006, /* Fn0-4 */ 118 119 // TMCC1 Remote - KeyPad Buttons 120 0x000011, 0x000012, 0x000013, /* Fn5-7 */ 121 0x000014, 0x000015, 0x000016, /* Fn8-10 */ 122 0x000017, 0x000018, 0x000019, /* Fn11-13 */ 123 0x000010, /* Fn14 */ 124 125 // TMCC1 Remote - Buttons 126 0x000009, 0x00001E, 0x000004, 0x000007, 0x000028, /* Fn15-19 */ 127 0x000029, 0x00002A, 0x00002B, 0x00001F, /* 20-23 */ 128 129 // TMCC1 RR Speed FnKeys 130 0x000064, // Fn24 ( 4) 131 0x00006A, // Fn25 (10) 132 0x00006E, // Fn26 (14) 133 0x000072, // Fn27 (18) 134 0x000078, // Fn28 (24) 135 0x00007F, // Fn29 (31) 136 137 // TMCC1 Aux FnKeys 138 0x000008, // Fn30 (Aux1 Off) 139 0x000009, // Fn31 (Aux1 Option 1 - On While Held) 140 0x00000A, // Fn32 (Aux1 Option 2 - Toggle On/Toggle Off) 141 0x00000B, // Fn33 (Aux1 On) 142 0x00000C, // Fn34 (Aux2 Off) 143 0x00000D, // Fn35 (Aux2 Option 1 - On While Held) 144 0x00000E, // Fn36 (Aux2 Option 2 - Toggle On/Toggle Off) 145 0x00000F, // Fn37 (Aux2 On) 146 147 // TMCC1 Unused FnKeys 148 0x00002E, // Fn38 149 0x00002E, // Fn39 150 0x00002E, // Fn40 151 0x00002E, // Fn41 152 0x00002E, // Fn42 153 0x00002E, // Fn43 154 0x00002E, // Fn44 155 0x00002E, // Fn45 156 0x00002E, // Fn46 157 0x00002E, // Fn47 158 0x00002E, // Fn48 159 0x00002E, // Fn49 160 0x00002E, // Fn50 161 0x00002E, // Fn51 162 0x00002E, // Fn52 163 0x00002E, // Fn53 164 0x00002E, // Fn54 165 0x00002E, // Fn55 166 0x00002E, // Fn56 167 0x00002E, // Fn57 168 0x00002E, // Fn58 169 0x00002E, // Fn59 170 0x00002E, // Fn60 171 0x00002E, // Fn61 172 0x00002E, // Fn62 173 0x00002E, // Fn63 174 0x00002E, // Fn64 175 0x00002E, // Fn65 176 0x00002E, // Fn66 177 0x00002E, // Fn67 178 0x00002E, // Fn68 179 }; 180 181 /** 182 * Translate TMCC1 function numbers to line characters. 183 * If the upper byte is zero, it will be replaced by 0xF8 184 * and the address will be set in the low position. 185 * If the upper byte is non-zero, that value will be sent, 186 * and the address will be set in the upper (TMCC2) position. 187 * If six bytes are specified (with the upper one non-zero), 188 * this will be interpreted as two commands to be sequentially sent, 189 * with the upper bytes sent first. 190 */ 191 192 // TMCC 2 Legacy Function Keys to trigger with TMCC2_32 speed steps. 193 private final static long[] SERIAL_FUNCTION_CODES_TMCC2_32 = new long[] { 194 195 // TMCC2_32 Remote - Buttons 196 0xF8010D, 0xF8011D, 0xF8011C, 0xF80105, 0xF80106, /* Fn0-4 */ 197 198 // TMCC2_32 Remote - Keypad Buttons 199 0xF80111, 0xF80112, 0xF80113, /* Fn5-7 */ 200 0xF80114, 0xF80115, 0xF80116, /* Fn8-10 */ 201 0xF80117, 0xF80118, 0xF80119, /* Fn11-13 */ 202 0xF80110, /* Fn14 */ 203 204 // TMCC2_32 Remote - Buttons 205 0xF80109, 0xF8011E, 0xF80104, 0xF80107, 0xF80128, /* Fn15-19 */ 206 0xF80129, 0xF8012A, 0xF8012B, 0xF8011F,/* 20-23 */ 207 208 // TMCC2_32 RR Speed FnKeys 209 0xF80164, // Fn24 ( 4) 210 0xF8016A, // Fn25 (10) 211 0xF8016E, // Fn26 (14) 212 0xF80172, // Fn27 (18) 213 0xF80178, // Fn28 (24) 214 0xF8017F, // Fn29 (31) 215 216 // TMCC2_32 Extended Lighting FnKeys 217 // Fn?? (Mars On) 218 // Fn?? (Mars Off) 219 220 // Fn?? (Ground Lt On) 221 // Fn?? (Ground Lt Off) 222 // Fn?? (Ground Lt Auto) 223 224 // Fn?? (DogHouse On) 225 // Fn?? (DogHouse Off) 226 227 // Fn?? (Tender Marker On) 228 // Fn?? (Tender Marker Off) 229 230 // Fn?? (Loco On) 231 // Fn?? (Loco Off) 232 233 // Fn?? (Rule 17 On) 234 // Fn?? (Rule 17 Off) 235 // Fn?? (Rule 17 Auto) 236 237 // Fn?? (Ditch Lt On) 238 // Fn?? (Ditch Lt On; Pulse Off with Horn) 239 // Fn?? (Ditch Lt Off; Pulse On with Horn) 240 // Fn?? (Ditch Lt Off) 241 242 // Fn?? (Cab Lt On) 243 // Fn?? (Cab Lt Off) 244 // Fn?? (Cab Lt Auto) 245 246 // Fn?? (Loco Marker On) 247 // Fn?? (Loco Marker Off) 248 249 // Fn?? (Hazard Lt On) 250 // Fn?? (Hazard Lt Off) 251 // Fn?? (Hazard Lt Auto) 252 253 // Fn?? (Strobe Lt On - Single Flash) 254 // Fn?? (Strobe Lt On - Double Flash) 255 // Fn?? (Strobe Lt Off) 256 257 // Fn?? (Car Cabin Lt On) 258 // Fn?? (Car Cabin Lt Off) 259 // Fn?? (Car Cabin Lt Auto) 260 261 262 //0xF8017DFB01F2FB0189L, // Fn35 Set Cab Light Auto (test!!!) 263 264 265 // Extended Sound Effects FnKeys 266 //0xF801FBF801FCL, // Fn35 Start Up Sequence 1 (Delayed Prime Mover, then Immediate Start Up) 267 //0xF801FC, // Fn36 Start Up Sequence 2 (Immediate Start Up) 268 //0xF801FDF801FEL, // Fn37 Shut Down Sequence 1 (Delay w/ Announcement then Immediate Shut Down) 269 //0xF801FE, // Fn38 Shut down Sequence 2 (Immediate Shut Down) 270 271 272 // TRMCC2_32 Aux FnKeys 273 0xF80108, // Fn30 274 0xF8010A, // Fn31 275 0xF8010B, // Fn32 276 0xF8010C, // Fn33 277 0xF8010E, // Fn34 278 0xF8010F, // Fn35 279 280 // TRMCC2_32 Unused FnKeys 281 0xF8012E, // Fn36 282 0xF8012E, // Fn37 283 0xF8012E, // Fn38 284 0xF8012E, // Fn39 285 0xF8012E, // Fn40 286 0xF8012E, // Fn41 287 0xF8012E, // Fn42 288 0xF8012E, // Fn43 289 0xF8012E, // Fn44 290 0xF8012E, // Fn45 291 0xF8012E, // Fn46 292 0xF8012E, // Fn47 293 0xF8012E, // Fn48 294 0xF8012E, // Fn49 295 0xF8012E, // Fn50 296 0xF8012E, // Fn51 297 0xF8012E, // Fn52 298 0xF8012E, // Fn53 299 0xF8012E, // Fn54 300 0xF8012E, // Fn55 301 0xF8012E, // Fn56 302 0xF8012E, // Fn57 303 0xF8012E, // Fn58 304 0xF8012E, // Fn59 305 0xF8012E, // Fn60 306 0xF8012E, // Fn61 307 0xF8012E, // Fn62 308 0xF8012E, // Fn63 309 }; 310 311 // TMCC 2 Legacy Function Keys to trigger with TMCC2_200 speed steps. 312 private final static long[] SERIAL_FUNCTION_CODES_TMCC2_200 = new long[] { 313 314 // TMCC2_200 Remote - Buttons 315 0xF8010D, 0xF8011D, 0xF8011C, 0xF80105, 0xF80106, /* Fn0-4 */ 316 317 // TMCC2_200 Remote - Keypad Buttons 318 0xF80111, 0xF80112, 0xF80113, /* Fn5-7 */ 319 0xF80114, 0xF80115, 0xF80116, /* Fn8-10 */ 320 0xF80117, 0xF80118, 0xF80119, /* Fn11-13 */ 321 0xF80110, /* Fn14 */ 322 323 // TMCC2_200 Remote - Buttons 324 0xF80109, 0xF8011E, 0xF80104, 0xF80107, 0xF80128, /* Fn15-19 */ 325 0xF80129, 0xF8012A, 0xF8012B, 0xF8011F,/* 20-23 */ 326 327 // TMCC2_200 RR Speed FnKeys 328 0xF8000A, // Fn24 ( 10) 329 0xF80028, // Fn25 ( 40) 330 0xF80046, // Fn26 ( 70) 331 0xF80064, // Fn27 (100) 332 0xF8008C, // Fn28 (140) 333 0xF800C7, // Fn29 (199) 334 335 // TMCC2_200 Extended Lighting FnKeys 336 337 //0xF8017DFB01F2FB0189L, // Fn35 Set Cab Light Auto (test!!!) 338 339 340 // Extended Sound Effects FnKeys 341 //0xF801FBF801FCL, // Fn35 Start Up Sequence 1 (Delayed Prime Mover, then Immediate Start Up) 342 //0xF801FC, // Fn36 Start Up Sequence 2 (Immediate Start Up) 343 //0xF801FDF801FEL, // Fn37 Shut Down Sequence 1 (Delay w/ Announcement then Immediate Shut Down) 344 //0xF801FE, // Fn38 Shut down Sequence 2 (Immediate Shut Down) 345 346 347 // TMCC2_200 Aux FnKeys 348 0xF80108, // Fn30 349 0xF8010A, // Fn31 350 0xF8010B, // Fn32 351 0xF8010C, // Fn33 352 0xF8010E, // Fn34 353 0xF8010F, // Fn35 354 355 // TMCC2_200 Unused FnKeys 356 0xF8012E, // Fn36 357 0xF8012E, // Fn37 358 0xF8012E, // Fn38 359 0xF8012E, // Fn39 360 0xF8012E, // Fn40 361 0xF8012E, // Fn41 362 0xF8012E, // Fn42 363 0xF8012E, // Fn43 364 0xF8012E, // Fn44 365 0xF8012E, // Fn45 366 0xF8012E, // Fn46 367 0xF8012E, // Fn47 368 0xF8012E, // Fn48 369 0xF8012E, // Fn49 370 0xF8012E, // Fn50 371 0xF8012E, // Fn51 372 0xF8012E, // Fn52 373 0xF8012E, // Fn53 374 0xF8012E, // Fn54 375 0xF8012E, // Fn55 376 0xF8012E, // Fn56 377 0xF8012E, // Fn57 378 0xF8012E, // Fn58 379 0xF8012E, // Fn59 380 0xF8012E, // Fn60 381 0xF8012E, // Fn61 382 0xF8012E, // Fn62 383 0xF8012E, // Fn63 384 }; 385 386 /** 387 * Set the speed. 388 * 389 * @param speed Number from 0 to 1; less than zero is emergency stop 390 */ 391 @Override 392 public void setSpeedSetting(float speed) { 393 float oldSpeed; 394 synchronized(this) { 395 oldSpeed = this.speedSetting; 396 this.speedSetting = speed; 397 } 398 399 // send to layout option 200 speed steps 400 if (speedStepMode == jmri.SpeedStepMode.TMCC2_200) { 401 402 // TMCC2 Legacy 200 speed step mode 403 int value = (int) (199 * speed); // max value to send is 199 in 200 step mode 404 if (value > 199) { 405 // max possible speed 406 value = 199; 407 } 408 SerialMessage m = new SerialMessage(); 409 m.setOpCode(0xF8); 410 411 if (value < 0) { 412 // System HALT (immediate stop; ALL) 413 m.putAsWord(0xFF8B); 414 } else { 415 // normal speed setting 416 m.putAsWord(0x0000 + (address.getNumber() << 9) + value); 417 } 418 // send to command station (send twice is set, but number of sends may need to be adjusted depending on efficiency) 419 tc.sendSerialMessage(m, null); 420 tc.sendSerialMessage(m, null); 421 } 422 423 // send to layout option 100 speed steps 424 if (speedStepMode == jmri.SpeedStepMode.TMCC1_100) { 425 426 /** 427 * TMCC1 ERR 100 speed step mode 428 * purpose is to increase resolution of 32 bits 429 * across 100 throttle 'clicks' by dividing value by 3 430 * and setting top speed at 32 431 */ 432 int value = (int) (99 * speed); // max value to send is 99 in 100 step mode 433 if (value > 93) { 434 // max possible speed step 435 value = 93; 436 } 437 SerialMessage m = new SerialMessage(); 438 m.setOpCode(0xFE); 439 440 if (value < 0) { 441 // System HALT (immediate stop; ALL) 442 m.putAsWord(0xFFFF); 443 } 444 if (value >= 0) { 445 // normal speed step setting 446 m.putAsWord(0x0060 + address.getNumber() * 128 + value / 3); 447 } 448 449 // send to command station (send twice is set, but number of sends may need to be adjusted depending on efficiency) 450 tc.sendSerialMessage(m, null); 451 tc.sendSerialMessage(m, null); 452 } 453 454 // send to layout option TMCC2 32 speed steps 455 if (speedStepMode == jmri.SpeedStepMode.TMCC2_32) { 456 457 // TMCC2 Legacy 32 speed step mode 458 int value = (int) (32 * speed); 459 if (value > 31) { 460 // max possible speed 461 value = 31; 462 } 463 SerialMessage m = new SerialMessage(); 464 m.setOpCode(0xF8); 465 466 if (value < 0) { 467 // System HALT (immediate stop; ALL) 468 m.putAsWord(0xFF8B); 469 } else { 470 // normal speed setting 471 m.putAsWord(0x0160 + address.getNumber() * 512 + value); 472 } 473 474 // send to command station (send twice is set, but number of sends may need to be adjusted depending on efficiency) 475 tc.sendSerialMessage(m, null); 476 tc.sendSerialMessage(m, null); 477 } 478 479 // send to layout option TMCC1 32 speed steps 480 if (speedStepMode == jmri.SpeedStepMode.TMCC1_32) { 481 482 // TMCC1 32 speed step mode 483 int value = (int) (32 * speed); 484 if (value > 31) { 485 // max possible speed 486 value = 31; 487 } 488 SerialMessage m = new SerialMessage(); 489 m.setOpCode(0xFE); 490 491 if (value < 0) { 492 // System HALT (immediate stop; ALL) 493 m.putAsWord(0xFFFF); 494 } else { 495 // normal speed setting 496 m.putAsWord(0x0060 + address.getNumber() * 128 + value); 497 } 498 499 // send to command station (send twice is set, but number of sends may need to be adjusted depending on efficiency) 500 tc.sendSerialMessage(m, null); 501 tc.sendSerialMessage(m, null); 502 } 503 504 synchronized(this) { 505 firePropertyChange(SPEEDSETTING, oldSpeed, this.speedSetting); 506 } 507 record(speed); 508 } 509 510 /** 511 * {@inheritDoc} 512 */ 513 @Override 514 public void setIsForward(boolean forward) { 515 boolean old = isForward; 516 isForward = forward; 517 518 // notify layout 519 SerialMessage m = new SerialMessage(); 520 if (speedStepMode == jmri.SpeedStepMode.TMCC1_32 || speedStepMode == jmri.SpeedStepMode.TMCC1_100) { 521 m.setOpCode(0xFE); 522 if (forward) { 523 m.putAsWord(0x0000 + address.getNumber() * 128); 524 setSpeedSetting(0.0f); 525 } else { 526 m.putAsWord(0x0003 + address.getNumber() * 128); 527 setSpeedSetting(0.0f); 528 } 529 } 530 531 if (speedStepMode == jmri.SpeedStepMode.TMCC2_32 || speedStepMode == jmri.SpeedStepMode.TMCC2_200) { 532 m.setOpCode(0xF8); 533 if (forward) { 534 m.putAsWord(0x0100 + address.getNumber() * 512); 535 setSpeedSetting(0.0f); 536 } else { 537 m.putAsWord(0x0103 + address.getNumber() * 512); 538 setSpeedSetting(0.0f); 539 } 540 } 541 542 // send to command station (send twice is set, but number of sends may need to be adjusted depending on efficiency) 543 tc.sendSerialMessage(m, null); 544 tc.sendSerialMessage(m, null); 545 546 firePropertyChange(ISFORWARD, old, isForward); 547 } 548 549 /** 550 * Send these messages to the layout and repeat 551 * while button is pressed/on. 552 * @param value Content of message to be sent in three bytes 553 * @param func The number of the function being addressed 554 */ 555 protected void sendFnToLayout(int value, int func) { 556 557 if (speedStepMode == jmri.SpeedStepMode.TMCC2_200) { 558 if (func == 24) { 559 setSpeedSetting(0.055f); 560 return; 561 } 562 if (func == 25) { 563 setSpeedSetting(0.205f); 564 return; 565 } 566 if (func == 26) { 567 setSpeedSetting(0.355f); 568 return; 569 } 570 if (func == 27) { 571 setSpeedSetting(0.505f); 572 return; 573 } 574 if (func == 28) { 575 setSpeedSetting(0.705f); 576 return; 577 } 578 if (func == 29) { 579 setSpeedSetting(1.0f); 580 return; 581 } 582 } 583 584 if (speedStepMode == jmri.SpeedStepMode.TMCC1_32 || speedStepMode == jmri.SpeedStepMode.TMCC1_100 || speedStepMode == jmri.SpeedStepMode.TMCC2_32) { 585 if (func == 24) { 586 setSpeedSetting(0.130f); 587 return; 588 } 589 if (func == 25) { 590 setSpeedSetting(0.320f); 591 return; 592 } 593 if (func == 26) { 594 setSpeedSetting(0.450f); 595 return; 596 } 597 if (func == 27) { 598 setSpeedSetting(0.580f); 599 return; 600 } 601 if (func == 28) { 602 setSpeedSetting(0.775f); 603 return; 604 } 605 if (func == 29) { 606 setSpeedSetting(1.0f); 607 return; 608 } 609 } 610 611 /** 612 * This code sends FnKey presses to the command station. 613 * Send once is set, per the need of TMCC multi-key commands that 614 * do not work when a specific command sequence is not followed. 615 * If these multi-key commands are integrated into single FnKeys, 616 * this "send" section can be converted back to "send twice" as 617 * the other send sequences througout tmcc\SerialThrottle.java. 618 */ 619 620 repeatFunctionSendWhileOn(value, func); // Single FnKey Press, Single Send; FnKey Held, Repeats FnKey while pressed. 621 } 622 623 /** 624 * This code block is necessary to support the send repeats of 625 * the repeatFunctionSendWhileOn(value, func); code above. 626 * This code block "Sends Again" if FkKey is still pressed/on, and 627 * repeats per the interval set in static final int REPEAT_TIME. 628 */ 629 630 static final int REPEAT_TIME = 150; 631 632 protected void repeatFunctionSendWhileOn(int value, int func) { 633 if (getFunction(func)) { 634 tc.sendSerialMessage(new SerialMessage(value), null); 635 jmri.util.ThreadingUtil.runOnLayoutDelayed(() -> { 636 repeatFunctionSendWhileOn(value, func); 637 }, REPEAT_TIME); 638 } 639 } 640 641 /* 642 * Set the speed step value. 643 * <p> 644 * Only 32 steps is available 645 * 646 * @param mode only TMCC1 32, TMCC2 32, TMCC1 100 and TMCC2 200 are allowed 647 */ 648 @Override 649 public void setSpeedStepMode(jmri.SpeedStepMode mode) { 650 if (mode == jmri.SpeedStepMode.TMCC1_32 || mode == jmri.SpeedStepMode.TMCC2_32 || mode == jmri.SpeedStepMode.TMCC1_100 || mode == jmri.SpeedStepMode.TMCC2_200) { 651 super.setSpeedStepMode(mode); 652 } 653 } 654 655 /** 656 * {@inheritDoc} 657 */ 658 @Override 659 public void throttleDispose() { 660 finishRecord(); 661 } 662 663}