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, 85); // supports 85 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[] getFnValueArray(int number) {
055                
056            if (number < 0) return new long[]{};
057            
058            if (getSpeedStepMode() == jmri.SpeedStepMode.TMCC1_32 || getSpeedStepMode() == jmri.SpeedStepMode.TMCC1_100) {
059                if (number < SERIAL_FUNCTION_CODES_TMCC1.length) {
060                    return SERIAL_FUNCTION_CODES_TMCC1[number];
061                } else {
062                    return new long[]{};
063                }
064            } else if (getSpeedStepMode() == jmri.SpeedStepMode.TMCC1TR_32 || getSpeedStepMode() == jmri.SpeedStepMode.TMCC1TR_100) {
065                if (number < SERIAL_FUNCTION_CODES_TMCC1TR.length) {
066                    return SERIAL_FUNCTION_CODES_TMCC1TR[number];
067                } else {
068                    return new long[]{};
069                }
070            } else if (getSpeedStepMode() == jmri.SpeedStepMode.TMCC2_32) {
071                 if (number < SERIAL_FUNCTION_CODES_TMCC2_32.length) {
072                     return SERIAL_FUNCTION_CODES_TMCC2_32[number];
073                } else {
074                    return new long[]{};
075                }
076            } else if (getSpeedStepMode() == jmri.SpeedStepMode.TMCC2TR_32) {
077                 if (number < SERIAL_FUNCTION_CODES_TMCC2TR_32.length) {
078                     return SERIAL_FUNCTION_CODES_TMCC2TR_32[number];
079                } else {
080                    return new long[]{};
081                }
082            } else if (getSpeedStepMode() == jmri.SpeedStepMode.TMCC2_200) {
083                 if (number < SERIAL_FUNCTION_CODES_TMCC2_200.length) {
084                     return SERIAL_FUNCTION_CODES_TMCC2_200[number];
085                } else {
086                    return new long[]{};
087                }
088           } else if (getSpeedStepMode() == jmri.SpeedStepMode.TMCC2TR_200) {
089                 if (number < SERIAL_FUNCTION_CODES_TMCC2TR_200.length) {
090                     return SERIAL_FUNCTION_CODES_TMCC2TR_200[number];
091                } else {
092                    return new long[]{};
093                }
094            }
095            return new long[]{};
096        }
097
098
099    /**
100     * {@inheritDoc}
101     */
102    @Override
103    public void setFunction(int func, boolean value) {
104        updateFunction(func, value);
105        
106        int numberOfTriple = 0; // ordinal number of triple being processed, e.g. 1, 2, 3, ...
107            checksumAccumulator = 0; // zeroes out accumulated checksum after each instance
108        
109        if (getFnValueArray(func).length >0) {
110            for (long triple : getFnValueArray(func)) {
111                numberOfTriple = numberOfTriple+1;
112                
113                // process each returned command
114                if (func>=0 && func < SERIAL_FUNCTION_CODES_TMCC1.length) {
115                    if ( triple > 0xFFFF ) {
116                        // TMCC 2 format
117                        if (triple > 0xFFFFFF ) {
118                            int first =  (int)(triple >> 24);
119                            int second = (int)(triple & 0xFFFFFF);
120                            accumulateChecksum(first);
121                            accumulateChecksum(second);
122                            
123                            // if this is the third triple, place the 
124                            // checksum in its lowest byte
125                            if (numberOfTriple == 3) {
126                                second = (second &0xFFFFFF00) | ( (~checksumAccumulator) & 0xFF);
127                            }
128                            
129                            // doubles are only sent once, not repeating
130                            sendOneWordOnce(first  + address.getNumber() * 512);
131                            sendOneWordOnce(second + address.getNumber() * 512);
132                            
133                        } else {
134                            // single message
135                            int content = (int)triple + address.getNumber() * 512;
136                            accumulateChecksum(content);
137                            
138                            // if this is the third triple, place the 
139                            // checksum in its lowest byte
140                            if (numberOfTriple == 3) {
141                                content = (content &0xFFFFFF00) | ( (~checksumAccumulator) & 0xFF);
142                            }
143
144                            sendFnToLayout(content, func);
145                        }
146                    } else {
147                        // TMCC 1 format
148                        sendFnToLayout((int)triple + address.getNumber() * 128, func);
149                    }
150                } else {
151                    super.setFunction(func, value);
152                }
153            }
154        } else {
155            super.setFunction(func, value);
156        }
157    }
158
159    // accumulate the checksum values into
160    // the checksumAccumulator variable
161    //
162    // Takes the two bottom bytes _only_ and adds them to the accumulation.
163    int checksumAccumulator = 0;
164    private void accumulateChecksum(int input) {
165        int byte1 = input&0xFF;
166        int byte2 = (input >> 8)&0xFF;
167        checksumAccumulator = (checksumAccumulator + byte1+byte2) & 0xFF;
168    }
169    
170    // the argument is a long containing 3 bytes. 
171    // The first byte is the message opcode
172    private void sendOneWordOnce(int word) {
173        SerialMessage m = new SerialMessage(word);
174        tc.sendSerialMessage(m, null);
175    }
176
177    // TMCC 1 Function Keys to trigger with TMCC1_32 and TMCC1_100 speed steps.
178    private final static long[][] SERIAL_FUNCTION_CODES_TMCC1 = new long[][] {
179
180        // TMCC1 Remote - Defined FnKeys
181        {0x00000D}, // Fn0 (Headlamp)
182        {0x00001D}, // Fn1 (Bell)
183        {0x00001C}, // Fn2 (Horn/Whistle)
184        {0x000005}, // Fn3 (F - Open Front Coupler)
185        {0x000006}, // Fn4 (R - Open Rear Coupler)
186
187        // TMCC1 Remote - Defined KeyPad FnKeys
188        {0x000011}, {0x000012}, {0x000013}, /* Fn5-7 */ // 1-2-3
189        {0x000014}, {0x000015}, {0x000016}, /* Fn8-10 */ // 4-5-6
190        {0x000017}, {0x000018}, {0x000019}, /* Fn11-13 */ // 7-8-9
191                    {0x000010},             /* Fn14 */ // 0
192
193        // TMCC1 Remote - Defined FnKeys
194        {0x000009}, // Fn15 (Aux1)
195        {0x00001E}, // Fn16 (Letoff Sound)
196        {0x000004}, // Fn17 (Boost)
197        {0x000007}, // Fn18 (Brake)
198        {0x000028}, // Fn19 (Momentum Low)
199        {0x000029}, // Fn20 (Momentum Medium)
200        {0x00002A}, // Fn21 (Momentum High)
201        {0x00002B}, // Fn22 (Set)
202        {0x00001F}, // Fn23 (Horn 2)
203
204        // TMCC1 RR Speed FnKeys
205        {0x000064}, // Fn24 ( 4)   5mph
206        {0x00006A}, // Fn25 (10)  20mph
207        {0x00006E}, // Fn26 (14)  35mph
208        {0x000072}, // Fn27 (18)  50mph
209        {0x000078}, // Fn28 (24)  70mph
210        {0x00007F}, // Fn29 (31)   Full
211
212        // TMCC1 ERR - Set SpeedSteps
213        {0x000009, 0x000010, 0x000009, 0x000010, 0x000004}, // Fn30 (Set ERR 100 SpeedSteps)
214        {0x000009, 0x000010, 0x000009, 0x000010, 0x000007}, // Fn31 (Set ERR  32 SpeedSteps)
215
216        // TMCC1 Acela/Subway FnKeys
217        {0x000009, 0x000005}, // Fn32 (Open Doors - Left)
218        {0x00000D, 0x000005, 0x00000D}, // Fn33 (Close Doors - Left)
219        {0x000009, 0x000006}, // Fn34 (Open Doors - Right)
220        {0x00000D, 0x000006, 0x00000D}, // Fn35 (Close Doors - Right)
221        {0x000009, 0x000013}, // Fn36 (Pantagraph - Automatic/Prototypical)
222        {0x000009, 0x000015}, // Fn37 (Pantagraph - Down)
223        {0x000009, 0x000016}, // Fn38 (Pantagraph - Manual Mode/Cycles Through Positions)
224        {0x000009, 0x00001C}, // Fn39 (Toggle Horn - City/Country)
225        {0x000009, 0x000018}, // Fn40 (Cab Light - Off)
226        {0x000009, 0x000019}, // Fn41 (Cab Light - On)
227        {0x000009, 0x00000D, 0x000018, 0x00000D}, // Fn42 (Interior Lights - Off)
228        {0x000009, 0x00000D, 0x000019, 0x00000D}, // Fn43 (Interior Lights - On)
229
230        // TMCC1 Break-Down B Unit
231        {0x000009, 0x000004}, // Fn44 Start Breakdown Sequence
232        {0x000009, 0x000015}, // Fn45 Made It Back to the Yard
233        {0x000009, 0x000013}, // Fn46 Restart Unit/Repairs Complete
234
235        // TMCC1 Boxcar/LiveStock Car
236        {0x000009, 0x000013}, // Fn47 Load
237        {0x000009, 0x000012}, // Fn48 Flat Wheel Sound
238
239        // TMCC1 Passenger/Dining Cars
240        {0x000009, 0x000017}, // Fn49 Station PA Arrival Dialog
241        {0x000009, 0x000012}, // Fn50 Conductor Arrival Dialog
242
243        // TMCC1 Crane/Boom Car
244        {0x000009, 0x000011, 0x000007}, // Fn51 Lower the Boom
245        {0x000009, 0x000011, 0x000004}, // Fn52 Raises the Boom
246        {0x000009, 0x000012, 0x000007}, // Fn53 Lowers Main/Large Hook
247        {0x000009, 0x000012, 0x000004}, // Fn54 Raises Main/Large Hook
248        {0x000017, 0x000013, 0x000007}, // Fn55 Lowers Small Hook
249        {0x000017, 0x000013, 0x000004}, // Fn56 Raises Small Hook
250        {0x000004, 0x000014}, // Fn57 Front Work Lights (Toggles On/Off)
251        {0x000004, 0x000015}, // Fn58 Rear Work Lights (Toggles On/Off)
252        {0x000004, 0x000016}, // Fn59 Launches Outriggers
253        {0x000009, 0x000017}, // Fn60 Crew Dialog Off
254        {0x000009, 0x000018}, // Fn61 All Sounds Off
255        {0x000009, 0x000019}, // Fn62 All Sounds On
256
257        // TMCC1 Unassigned FnKeys
258        {0x00002E}, // Fn63 Code to Trigger SerialMonFrame Message/Unassigned FnKey
259        {0x00002E}, // Fn64 Code to Trigger SerialMonFrame Message/Unassigned FnKey
260        {0x00002E}, // Fn65 Code to Trigger SerialMonFrame Message/Unassigned FnKey
261        {0x00002E}, // Fn66 Code to Trigger SerialMonFrame Message/Unassigned FnKey
262        {0x00002E}, // Fn67 Code to Trigger SerialMonFrame Message/Unassigned FnKey
263        {0x00002E}, // Fn68 Code to Trigger SerialMonFrame Message/Unassigned FnKey
264
265        // TMCC1 Aux FnKeys
266        {0x000008}, // Fnxx (Aux1 Off)
267        {0x000009}, // Fnxx (Aux1 Option 1 - On While Held)
268        {0x00000A}, // Fnxx (Aux1 Option 2 - Toggle On/Toggle Off)
269        {0x00000B}, // Fnxx (Aux1 On)
270        {0x00000C}, // Fnxx (Aux2 Off)
271        {0x00000D}, // Fnxx (Aux2 Option 1 - Toggle On/Toggle Off)
272        {0x00000E}, // Fnxx (Aux2 Option 2 - On While Held)
273        {0x00000F}, // Fnxx (Aux2 On)
274
275    };
276
277    // TMCC 1 TR Function Keys to trigger with TMCC1TR_32 and TMCC1TR_100 speed steps.
278    private final static long[][] SERIAL_FUNCTION_CODES_TMCC1TR = new long[][] {
279
280        // TMCC1TR Remote - Defined FnKeys
281        {0x00C80D}, // Fn0 (Headlamp)
282        {0x00C81D}, // Fn1 (Bell)
283        {0x00C81C}, // Fn2 (Horn/Whistle)
284        {0x00C805}, // Fn3 (F - Open Front Coupler)
285        {0x00C806}, // Fn4 (R - Open Rear Coupler)
286
287        // TMCC1TR Remote - Defined KeyPad FnKeys
288        {0x00C811}, {0x00C812}, {0x00C813}, /* Fn5-7 */ // 1-2-3
289        {0x00C814}, {0x00C815}, {0x00C816}, /* Fn8-10 */ // 4-5-6
290        {0x00C817}, {0x00C818}, {0x00C819}, /* Fn11-13 */ // 7-8-9
291                    {0x00C810},             /* Fn14 */ // 0
292
293        // TMCC1TR Remote - Defined FnKeys
294        {0x00C809}, // Fn15 (Aux1)
295        {0x00C81E}, // Fn16 (Letoff Sound)
296        {0x00C804}, // Fn17 (Boost)
297        {0x00C807}, // Fn18 (Brake)
298        {0x00C828}, // Fn19 (Momentum Low)
299        {0x00C829}, // Fn20 (Momentum Medium)
300        {0x00C82A}, // Fn21 (Momentum High)
301        {0x00C82B}, // Fn22 (Set)
302        {0x00C81F}, // Fn23 (Horn 2)
303
304        // TMCC1TR RR Speed FnKeys
305        {0x00C864}, // Fn24 ( 4)   5mph
306        {0x00C86A}, // Fn25 (10)  20mph
307        {0x00C86E}, // Fn26 (14)  35mph
308        {0x00C872}, // Fn27 (18)  50mph
309        {0x00C878}, // Fn28 (24)  70mph
310        {0x00C87F}, // Fn29 (31)   Full
311
312        // TMCC1TR ERR - Set SpeedSteps
313        {0x00C809, 0x00C810, 0x00C809, 0x00C810, 0x00C804}, // Fn30 (Set ERR 100 SpeedSteps)
314        {0x00C809, 0x00C810, 0x00C809, 0x00C810, 0x00C807}, // Fn31 (Set ERR  32 SpeedSteps)
315
316        // TMCC1TR Acela/Subway FnKeys
317        {0x00C809, 0x00C805}, // Fn32 (Open Doors - Left)
318        {0x00C80D, 0x00C805, 0x00C80D}, // Fn33 (Close Doors - Left)
319        {0x00C809, 0x00C806}, // Fn34 (Open Doors - Right)
320        {0x00C80D, 0x00C806, 0x00C80D}, // Fn35 (Close Doors - Right)
321        {0x00C809, 0x00C813}, // Fn36 (Pantagraph - Automatic/Prototypical)
322        {0x00C809, 0x00C815}, // Fn37 (Pantagraph - Down)
323        {0x00C809, 0x00C816}, // Fn38 (Pantagraph - Manual Mode/Cycles Through Positions)
324        {0x00C809, 0x00C81C}, // Fn39 (Toggle Horn - City/Country)
325        {0x00C809, 0x00C818}, // Fn40 (Cab Light - Off)
326        {0x00C809, 0x00C819}, // Fn41 (Cab Light - On)
327        {0x00C809, 0x00C80D, 0x00C818, 0x00C80D}, // Fn42 (Interior Lights - Off)
328        {0x00C809, 0x00C80D, 0x00C819, 0x00C80D}, // Fn43 (Interior Lights - On)
329
330        // TMCC1TR Break-Down B Unit
331        {0x00C809, 0x00C804}, // Fn44 Start Breakdown Sequence
332        {0x00C809, 0x00C815}, // Fn45 Made It Back to the Yard
333        {0x00C809, 0x00C813}, // Fn46 Restart Unit/Repairs Complete
334
335        // TMCC1TR Boxcar/LiveStock Car
336        {0x00C809, 0x00C813}, // Fn47 Load
337        {0x00C809, 0x00C812}, // Fn48 Flat Wheel Sound
338
339        // TMCC1TR Passenger/Dining Cars
340        {0x00C809, 0x00C817}, // Fn49 Station PA Arrival Dialog
341        {0x00C809, 0x00C812}, // Fn50 Conductor Arrival Dialog
342
343        // TMCC1TR Crane/Boom Car
344        {0x00C809, 0x00C811, 0x00C807}, // Fn51 Lower the Boom
345        {0x00C809, 0x00C811, 0x00C804}, // Fn52 Raises the Boom
346        {0x00C809, 0x00C812, 0x00C807}, // Fn53 Lowers Main/Large Hook
347        {0x00C809, 0x00C812, 0x00C804}, // Fn54 Raises Main/Large Hook
348        {0x00C817, 0x00C813, 0x00C807}, // Fn55 Lowers Small Hook
349        {0x00C817, 0x00C813, 0x00C804}, // Fn56 Raises Small Hook
350        {0x00C804, 0x00C814}, // Fn57 Front Work Lights (Toggles On/Off)
351        {0x00C804, 0x00C815}, // Fn58 Rear Work Lights (Toggles On/Off)
352        {0x00C804, 0x00C816}, // Fn59 Launches Outriggers
353        {0x00C809, 0x00C817}, // Fn60 Crew Dialog Off
354        {0x00C809, 0x00C818}, // Fn61 All Sounds Off
355        {0x00C809, 0x00C819}, // Fn62 All Sounds On
356
357        // TMCC1TR Unassigned FnKeys
358        {0x00C82E}, // Fn63 Code to Trigger SerialMonFrame Message/Unassigned FnKey
359        {0x00C82E}, // Fn64 Code to Trigger SerialMonFrame Message/Unassigned FnKey
360        {0x00C82E}, // Fn65 Code to Trigger SerialMonFrame Message/Unassigned FnKey
361        {0x00C82E}, // Fn66 Code to Trigger SerialMonFrame Message/Unassigned FnKey
362        {0x00C82E}, // Fn67 Code to Trigger SerialMonFrame Message/Unassigned FnKey
363        {0x00C82E}, // Fn68 Code to Trigger SerialMonFrame Message/Unassigned FnKey
364
365        // TMCC1TR Aux FnKeys
366        {0x00C808}, // Fnxx (Aux1 Off)
367        {0x00C809}, // Fnxx (Aux1 Option 1 - On While Held)
368        {0x00C80A}, // Fnxx (Aux1 Option 2 - Toggle On/Toggle Off)
369        {0x00C80B}, // Fnxx (Aux1 On)
370        {0x00C80C}, // Fnxx (Aux2 Off)
371        {0x00C80D}, // Fnxx (Aux2 Option 1 - Toggle On/Toggle Off)
372        {0x00C80E}, // Fnxx (Aux2 Option 2 - On While Held)
373        {0x00C80F}, // Fnxx (Aux2 On)
374
375    };
376
377
378    /**
379    * Translate TMCC1 function numbers to line characters.
380    * If the upper byte is zero, it will be replaced by 0xF8
381    * and the address will be set in the low position.
382    * If the upper byte is non-zero, that value will be sent,
383    * and the address will be set in the upper (TMCC2) position.
384    * If six bytes are specified (with the upper one non-zero), 
385    * this will be interpreted as two commands to be sequentially sent,
386    * with the upper bytes sent first.
387    */
388
389    // TMCC 2 Legacy Function Keys to trigger with TMCC2_32 speed steps.
390    private final static long[][] SERIAL_FUNCTION_CODES_TMCC2_32 = new long[][] {
391
392        // TMCC2_32 Remote - Defined FnKeys
393        {0xF8010D}, // Fn0 (Headlamp)
394        {0xF8011D}, // Fn1 (Bell)
395        {0xF8011C}, // Fn2 (Horn/Whistle)
396        {0xF80105}, // Fn3 (F - Open Front Coupler)
397        {0xF80106}, // Fn4 (R - Open Rear Coupler)
398
399        // TMCC2_32 Remote - Defined KeyPad FnKeys
400        {0xF80111}, {0xF80112}, {0xF80113}, /* Fn5-7 */ // 1-2-3
401        {0xF80114}, {0xF80115}, {0xF80116}, /* Fn8-10 */ // 4-5-6
402        {0xF80117}, {0xF80118}, {0xF80119}, /* Fn11-13 */ // 7-8-9
403                    {0xF80110},             /* Fn14 */ // 0
404
405        // TMCC2_32 Remote - Defined FnKeys
406        {0xF80109}, // Fn15 (Aux1)
407        {0xF8011E}, // Fn16 (Letoff Sound)
408        {0xF80104}, // Fn17 (Boost)
409        {0xF80107}, // Fn18 (Brake)
410        {0xF80128}, // Fn19 (Momentum Low)
411        {0xF80129}, // Fn20 (Momentum Medium)
412        {0xF8012A}, // Fn21 (Momentum High)
413        {0xF8012B}, // Fn22 (Set)
414        {0xF8011F}, // Fn23 (Horn 2)
415
416        // TMCC2_32 RR Speed FnKeys
417        {0xF80164}, // Fn24 ( 4)   5mph
418        {0xF8016A}, // Fn25 (10)  20mph
419        {0xF8016E}, // Fn26 (14)  35mph
420        {0xF80172}, // Fn27 (18)  50mph
421        {0xF80178}, // Fn28 (24)  70mph
422        {0xF8017F}, // Fn29 (31)   Full
423
424        // TMCC2_32 Extended Lighting FnKeys
425        {0xF8017D, 0xFB00E8, 0xFB0000}, // Fn30 (Mars Lt On)
426        {0xF8017D, 0xFB00E9, 0xFB0000}, // Fn31 (Mars Lt Off)
427
428        {0xF8017D, 0xFB00D0, 0xFB0000}, // Fn32 (Ground Lt On)
429        {0xF8017D, 0xFB00D1, 0xFB0000}, // Fn33 (Ground Lt Off)
430        {0xF8017D, 0xFB00D2, 0xFB0000}, // Fn34 (Ground Lt Auto)
431
432        {0xF8017D, 0xFB00A0, 0xFB0000}, // Fn35 (DogHouse On)
433        {0xF8017D, 0xFB00A1, 0xFB0000}, // Fn36 (DogHouse Off)
434
435        {0xF8017D, 0xFB00CC, 0xFB0000}, // Fn37 (Tender Marker On)
436        {0xF8017D, 0xFB00CD, 0xFB0000}, // Fn38 (Tender Marker Off)
437
438        {0xF8017D, 0xFB00F4, 0xFB0000}, // Fn39 (Rule 17 On)
439        {0xF8017D, 0xFB00F5, 0xFB0000}, // Fn40 (Rule 17 Off)
440        {0xF8017D, 0xFB00F6, 0xFB0000}, // Fn41 (Rule 17 Auto)
441
442        {0xF8017D, 0xFB00C0, 0xFB0000}, // Fn42 (Ditch Lt On)
443        {0xF8017D, 0xFB00C1, 0xFB0000}, // Fn43 (Ditch Lt On; Pulse Off with Horn)
444        {0xF8017D, 0xFB00C2, 0xFB0000}, // Fn44 (Ditch Lt Off; Pulse On with Horn)
445        {0xF8017D, 0xFB00C3, 0xFB0000}, // Fn45 (Ditch Lt Off)
446
447        {0xF8017D, 0xFB00F0, 0xFB0000}, // Fn46 (Cab Lt On)
448        {0xF8017D, 0xFB00F1, 0xFB0000}, // Fn47 (Cab Lt Off)
449        {0xF8017D, 0xFB00F2, 0xFB0000}, // Fn48 (Cab Lt Auto)
450
451        {0xF8017D, 0xFB00C8, 0xFB0000}, // Fn49 (Loco Marker On)
452        {0xF8017D, 0xFB00C9, 0xFB0000}, // Fn50 (Loco Marker Off)
453
454        {0xF8017D, 0xFB00B0, 0xFB0000}, // Fn51 (Hazard Lt On)
455        {0xF8017D, 0xFB00B1, 0xFB0000}, // Fn52 (Hazard Lt Off)
456        {0xF8017D, 0xFB00B2, 0xFB0000}, // Fn53 (Hazard Lt Auto)
457
458        {0xF8017D, 0xFB00E0, 0xFB0000}, // Fn54 (Strobe Lt On - Single Flash)
459        {0xF8017D, 0xFB00E1, 0xFB0000}, // Fn55 (Strobe Lt On - Double Flash)
460        {0xF8017D, 0xFB00E2, 0xFB0000}, // Fn56 (Strobe Lt Off)
461
462        {0xF8017D, 0xFB00F8, 0xFB0000}, // Fn57 (Car Cabin Lt On)
463        {0xF8017D, 0xFB00F9, 0xFB0000}, // Fn58 (Car Cabin Lt Off)
464        {0xF8017D, 0xFB00FA, 0xFB0000}, // Fn59 (Car Cabin Lt Auto)
465
466        // TMCC2 Acela/Subway FnKeys
467        {0xF80109, 0xF80112}, // Fn60 (Crew: Report Speed - Moving)
468        {0xF80109, 0xF80115}, // Fn61 (Tower: Emergency Stop/Crew: Ack - Moving)
469        {0xF8017C, 0xFB0020, 0xFB0000}, // Fn62 (Open Doors - Left)
470        {0xF8017C, 0xFB0021, 0xFB0000}, // Fn63 (Close Doors - Left)
471        {0xF8017C, 0xFB0022, 0xFB0000}, // Fn64 (Open Doors - Right)
472        {0xF8017C, 0xFB0023, 0xFB0000}, // Fn65 (Close Doors - Right)
473        {0xF8017C, 0xFB0010, 0xFB0000}, // Fn66 (Pantagraph - Up/F)
474        {0xF8017C, 0xFB0011, 0xFB0000}, // Fn67 (Pantagraph - Down/F)
475        {0xF8017C, 0xFB0012, 0xFB0000}, // Fn68 (Pantagraph - Up/R)
476        {0xF8017C, 0xFB0013, 0xFB0000}, // Fn69 (Pantagraph - Down/R)
477        
478        // Only TMCC1 Break-Down B Unit
479
480        // TMCC2 Boxcar/Livestock Car
481        {0xF8017C, 0xFB0030, 0xFB0000}, // Fn70 (Option1 On)
482        {0xF8017C, 0xFB0031, 0xFB0000}, // Fn71 (Opiton1 Off)
483        {0xF8017C, 0xFB0032, 0xFB0000}, // Fn72 (Option2 On)
484        {0xF8017C, 0xFB0033, 0xFB0000}, // Fn73 (Option2 Off)
485        {0xF8017C, 0xFB0034, 0xFB0000}, // Fn74 (Load)
486        {0xF8017C, 0xFB0035, 0xFB0000}, // Fn75 (Unload)
487        {0xF8017C, 0xFB0036, 0xFB0000}, // Fn76 (FRED On)
488        {0xF8017C, 0xFB0037, 0xFB0000}, // Fn77 (FRED Off)
489        {0xF8017C, 0xFB0038, 0xFB0000}, // Fn78 (Flat Wheel On)
490        {0xF8017C, 0xFB0039, 0xFB0000}, // Fn79 (Flat Wheel Off)
491        {0xF8017C, 0xFB003A, 0xFB0000}, // Fn80 (Game On)
492        {0xF8017C, 0xFB003B, 0xFB0000}, // Fn81 (Game Off)
493
494        // Only TMCC1 Passenger/Dining Cars
495
496        // Only TMCC1 Crane/Boom Car
497
498        // TMCC2 Smoke System
499        {0xF8017C, 0xFB0000, 0xFB0000}, // Fn82 (Smoke System Off)
500        {0xF8017C, 0xFB0001, 0xFB0000}, // Fn83 (Smoke System Low)
501        {0xF8017C, 0xFB0002, 0xFB0000}, // Fn84 (Smoke System Med)
502        {0xF8017C, 0xFB0003, 0xFB0000}, // Fn85 (Smoke System High)
503
504        // TMCC2_32 Unassigned FnKeys
505        {0xF8012E}, // Fnxx Code to Trigger SerialMonFrame Message/Unassigned FnKey
506        {0xF8012E}, // Fnxx Code to Trigger SerialMonFrame Message/Unassigned FnKey
507
508        // TMCC2_32 Aux FnKeys
509        {0xF80108}, // Fnxx (Aux1 Off)
510        {0xF80109}, // Fnxx (Aux1 Option 1 - On While Held) 
511        {0xF8010A}, // Fnxx (Aux1 Option 2 - Toggle On/Toggle Off)
512        {0xF8010B}, // Fnxx (Aux1 On)
513        {0xF8010C}, // Fnxx (Aux2 Off)
514        {0xF8010D}, // Fnxx (Aux2 Option 1 - Toggle On/Toggle Off) 
515        {0xF8010E}, // Fnxx (Aux2 Option 2 - On While Held)
516        {0xF8010F}, // Fnxx (Aux2 On)
517
518};
519
520    // TMCC 2 Legacy TR Function Keys to trigger with TMCC2TR_32 speed steps.
521    private final static long[][] SERIAL_FUNCTION_CODES_TMCC2TR_32 = new long[][] {
522
523        // TMCC2TR_32 Remote - Defined FnKeys
524        {0xF9010D}, // Fn0 (Headlamp)
525        {0xF9011D}, // Fn1 (Bell)
526        {0xF9011C}, // Fn2 (Horn/Whistle)
527        {0xF90105}, // Fn3 (F - Open Front Coupler)
528        {0xF90106}, // Fn4 (R - Open Rear Coupler)
529
530        // TMCC2TR_32 Remote - Defined KeyPad FnKeys
531        {0xF90111}, {0xF90112}, {0xF90113}, /* Fn5-7 */ // 1-2-3
532        {0xF90114}, {0xF90115}, {0xF90116}, /* Fn8-10 */ // 4-5-6
533        {0xF90117}, {0xF90118}, {0xF90119}, /* Fn11-13 */ // 7-8-9
534                    {0xF90110},             /* Fn14 */ // 0
535
536        // TMCC2TR_32 Remote - Defined FnKeys
537        {0xF90109}, // Fn15 (Aux1)
538        {0xF9011E}, // Fn16 (Letoff Sound)
539        {0xF90104}, // Fn17 (Boost)
540        {0xF90107}, // Fn18 (Brake)
541        {0xF90128}, // Fn19 (Momentum Low)
542        {0xF90129}, // Fn20 (Momentum Medium)
543        {0xF9012A}, // Fn21 (Momentum High)
544        {0xF9012B}, // Fn22 (Set)
545        {0xF9011F}, // Fn23 (Horn 2)
546
547        // TMCC2TR_32 RR Speed FnKeys
548        {0xF90164}, // Fn24 ( 4)   5mph
549        {0xF9016A}, // Fn25 (10)  20mph
550        {0xF9016E}, // Fn26 (14)  35mph
551        {0xF90172}, // Fn27 (18)  50mph
552        {0xF90178}, // Fn28 (24)  70mph
553        {0xF9017F}, // Fn29 (31)   Full
554
555        // TMCC2TR_32 Extended Lighting FnKeys
556        {0xF9017D, 0xFB00E8, 0xFB0000}, // Fn30 (Mars Lt On)
557        {0xF9017D, 0xFB00E9, 0xFB0000}, // Fn31 (Mars Lt Off)
558
559        {0xF9017D, 0xFB00D0, 0xFB0000}, // Fn32 (Ground Lt On)
560        {0xF9017D, 0xFB00D1, 0xFB0000}, // Fn33 (Ground Lt Off)
561        {0xF9017D, 0xFB00D2, 0xFB0000}, // Fn34 (Ground Lt Auto)
562
563        {0xF9017D, 0xFB00A0, 0xFB0000}, // Fn35 (DogHouse On)
564        {0xF9017D, 0xFB00A1, 0xFB0000}, // Fn36 (DogHouse Off)
565
566        {0xF9017D, 0xFB00CC, 0xFB0000}, // Fn37 (Tender Marker On)
567        {0xF9017D, 0xFB00CD, 0xFB0000}, // Fn38 (Tender Marker Off)
568
569        {0xF9017D, 0xFB00F4, 0xFB0000}, // Fn39 (Rule 17 On)
570        {0xF9017D, 0xFB00F5, 0xFB0000}, // Fn40 (Rule 17 Off)
571        {0xF9017D, 0xFB00F6, 0xFB0000}, // Fn41 (Rule 17 Auto)
572
573        {0xF9017D, 0xFB00C0, 0xFB0000}, // Fn42 (Ditch Lt On)
574        {0xF9017D, 0xFB00C1, 0xFB0000}, // Fn43 (Ditch Lt On; Pulse Off with Horn)
575        {0xF9017D, 0xFB00C2, 0xFB0000}, // Fn44 (Ditch Lt Off; Pulse On with Horn)
576        {0xF9017D, 0xFB00C3, 0xFB0000}, // Fn45 (Ditch Lt Off)
577
578        {0xF9017D, 0xFB00F0, 0xFB0000}, // Fn46 (Cab Lt On)
579        {0xF9017D, 0xFB00F1, 0xFB0000}, // Fn47 (Cab Lt Off)
580        {0xF9017D, 0xFB00F2, 0xFB0000}, // Fn48 (Cab Lt Auto)
581
582        {0xF9017D, 0xFB00C8, 0xFB0000}, // Fn49 (Loco Marker On)
583        {0xF9017D, 0xFB00C9, 0xFB0000}, // Fn50 (Loco Marker Off)
584
585        {0xF9017D, 0xFB00B0, 0xFB0000}, // Fn51 (Hazard Lt On)
586        {0xF9017D, 0xFB00B1, 0xFB0000}, // Fn52 (Hazard Lt Off)
587        {0xF9017D, 0xFB00B2, 0xFB0000}, // Fn53 (Hazard Lt Auto)
588
589        {0xF9017D, 0xFB00E0, 0xFB0000}, // Fn54 (Strobe Lt On - Single Flash)
590        {0xF9017D, 0xFB00E1, 0xFB0000}, // Fn55 (Strobe Lt On - Double Flash)
591        {0xF9017D, 0xFB00E2, 0xFB0000}, // Fn56 (Strobe Lt Off)
592
593        {0xF9017D, 0xFB00F8, 0xFB0000}, // Fn57 (Car Cabin Lt On)
594        {0xF9017D, 0xFB00F9, 0xFB0000}, // Fn58 (Car Cabin Lt Off)
595        {0xF9017D, 0xFB00FA, 0xFB0000}, // Fn59 (Car Cabin Lt Auto)
596
597        // TMCC2TR Acela/Subway FnKeys
598        {0xF90109, 0xF90112}, // Fn60 (Crew: Report Speed - Moving)
599        {0xF90109, 0xF90115}, // Fn61 (Tower: Emergency Stop/Crew: Ack - Moving)
600        {0xF9017C, 0xFB0020, 0xFB0000}, // Fn62 (Open Doors - Left)
601        {0xF9017C, 0xFB0021, 0xFB0000}, // Fn63 (Close Doors - Left)
602        {0xF9017C, 0xFB0022, 0xFB0000}, // Fn64 (Open Doors - Right)
603        {0xF9017C, 0xFB0023, 0xFB0000}, // Fn65 (Close Doors - Right)
604        {0xF9017C, 0xFB0010, 0xFB0000}, // Fn66 (Pantagraph - Up/F)
605        {0xF9017C, 0xFB0011, 0xFB0000}, // Fn67 (Pantagraph - Down/F)
606        {0xF9017C, 0xFB0012, 0xFB0000}, // Fn68 (Pantagraph - Up/R)
607        {0xF9017C, 0xFB0013, 0xFB0000}, // Fn69 (Pantagraph - Down/R)
608        
609        // Only TMCC1 Break-Down B Unit
610
611        // TMCC2TR Boxcar/Livestock Car
612        {0xF9017C, 0xFB0030, 0xFB0000}, // Fn70 (Option1 On)
613        {0xF9017C, 0xFB0031, 0xFB0000}, // Fn71 (Opiton1 Off)
614        {0xF9017C, 0xFB0032, 0xFB0000}, // Fn72 (Option2 On)
615        {0xF9017C, 0xFB0033, 0xFB0000}, // Fn73 (Option2 Off)
616        {0xF9017C, 0xFB0034, 0xFB0000}, // Fn74 (Load)
617        {0xF9017C, 0xFB0035, 0xFB0000}, // Fn75 (Unload)
618        {0xF9017C, 0xFB0036, 0xFB0000}, // Fn76 (FRED On)
619        {0xF9017C, 0xFB0037, 0xFB0000}, // Fn77 (FRED Off)
620        {0xF9017C, 0xFB0038, 0xFB0000}, // Fn78 (Flat Wheel On)
621        {0xF9017C, 0xFB0039, 0xFB0000}, // Fn79 (Flat Wheel Off)
622        {0xF9017C, 0xFB003A, 0xFB0000}, // Fn80 (Game On)
623        {0xF9017C, 0xFB003B, 0xFB0000}, // Fn81 (Game Off)
624
625        // Only TMCC1 Passenger/Dining Cars
626
627        // Only TMCC1 Crane/Boom Car
628
629        // TMCC2TR Smoke System
630        {0xF9017C, 0xFB0000, 0xFB0000}, // Fn82 (Smoke System Off)
631        {0xF9017C, 0xFB0001, 0xFB0000}, // Fn83 (Smoke System Low)
632        {0xF9017C, 0xFB0002, 0xFB0000}, // Fn84 (Smoke System Med)
633        {0xF9017C, 0xFB0003, 0xFB0000}, // Fn85 (Smoke System High)
634
635        // TRMCC2TR_32 Unassigned FnKeys
636        {0xF9012E}, // Fnxx Code to Trigger SerialMonFrame Message/Unassigned FnKey
637        {0xF9012E}, // Fnxx Code to Trigger SerialMonFrame Message/Unassigned FnKey
638
639        // TRMCC2TR_32 Aux FnKeys
640        {0xF90108}, // Fnxx (Aux1 Off)
641        {0xF90109}, // Fnxx (Aux1 Option 1 - On While Held) 
642        {0xF9010A}, // Fnxx (Aux1 Option 2 - Toggle On/Toggle Off)
643        {0xF9010B}, // Fnxx (Aux1 On)
644        {0xF9010C}, // Fnxx (Aux2 Off)
645        {0xF9010D}, // Fnxx (Aux2 Option 1 - Toggle On/Toggle Off) 
646        {0xF9010E}, // Fnxx (Aux2 Option 2 - On While Held)
647        {0xF9010F}, // Fnxx (Aux2 On)
648
649};
650
651    // TMCC 2 Legacy Function Keys to trigger with TMCC2_200 speed steps.
652    private final static long[][] SERIAL_FUNCTION_CODES_TMCC2_200 = new long[][] {
653
654        // TMCC2_200 Remote - Defined FnKeys
655        {0xF8010D}, // Fn0 (Headlamp)
656        {0xF8011D}, // Fn1 (Bell)
657        {0xF8011C}, // Fn2 (Horn/Whistle)
658        {0xF80105}, // Fn3 (F - Open Front Coupler)
659        {0xF80106}, // Fn4 (R - Open Rear Coupler)
660
661        // TMCC2_200 Remote - Defined KeyPad FnKeys
662        {0xF80111}, {0xF80112}, {0xF80113}, /* Fn5-7 */ // 1-2-3
663        {0xF80114}, {0xF80115}, {0xF80116}, /* Fn8-10 */ // 4-5-6
664        {0xF80117}, {0xF80118}, {0xF80119}, /* Fn11-13 */ // 7-8-9
665                    {0xF80110},             /* Fn14 */ // 0
666
667        // TMCC2_200 Remote - Defined FnKeys
668        {0xF80109}, // Fn15 (Aux1)
669        {0xF8011E}, // Fn16 (Letoff Sound)
670        {0xF80104}, // Fn17 (Boost)
671        {0xF80107}, // Fn18 (Brake)
672        {0xF80128}, // Fn19 (Momentum Low)
673        {0xF80129}, // Fn20 (Momentum Medium)
674        {0xF8012A}, // Fn21 (Momentum High)
675        {0xF8012B}, // Fn22 (Set)
676        {0xF8011F}, // Fn23 (Horn 2)
677
678        // TMCC2_200 RR Speed FnKeys
679        {0xF8000A}, // Fn24 ( 10)   5mph
680        {0xF80028}, // Fn25 ( 40)  20mph
681        {0xF80046}, // Fn26 ( 70)  35mph
682        {0xF80064}, // Fn27 (100)  50mph
683        {0xF8008C}, // Fn28 (140)  70mph
684        {0xF800C7}, // Fn29 (199)   Full
685
686        // TMCC2_200 Extended Lighting FnKeys
687        {0xF8017D, 0xFB00E8, 0xFB0000}, // Fn30 (Mars Lt On)
688        {0xF8017D, 0xFB00E9, 0xFB0000}, // Fn31 (Mars Lt Off)
689
690        {0xF8017D, 0xFB00D0, 0xFB0000}, // Fn32 (Ground Lt On)
691        {0xF8017D, 0xFB00D1, 0xFB0000}, // Fn33 (Ground Lt Off)
692        {0xF8017D, 0xFB00D2, 0xFB0000}, // Fn34 (Ground Lt Auto)
693
694        {0xF8017D, 0xFB00A0, 0xFB0000}, // Fn35 (DogHouse On)
695        {0xF8017D, 0xFB00A1, 0xFB0000}, // Fn36 (DogHouse Off)
696
697        {0xF8017D, 0xFB00CC, 0xFB0000}, // Fn37 (Tender Marker On)
698        {0xF8017D, 0xFB00CD, 0xFB0000}, // Fn38 (Tender Marker Off)
699
700        {0xF8017D, 0xFB00F4, 0xFB0000}, // Fn39 (Rule 17 On)
701        {0xF8017D, 0xFB00F5, 0xFB0000}, // Fn40 (Rule 17 Off)
702        {0xF8017D, 0xFB00F6, 0xFB0000}, // Fn41 (Rule 17 Auto)
703
704        {0xF8017D, 0xFB00C0, 0xFB0000}, // Fn42 (Ditch Lt On)
705        {0xF8017D, 0xFB00C1, 0xFB0000}, // Fn43 (Ditch Lt On; Pulse Off with Horn)
706        {0xF8017D, 0xFB00C2, 0xFB0000}, // Fn44 (Ditch Lt Off; Pulse On with Horn)
707        {0xF8017D, 0xFB00C3, 0xFB0000}, // Fn45 (Ditch Lt Off)
708
709        {0xF8017D, 0xFB00F0, 0xFB0000}, // Fn46 (Cab Lt On)
710        {0xF8017D, 0xFB00F1, 0xFB0000}, // Fn47 (Cab Lt Off)
711        {0xF8017D, 0xFB00F2, 0xFB0000}, // Fn48 (Cab Lt Auto)
712
713        {0xF8017D, 0xFB00C8, 0xFB0000}, // Fn49 (Loco Marker On)
714        {0xF8017D, 0xFB00C9, 0xFB0000}, // Fn50 (Loco Marker Off)
715
716        {0xF8017D, 0xFB00B0, 0xFB0000}, // Fn51 (Hazard Lt On)
717        {0xF8017D, 0xFB00B1, 0xFB0000}, // Fn52 (Hazard Lt Off)
718        {0xF8017D, 0xFB00B2, 0xFB0000}, // Fn53 (Hazard Lt Auto)
719
720        {0xF8017D, 0xFB00E0, 0xFB0000}, // Fn54 (Strobe Lt On - SingleFlash)
721        {0xF8017D, 0xFB00E1, 0xFB0000}, // Fn55 (Strobe Lt On - DoubleFlash)
722        {0xF8017D, 0xFB00E2, 0xFB0000}, // Fn56 (Strobe Lt Off)
723
724        {0xF8017D, 0xFB00F8, 0xFB0000}, // Fn57 (Car Cabin Lt On)
725        {0xF8017D, 0xFB00F9, 0xFB0000}, // Fn58 (Car Cabin Lt Off)
726        {0xF8017D, 0xFB00FA, 0xFB0000}, // Fn59 (Car Cabin Lt Auto)
727
728        // TMCC2 Acela/Subway FnKeys
729        {0xF80109, 0xF80112}, // Fn60 (Crew: Report Speed - Moving)
730        {0xF80109, 0xF80115}, // Fn61 (Tower: Emergency Stop/Crew: Ack - Moving)
731        {0xF8017C, 0xFB0020, 0xFB0000}, // Fn62 (Open Doors - Left)
732        {0xF8017C, 0xFB0021, 0xFB0000}, // Fn63 (Close Doors - Left)
733        {0xF8017C, 0xFB0022, 0xFB0000}, // Fn64 (Open Doors - Right)
734        {0xF8017C, 0xFB0023, 0xFB0000}, // Fn65 (Close Doors - Right)
735        {0xF8017C, 0xFB0010, 0xFB0000}, // Fn66 (Pantagraph - Up/F)
736        {0xF8017C, 0xFB0011, 0xFB0000}, // Fn67 (Pantagraph - Down/F)
737        {0xF8017C, 0xFB0012, 0xFB0000}, // Fn68 (Pantagraph - Up/R)
738        {0xF8017C, 0xFB0013, 0xFB0000}, // Fn69 (Pantagraph - Down/R)
739
740        // Only TMCC1 Break-Down B Unit
741
742        // TMCC2 Boxcar/Livestock Car
743        {0xF8017C, 0xFB0030, 0xFB0000}, // Fn70 (Option1 On)
744        {0xF8017C, 0xFB0031, 0xFB0000}, // Fn71 (Opiton1 Off)
745        {0xF8017C, 0xFB0032, 0xFB0000}, // Fn72 (Option2 On)
746        {0xF8017C, 0xFB0033, 0xFB0000}, // Fn73 (Option2 Off)
747        {0xF8017C, 0xFB0034, 0xFB0000}, // Fn74 (Load)
748        {0xF8017C, 0xFB0035, 0xFB0000}, // Fn75 (Unload)
749        {0xF8017C, 0xFB0036, 0xFB0000}, // Fn76 (FRED On)
750        {0xF8017C, 0xFB0037, 0xFB0000}, // Fn77 (FRED Off)
751        {0xF8017C, 0xFB0038, 0xFB0000}, // Fn78 (Flat Wheel On)
752        {0xF8017C, 0xFB0039, 0xFB0000}, // Fn79 (Flat Wheel Off)
753        {0xF8017C, 0xFB003A, 0xFB0000}, // Fn80 (Game On)
754        {0xF8017C, 0xFB003B, 0xFB0000}, // Fn81 (Game Off)
755
756        // Only TMCC1 Passenger/Dining Cars
757
758        // Only TMCC1 Crane/Boom Car
759
760        // TMCC2 Smoke System
761        {0xF8017C, 0xFB0000, 0xFB0000}, // Fn82 (Smoke System Off)
762        {0xF8017C, 0xFB0001, 0xFB0000}, // Fn83 (Smoke System Low)
763        {0xF8017C, 0xFB0002, 0xFB0000}, // Fn84 (Smoke System Med)
764        {0xF8017C, 0xFB0003, 0xFB0000}, // Fn85 (Smoke System High)
765
766        // TRMCC2_200 Unassigned FnKeys
767        {0xF8012E}, // Fnxx Code to Trigger SerialMonFrame Message/Unassigned FnKey
768        {0xF8012E}, // Fnxx Code to Trigger SerialMonFrame Message/Unassigned FnKey
769
770        // TMCC2_200 Aux FnKeys
771        {0xF80108}, // Fnxx (Aux1 Off)
772        {0xF80109}, // Fnxx (Aux1 Option 1 - On While Held) 
773        {0xF8010A}, // Fnxx (Aux1 Option 2 - Toggle On/Toggle Off)
774        {0xF8010B}, // Fnxx (Aux1 On)
775        {0xF8010C}, // Fnxx (Aux2 Off)
776        {0xF8010D}, // Fnxx (Aux2 Option 1 - Toggle On/Toggle Off) 
777        {0xF8010E}, // Fnxx (Aux2 Option 2 - On While Held)
778        {0xF8010F}, // Fnxx (Aux2 On)
779
780    };
781
782    // TMCC 2 Legacy TR Function Keys to trigger with TMCC2TR_200 speed steps.
783    private final static long[][] SERIAL_FUNCTION_CODES_TMCC2TR_200 = new long[][] {
784
785        // TMCC2TR_200 Remote - Defined FnKeys
786        {0xF9010D}, // Fn0 (Headlamp)
787        {0xF9011D}, // Fn1 (Bell)
788        {0xF9011C}, // Fn2 (Horn/Whistle)
789        {0xF90105}, // Fn3 (F - Open Front Coupler)
790        {0xF90106}, // Fn4 (R - Open Rear Coupler)
791
792        // TMCC2TR_200 Remote - Defined KeyPad FnKeys
793        {0xF90111}, {0xF90112}, {0xF90113}, /* Fn5-7 */ // 1-2-3
794        {0xF90114}, {0xF90115}, {0xF90116}, /* Fn8-10 */ // 4-5-6
795        {0xF90117}, {0xF90118}, {0xF90119}, /* Fn11-13 */ // 7-8-9
796                    {0xF90110},             /* Fn14 */ // 0
797
798        // TMCC2TR_200 Remote - Defined FnKeys
799        {0xF90109}, // Fn15 (Aux1)
800        {0xF9011E}, // Fn16 (Letoff Sound)
801        {0xF90104}, // Fn17 (Boost)
802        {0xF90107}, // Fn18 (Brake)
803        {0xF90128}, // Fn19 (Momentum Low)
804        {0xF90129}, // Fn20 (Momentum Medium)
805        {0xF9012A}, // Fn21 (Momentum High)
806        {0xF9012B}, // Fn22 (Set)
807        {0xF9011F}, // Fn23 (Horn 2)
808
809        // TMCC2TR_200 RR Speed FnKeys
810        {0xF9000A}, // Fn24 ( 10)   5mph
811        {0xF90028}, // Fn25 ( 40)  20mph
812        {0xF90046}, // Fn26 ( 70)  35mph
813        {0xF90064}, // Fn27 (100)  50mph
814        {0xF9008C}, // Fn28 (140)  70mph
815        {0xF900C7}, // Fn29 (199)   Full
816
817        // TMCC2TR_200 Extended Lighting FnKeys
818        {0xF9017D, 0xFB00E8, 0xFB0000}, // Fn30 (Mars Lt On)
819        {0xF9017D, 0xFB00E9, 0xFB0000}, // Fn31 (Mars Lt Off)
820
821        {0xF9017D, 0xFB00D0, 0xFB0000}, // Fn32 (Ground Lt On)
822        {0xF9017D, 0xFB00D1, 0xFB0000}, // Fn33 (Ground Lt Off)
823        {0xF9017D, 0xFB00D2, 0xFB0000}, // Fn34 (Ground Lt Auto)
824
825        {0xF9017D, 0xFB00A0, 0xFB0000}, // Fn35 (DogHouse On)
826        {0xF9017D, 0xFB00A1, 0xFB0000}, // Fn36 (DogHouse Off)
827
828        {0xF9017D, 0xFB00CC, 0xFB0000}, // Fn37 (Tender Marker On)
829        {0xF9017D, 0xFB00CD, 0xFB0000}, // Fn38 (Tender Marker Off)
830
831        {0xF9017D, 0xFB00F4, 0xFB0000}, // Fn39 (Rule 17 On)
832        {0xF9017D, 0xFB00F5, 0xFB0000}, // Fn40 (Rule 17 Off)
833        {0xF9017D, 0xFB00F6, 0xFB0000}, // Fn41 (Rule 17 Auto)
834
835        {0xF9017D, 0xFB00C0, 0xFB0000}, // Fn42 (Ditch Lt On)
836        {0xF9017D, 0xFB00C1, 0xFB0000}, // Fn43 (Ditch Lt On; Pulse Off with Horn)
837        {0xF9017D, 0xFB00C2, 0xFB0000}, // Fn44 (Ditch Lt Off; Pulse On with Horn)
838        {0xF9017D, 0xFB00C3, 0xFB0000}, // Fn45 (Ditch Lt Off)
839
840        {0xF9017D, 0xFB00F0, 0xFB0000}, // Fn46 (Cab Lt On)
841        {0xF9017D, 0xFB00F1, 0xFB0000}, // Fn47 (Cab Lt Off)
842        {0xF9017D, 0xFB00F2, 0xFB0000}, // Fn48 (Cab Lt Auto)
843
844        {0xF9017D, 0xFB00C8, 0xFB0000}, // Fn49 (Loco Marker On)
845        {0xF9017D, 0xFB00C9, 0xFB0000}, // Fn50 (Loco Marker Off)
846
847        {0xF9017D, 0xFB00B0, 0xFB0000}, // Fn51 (Hazard Lt On)
848        {0xF9017D, 0xFB00B1, 0xFB0000}, // Fn52 (Hazard Lt Off)
849        {0xF9017D, 0xFB00B2, 0xFB0000}, // Fn53 (Hazard Lt Auto)
850
851        {0xF9017D, 0xFB00E0, 0xFB0000}, // Fn54 (Strobe Lt On - SingleFlash)
852        {0xF9017D, 0xFB00E1, 0xFB0000}, // Fn55 (Strobe Lt On - DoubleFlash)
853        {0xF9017D, 0xFB00E2, 0xFB0000}, // Fn56 (Strobe Lt Off)
854
855        {0xF9017D, 0xFB00F8, 0xFB0000}, // Fn57 (Car Cabin Lt On)
856        {0xF9017D, 0xFB00F9, 0xFB0000}, // Fn58 (Car Cabin Lt Off)
857        {0xF9017D, 0xFB00FA, 0xFB0000}, // Fn59 (Car Cabin Lt Auto)
858
859        // TMCC2TR Acela/Subway FnKeys
860        {0xF90109, 0xF90112}, // Fn60 (Crew: Report Speed - Moving)
861        {0xF90109, 0xF90115}, // Fn61 (Tower: Emergency Stop/Crew: Ack - Moving)
862        {0xF9017C, 0xFB0020, 0xFB0000}, // Fn62 (Open Doors - Left)
863        {0xF9017C, 0xFB0021, 0xFB0000}, // Fn63 (Close Doors - Left)
864        {0xF9017C, 0xFB0022, 0xFB0000}, // Fn64 (Open Doors - Right)
865        {0xF9017C, 0xFB0023, 0xFB0000}, // Fn65 (Close Doors - Right)
866        {0xF9017C, 0xFB0010, 0xFB0000}, // Fn66 (Pantagraph - Up/F)
867        {0xF9017C, 0xFB0011, 0xFB0000}, // Fn67 (Pantagraph - Down/F)
868        {0xF9017C, 0xFB0012, 0xFB0000}, // Fn68 (Pantagraph - Up/R)
869        {0xF9017C, 0xFB0013, 0xFB0000}, // Fn69 (Pantagraph - Down/R)
870
871        // Only TMCC1 Break-Down B Unit
872
873        // TMCC2TR Boxcar/Livestock Car
874        {0xF9017C, 0xFB0030, 0xFB0000}, // Fn70 (Option1 On)
875        {0xF9017C, 0xFB0031, 0xFB0000}, // Fn71 (Opiton1 Off)
876        {0xF9017C, 0xFB0032, 0xFB0000}, // Fn72 (Option2 On)
877        {0xF9017C, 0xFB0033, 0xFB0000}, // Fn73 (Option2 Off)
878        {0xF9017C, 0xFB0034, 0xFB0000}, // Fn74 (Load)
879        {0xF9017C, 0xFB0035, 0xFB0000}, // Fn75 (Unload)
880        {0xF9017C, 0xFB0036, 0xFB0000}, // Fn76 (FRED On)
881        {0xF9017C, 0xFB0037, 0xFB0000}, // Fn77 (FRED Off)
882        {0xF9017C, 0xFB0038, 0xFB0000}, // Fn78 (Flat Wheel On)
883        {0xF9017C, 0xFB0039, 0xFB0000}, // Fn79 (Flat Wheel Off)
884        {0xF9017C, 0xFB003A, 0xFB0000}, // Fn80 (Game On)
885        {0xF9017C, 0xFB003B, 0xFB0000}, // Fn81 (Game Off)
886
887        // Only TMCC1 Passenger/Dining Cars
888
889        // Only TMCC1 Crane/Boom Car
890
891        // TMCC2TR Smoke System
892        {0xF9017C, 0xFB0000, 0xFB0000}, // Fn82 (Smoke System Off)
893        {0xF9017C, 0xFB0001, 0xFB0000}, // Fn83 (Smoke System Low)
894        {0xF9017C, 0xFB0002, 0xFB0000}, // Fn84 (Smoke System Med)
895        {0xF9017C, 0xFB0003, 0xFB0000}, // Fn85 (Smoke System High)
896
897        // TRMCC2TR_200 Unassigned FnKeys
898        {0xF9012E}, // Fnxx Code to Trigger SerialMonFrame Message/Unassigned FnKey
899        {0xF9012E}, // Fnxx Code to Trigger SerialMonFrame Message/Unassigned FnKey
900
901        // TMCC2TR_200 Aux FnKeys
902        {0xF90108}, // Fnxx (Aux1 Off)
903        {0xF90109}, // Fnxx (Aux1 Option 1 - On While Held) 
904        {0xF9010A}, // Fnxx (Aux1 Option 2 - Toggle On/Toggle Off)
905        {0xF9010B}, // Fnxx (Aux1 On)
906        {0xF9010C}, // Fnxx (Aux2 Off)
907        {0xF9010D}, // Fnxx (Aux2 Option 1 - Toggle On/Toggle Off) 
908        {0xF9010E}, // Fnxx (Aux2 Option 2 - On While Held)
909        {0xF9010F}, // Fnxx (Aux2 On)
910
911    };
912
913
914     int previousValue;
915     int newValue;
916
917    /**
918     * Set the speed.
919     *
920     * @param speed Number from 0 to 1; less than zero is emergency stop
921     */
922
923    @Override
924    public void setSpeedSetting(float speed) {
925        float oldSpeed;
926        synchronized(this) {
927            oldSpeed = this.speedSetting;
928            this.speedSetting = speed;
929        }
930        
931        // Option TMCC2_200 "Absolute" speed steps
932        if (speedStepMode == jmri.SpeedStepMode.TMCC2_200) {
933
934            // TMCC2 Legacy 200 speed step mode
935            int value = (int) (199 * speed); // max value to send is 199 in 200 step mode
936            if (value > 199) {
937                // max possible speed
938                value = 199;
939            }
940            SerialMessage m = new SerialMessage();
941            m.setOpCode(0xF8);
942    
943            if (value < 0) {
944                // System HALT (immediate stop; ALL)
945                m.putAsWord(0xFF8B);
946
947                // send to layout (send 4 times to ensure received)
948                tc.sendSerialMessage(m, null);
949                tc.sendSerialMessage(m, null);
950                tc.sendSerialMessage(m, null);
951                tc.sendSerialMessage(m, null);
952
953            } else {
954                // normal speed setting
955                m.putAsWord(0x0000 + (address.getNumber() << 9) + value);
956
957                // send to command station (send twice is set, but number of sends may need to be adjusted depending on efficiency)
958                tc.sendSerialMessage(m, null);
959                tc.sendSerialMessage(m, null);
960            }
961        }
962
963        // Option TMCC2TR_200 "Absolute" speed steps
964        if (speedStepMode == jmri.SpeedStepMode.TMCC2TR_200) {
965
966            // TMCC2 Legacy TR 200 speed step mode
967            int value = (int) (199 * speed); // max value to send is 199 in 200 step mode
968            if (value > 199) {
969                // max possible speed
970                value = 199;
971            }
972            SerialMessage m = new SerialMessage();
973            m.setOpCode(0xF9);
974    
975            if (value < 0) {
976                // System HALT (immediate stop; ALL)
977                m.putAsWord(0xFF8B);
978
979                // send to layout (send 4 times to ensure received)
980                tc.sendSerialMessage(m, null);
981                tc.sendSerialMessage(m, null);
982                tc.sendSerialMessage(m, null);
983                tc.sendSerialMessage(m, null);
984
985            } else {
986                // normal speed setting
987                m.putAsWord(0x0000 + (address.getNumber() << 9) + value);
988
989                // send to command station (send twice is set, but number of sends may need to be adjusted depending on efficiency)
990                tc.sendSerialMessage(m, null);
991                tc.sendSerialMessage(m, null);
992            }
993        }
994
995        // Option TMCC1_100 "Relative" speed steps
996        if (speedStepMode == jmri.SpeedStepMode.TMCC1_100) {
997            
998          /** 
999            * TMCC1 MedMomentum, HighMomentum and 100 speed step mode
1000            * purpose is to increase resolution of 32 bits
1001            * across 100 throttle 'clicks'
1002          */
1003
1004            int value = (int) (99 * speed); // max value to send is 99 in 100 step mode
1005            if (value > 99) {
1006                // max possible speed step
1007                value = 99;
1008            }
1009            SerialMessage m = new SerialMessage();
1010            m.setOpCode(0xFE);
1011
1012            if (value < 0) {
1013                // System HALT (immediate stop; ALL)
1014                m.putAsWord(0xFFFF);
1015
1016                // send to layout (send 4 times to ensure received)
1017                tc.sendSerialMessage(m, null);
1018                tc.sendSerialMessage(m, null);
1019                tc.sendSerialMessage(m, null);
1020                tc.sendSerialMessage(m, null);
1021            }
1022            if (value == 0) {
1023                // normal speed step setting
1024                m.putAsWord(0x0060 + address.getNumber() * 128 + value);
1025
1026                // send to layout (send twice is set, but number of sends may need to be adjusted depending on efficiency)
1027                tc.sendSerialMessage(m, null);
1028                tc.sendSerialMessage(m, null);
1029            }
1030
1031            if (value > 0) {
1032                 newValue = value;
1033                 if (newValue > previousValue) {
1034                    // increase TMCC "Relative" speed +1 (repeat * valueChange46)
1035                    int valueChange46 = (newValue - previousValue);
1036                    for (int i = 0x0000; i < valueChange46; i++) {
1037                        m.putAsWord(0x0046 + address.getNumber() * 128);
1038                        tc.sendSerialMessage(m, null);
1039                    }
1040                }
1041                if (newValue < previousValue) {
1042                    // decrease TMCC "Relative" speed -1 (repeat * valueChange44)
1043                    int valueChange44 = (previousValue - newValue);
1044                    for (int j = 0x0000; j < valueChange44; j++) {
1045                        m.putAsWord(0x0044 + address.getNumber() * 128);
1046                        tc.sendSerialMessage(m, null);
1047                    }
1048                }
1049            previousValue = newValue;                
1050            }
1051        }
1052
1053        // Option TMCC1TR_100 "Relative" speed steps
1054        if (speedStepMode == jmri.SpeedStepMode.TMCC1TR_100) {
1055            
1056          /** 
1057            * TMCC1TR MedMomentum, HighMomentum and 100 speed step mode
1058            * purpose is to increase resolution of 32 bits
1059            * across 100 throttle 'clicks'
1060          */
1061
1062            int value = (int) (99 * speed); // max value to send is 99 in 100 step mode
1063            if (value > 99) {
1064                // max possible speed step
1065                value = 99;
1066            }
1067            SerialMessage m = new SerialMessage();
1068            m.setOpCode(0xFE);
1069
1070            if (value < 0) {
1071                // System HALT (immediate stop; ALL)
1072                m.putAsWord(0xFFFF);
1073
1074                // send to layout (send 4 times to ensure received)
1075                tc.sendSerialMessage(m, null);
1076                tc.sendSerialMessage(m, null);
1077                tc.sendSerialMessage(m, null);
1078                tc.sendSerialMessage(m, null);
1079            }
1080            if (value == 0) {
1081                // normal speed step setting
1082                m.putAsWord(0xC860 + address.getNumber() * 128 + value);
1083
1084                // send to layout (send twice is set, but number of sends may need to be adjusted depending on efficiency)
1085                tc.sendSerialMessage(m, null);
1086                tc.sendSerialMessage(m, null);
1087            }
1088
1089            if (value > 0) {
1090                 newValue = value;
1091                 if (newValue > previousValue) {
1092                    // increase TMCC "Relative" speed +1 (repeat * valueChange46)
1093                    int valueChange46 = (newValue - previousValue);
1094                    for (int i = 0x0000; i < valueChange46; i++) {
1095                        m.putAsWord(0xC846 + address.getNumber() * 128);
1096                        tc.sendSerialMessage(m, null);
1097                    }
1098                }
1099                if (newValue < previousValue) {
1100                    // decrease TMCC "Relative" speed -1 (repeat * valueChange44)
1101                    int valueChange44 = (previousValue - newValue);
1102                    for (int j = 0x0000; j < valueChange44; j++) {
1103                        m.putAsWord(0xC844 + address.getNumber() * 128);
1104                        tc.sendSerialMessage(m, null);
1105                    }
1106                }
1107            previousValue = newValue;                
1108            }
1109        }
1110
1111        // Option TMCC2_32 "Absolute" speed steps
1112        if (speedStepMode == jmri.SpeedStepMode.TMCC2_32) {
1113
1114            // TMCC2 Legacy 32 speed step mode
1115            int value = (int) (32 * speed);
1116            if (value > 31) {
1117                // max possible speed
1118                value = 31;
1119            }
1120            SerialMessage m = new SerialMessage();
1121            m.setOpCode(0xF8);
1122    
1123            if (value < 0) {
1124                // System HALT (immediate stop; ALL)
1125                m.putAsWord(0xFF8B);
1126
1127                // send to layout (send 4 times to ensure received)
1128                tc.sendSerialMessage(m, null);
1129                tc.sendSerialMessage(m, null);
1130                tc.sendSerialMessage(m, null);
1131                tc.sendSerialMessage(m, null);
1132
1133            } else {
1134                // normal speed setting
1135                m.putAsWord(0x0160 + address.getNumber() * 512 + value);
1136
1137                // send to command station (send twice is set, but number of sends may need to be adjusted depending on efficiency)
1138                tc.sendSerialMessage(m, null);
1139                tc.sendSerialMessage(m, null);
1140            }
1141        }
1142
1143        // Option TMCC2TR_32 "Absolute" speed steps
1144        if (speedStepMode == jmri.SpeedStepMode.TMCC2TR_32) {
1145
1146            // TMCC2 Legacy TR 32 speed step mode
1147            int value = (int) (32 * speed);
1148            if (value > 31) {
1149                // max possible speed
1150                value = 31;
1151            }
1152            SerialMessage m = new SerialMessage();
1153            m.setOpCode(0xF9);
1154    
1155            if (value < 0) {
1156                // System HALT (immediate stop; ALL)
1157                m.putAsWord(0xFF8B);
1158
1159                // send to layout (send 4 times to ensure received)
1160                tc.sendSerialMessage(m, null);
1161                tc.sendSerialMessage(m, null);
1162                tc.sendSerialMessage(m, null);
1163                tc.sendSerialMessage(m, null);
1164
1165            } else {
1166                // normal speed setting
1167                m.putAsWord(0x0160 + address.getNumber() * 512 + value);
1168
1169                // send to command station (send twice is set, but number of sends may need to be adjusted depending on efficiency)
1170                tc.sendSerialMessage(m, null);
1171                tc.sendSerialMessage(m, null);
1172            }
1173        }
1174
1175        // Option TMCC1_32 "Absolute" speed steps
1176        if (speedStepMode == jmri.SpeedStepMode.TMCC1_32) {
1177
1178            // TMCC1 32 speed step mode
1179            int value = (int) (32 * speed);
1180            if (value > 31) {
1181                // max possible speed
1182                value = 31;
1183            }
1184            SerialMessage m = new SerialMessage();
1185            m.setOpCode(0xFE);
1186    
1187            if (value < 0) {
1188                // System HALT (immediate stop; ALL)
1189                m.putAsWord(0xFFFF);
1190
1191                // send to layout (send 4 times to ensure received)
1192                tc.sendSerialMessage(m, null);
1193                tc.sendSerialMessage(m, null);
1194                tc.sendSerialMessage(m, null);
1195                tc.sendSerialMessage(m, null);
1196
1197            } else {
1198                // normal speed setting
1199                m.putAsWord(0x0060 + address.getNumber() * 128 + value);
1200
1201                // send to layout (send twice is set, but number of sends may need to be adjusted depending on efficiency)
1202                tc.sendSerialMessage(m, null);
1203                tc.sendSerialMessage(m, null);           
1204            }
1205        }
1206                  
1207        // Option TMCC1TR_32 "Absolute" speed steps
1208        if (speedStepMode == jmri.SpeedStepMode.TMCC1TR_32) {
1209
1210            // TMCC1TR 32 speed step mode
1211            int value = (int) (32 * speed);
1212            if (value > 31) {
1213                // max possible speed
1214                value = 31;
1215            }
1216            SerialMessage m = new SerialMessage();
1217            m.setOpCode(0xFE);
1218    
1219            if (value < 0) {
1220                // System HALT (immediate stop; ALL)
1221                m.putAsWord(0xFFFF);
1222
1223                // send to layout (send 4 times to ensure received)
1224                tc.sendSerialMessage(m, null);
1225                tc.sendSerialMessage(m, null);
1226                tc.sendSerialMessage(m, null);
1227                tc.sendSerialMessage(m, null);
1228
1229            } else {
1230                // normal speed setting
1231                m.putAsWord(0xC860 + address.getNumber() * 128 + value);
1232
1233                // send to layout (send twice is set, but number of sends may need to be adjusted depending on efficiency)
1234                tc.sendSerialMessage(m, null);
1235                tc.sendSerialMessage(m, null);           
1236            }
1237        }
1238
1239        synchronized(this) {
1240            firePropertyChange(SPEEDSETTING, oldSpeed, this.speedSetting);
1241        }
1242        record(speed);
1243    }
1244
1245    /**
1246     * {@inheritDoc}
1247     */
1248    @Override
1249    public void setIsForward(boolean forward) {
1250        boolean old = isForward;
1251        isForward = forward;
1252
1253        // notify layout
1254        SerialMessage m = new SerialMessage();
1255        if (speedStepMode == jmri.SpeedStepMode.TMCC1_32 || speedStepMode == jmri.SpeedStepMode.TMCC1_100) {
1256            m.setOpCode(0xFE);
1257            if (forward) {
1258                m.putAsWord(0x0000 + address.getNumber() * 128);
1259                setSpeedSetting(0.0f);
1260            } else {
1261                m.putAsWord(0x0003 + address.getNumber() * 128);
1262                setSpeedSetting(0.0f);
1263            }
1264        }
1265
1266        if (speedStepMode == jmri.SpeedStepMode.TMCC1TR_32 || speedStepMode == jmri.SpeedStepMode.TMCC1TR_100) {
1267            m.setOpCode(0xFE);
1268            if (forward) {
1269                m.putAsWord(0xC800 + address.getNumber() * 128);
1270                setSpeedSetting(0.0f);
1271            } else {
1272                m.putAsWord(0xC803 + address.getNumber() * 128);
1273                setSpeedSetting(0.0f);
1274            }
1275        }
1276
1277        if (speedStepMode == jmri.SpeedStepMode.TMCC2_32 || speedStepMode == jmri.SpeedStepMode.TMCC2_200) {
1278            m.setOpCode(0xF8);
1279            if (forward) {
1280                m.putAsWord(0x0100 + address.getNumber() * 512);
1281                setSpeedSetting(0.0f);
1282            } else {
1283                m.putAsWord(0x0103 + address.getNumber() * 512);
1284                setSpeedSetting(0.0f);
1285            }
1286        }
1287
1288        if (speedStepMode == jmri.SpeedStepMode.TMCC2TR_32 || speedStepMode == jmri.SpeedStepMode.TMCC2TR_200) {
1289            m.setOpCode(0xF9);
1290            if (forward) {
1291                m.putAsWord(0x0100 + address.getNumber() * 512);
1292                setSpeedSetting(0.0f);
1293            } else {
1294                m.putAsWord(0x0103 + address.getNumber() * 512);
1295                setSpeedSetting(0.0f);
1296            }
1297        }
1298
1299        // send to command station (send twice is set, but number of sends may need to be adjusted depending on efficiency)
1300        tc.sendSerialMessage(m, null);
1301        tc.sendSerialMessage(m, null);
1302
1303        firePropertyChange(ISFORWARD, old, isForward);
1304    }
1305
1306    /**
1307     * Send these messages to the layout and repeat
1308     * while button is pressed/on.
1309     * @param value Content of message to be sent in three bytes
1310     * @param func  The number of the function being addressed
1311     */
1312    protected void sendFnToLayout(int value, int func) {
1313        
1314        if (speedStepMode == jmri.SpeedStepMode.TMCC2_200 || speedStepMode == jmri.SpeedStepMode.TMCC2TR_200) {
1315            if (func == 24) {
1316                setSpeedSetting(0.055f);
1317                return;
1318            }
1319            if (func == 25) {
1320                setSpeedSetting(0.205f);
1321                return;
1322            }
1323            if (func == 26) {
1324                setSpeedSetting(0.355f);
1325                return;
1326            }
1327            if (func == 27) {
1328                setSpeedSetting(0.505f);
1329                return;
1330            }
1331            if (func == 28) {
1332                setSpeedSetting(0.705f);
1333                return;
1334            }
1335            if (func == 29) {
1336                setSpeedSetting(1.0f);
1337                return;
1338            }
1339        }
1340
1341        if (speedStepMode == jmri.SpeedStepMode.TMCC1_100 || speedStepMode == jmri.SpeedStepMode.TMCC1TR_100) {
1342            if (func == 24) {
1343                setSpeedSetting(0.055f);
1344                return;
1345            }
1346            if (func == 25) {
1347                setSpeedSetting(0.205f);
1348                return;
1349            }
1350            if (func == 26) {
1351                setSpeedSetting(0.355f);
1352                return;
1353            }
1354            if (func == 27) {
1355                setSpeedSetting(0.505f);
1356                return;
1357            }
1358            if (func == 28) {
1359                setSpeedSetting(0.705f);
1360                return;
1361            }
1362            if (func == 29) {
1363                setSpeedSetting(1.0f);
1364                return;
1365            }
1366        }
1367
1368        if (speedStepMode == jmri.SpeedStepMode.TMCC1_32 || speedStepMode == jmri.SpeedStepMode.TMCC1TR_32 || speedStepMode == jmri.SpeedStepMode.TMCC2_32 || speedStepMode == jmri.SpeedStepMode.TMCC2TR_32) {
1369            if (func == 24) {
1370                setSpeedSetting(0.130f);
1371                return;
1372            }
1373            if (func == 25) {
1374                setSpeedSetting(0.320f);
1375                return;
1376            }
1377            if (func == 26) {
1378                setSpeedSetting(0.450f);
1379                return;
1380            }
1381            if (func == 27) {
1382                setSpeedSetting(0.580f);
1383                return;
1384            }
1385            if (func == 28) {
1386                setSpeedSetting(0.775f);
1387                return;
1388            }
1389            if (func == 29) {
1390                setSpeedSetting(1.0f);
1391                return;
1392            }
1393        }
1394
1395        /**
1396        * This code sends FnKey presses to the command station. 
1397        * Send once is set, per the need of TMCC multi-key commands that
1398        * do not work when a specific command sequence is not followed.
1399        * If these multi-key commands are integrated into single FnKeys,
1400        * this "send" section can be converted back to "send twice" as
1401        * the other send sequences througout tmcc\SerialThrottle.java.
1402        */
1403
1404        repeatFunctionSendWhileOn(value, func); // Single FnKey Press, Single Send; FnKey Held, Repeats FnKey while pressed.
1405    }
1406
1407    /**
1408    * This code block is necessary to support the send repeats of
1409    * the repeatFunctionSendWhileOn(value, func); code above.
1410    * This code block "Sends Again" if FkKey is still pressed/on, and
1411    * repeats per the interval set in static final int REPEAT_TIME.
1412    */
1413
1414    static final int REPEAT_TIME = 150;
1415
1416    protected void repeatFunctionSendWhileOn(int value, int func) {
1417        if (getFunction(func)) {
1418            tc.sendSerialMessage(new SerialMessage(value), null);
1419            jmri.util.ThreadingUtil.runOnLayoutDelayed(() -> {
1420                repeatFunctionSendWhileOn(value, func);
1421            }, REPEAT_TIME);
1422        }
1423    }
1424
1425    /*
1426     * Set the speed step value.
1427     * <p>
1428     * The speed step range is from 32 steps, to 100 steps, to 200 steps
1429     *
1430     * @param mode only TMCC1_32, TMCC2_32, TMCC1_100 and TMCC2_200 are allowed
1431     */
1432    @Override
1433    public void setSpeedStepMode(jmri.SpeedStepMode mode) {
1434        if (mode == jmri.SpeedStepMode.TMCC1_32 || mode == jmri.SpeedStepMode.TMCC1TR_32 || mode == jmri.SpeedStepMode.TMCC2_32 || mode == jmri.SpeedStepMode.TMCC2TR_32 || mode == jmri.SpeedStepMode.TMCC1_100 || mode == jmri.SpeedStepMode.TMCC1TR_100 || mode == jmri.SpeedStepMode.TMCC2_200 || mode == jmri.SpeedStepMode.TMCC2TR_200) {
1435            super.setSpeedStepMode(mode);
1436        }
1437    }
1438
1439    /**
1440     * {@inheritDoc}
1441     */
1442    @Override
1443    public void throttleDispose() {
1444        finishRecord();
1445    }
1446
1447}