001package jmri.jmrit.etcs.dmi.swing;
002
003import jmri.jmrit.etcs.CabMessage;
004import jmri.jmrit.etcs.TrackCondition;
005import jmri.jmrit.etcs.TrackSection;
006import jmri.jmrit.etcs.StationTrackCondition;
007import jmri.jmrit.etcs.MovementAuthority;
008
009import java.util.ArrayList;
010
011import org.apiguardian.api.API;
012
013/**
014 * Class to demonstrate features of the ERTMS ETCS DMI.
015 * @author Steve Young Copyright (C) 2024
016 */
017@API(status=API.Status.EXPERIMENTAL)
018public class DmiDemo {
019
020    final DmiPanel dmiPanel;
021
022    /**
023     * Create a new Demo for a given DmiPanel.
024     * @param mainPanel the mainPanel to run the demo on.
025     */
026    public DmiDemo(DmiPanel mainPanel) {
027        dmiPanel = mainPanel;
028    }
029
030    /**
031     * Run the Demonstration.
032     */
033    public void runDemo() {
034        jmri.util.ThreadingUtil.newThread(this::doDemo, "DMI Demo").start();
035    }
036
037    private void doDemo() {
038        dmiPanel.messageDriver(new CabMessage("Starting DMI GUI Demo", 1, false));
039        waitFor(1000);
040        pt1();
041    }
042
043    private void pt1(){
044
045        CabMessage ackMsg = new CabMessage("Message which needs Acknowledge", 1, true);
046        dmiPanel.messageDriver(ackMsg);
047        waitFor(3000);
048
049        dmiPanel.removeMessage(ackMsg.getMessageId());
050        dmiPanel.messageDriver(new CabMessage("Ack Message removed, this is a normal CabMessage.", 1, false));
051        waitFor(1000);
052
053
054        dmiPanel.messageDriver(new CabMessage("Ramp speed, setSpeedHookSpeed 0 to 140", 1, false));
055        for (int i = 0; i < 141; i++) {
056            waitFor(50);
057            dmiPanel.setActualSpeed(i);
058            setSpeedHookSpeed(i, dmiPanel);
059        }
060
061        dmiPanel.messageDriver(new CabMessage("Ramp speed, "
062            +"setSpeedHookSpeed 140 to 0", 1, false));
063        for (int i = 140; i > -1; i-- ) {
064            waitFor(50);
065            dmiPanel.setActualSpeed(i);
066            setSpeedHookSpeed(i, dmiPanel);
067        }
068
069        dmiPanel.messageDriver(new CabMessage("Max Speed to 180", 1, false));
070        dmiPanel.setMaxDialSpeed(180);
071        waitFor(1000);
072
073        dmiPanel.messageDriver(new CabMessage("RampActualSpeed setSpeedHookSpeed 0 - 20", 1, false));
074        for (int i = 0; i < 21; i++ ) {
075            waitFor(150);
076            dmiPanel.setActualSpeed(i);
077            setSpeedHookSpeed(i, dmiPanel);
078        }
079
080        dmiPanel.messageDriver(new CabMessage("RampActualSpeed setSpeedHookSpeed 20 - 0", 1, false));
081        for (int i = 20; i > -1; i-- ) {
082            waitFor(150);
083            dmiPanel.setActualSpeed(i);
084            setSpeedHookSpeed(i, dmiPanel);
085        }
086
087        dmiPanel.messageDriver(new CabMessage("Ramp speed and hook to 20", 1, false));
088        for (int i = 0; i < 21; i++ ) {
089            waitFor(150);
090            dmiPanel.setActualSpeed(i);
091            setSpeedHookSpeed(i, dmiPanel);
092        }
093
094        dmiPanel.messageDriver(new CabMessage("Max Speed to 250", 1, false));
095        dmiPanel.setMaxDialSpeed(250);
096        waitFor(1000);
097
098        dmiPanel.messageDriver(new CabMessage("Max Speed to 400", 1, false));
099        dmiPanel.setMaxDialSpeed(400);
100        waitFor(1000);
101
102        dmiPanel.messageDriver(new CabMessage("Ramp speed and Target Advice Speed 0-400", 1, false));
103        for (int i = 0; i < 401; i++ ) {
104            waitFor(20);
105            dmiPanel.setActualSpeed(i);
106            dmiPanel.setTargetAdviceSpeed(i);
107        }
108
109        dmiPanel.messageDriver(new CabMessage("speed 70 , hook 80", 1, false));
110        dmiPanel.setActualSpeed(70);
111        setSpeedHookSpeed(80, dmiPanel);
112
113        dmiPanel.setTargetAdviceSpeed(-1);
114
115        dmiPanel.messageDriver(new CabMessage("Limited Supervision Speed 10", 1, false));
116        dmiPanel.setLimitedSupervisionSpeed(10);
117        waitFor(1000);
118
119        dmiPanel.messageDriver(new CabMessage("Limited Supervision Speed 0-400", 1, false));
120        for (int i = 0; i < 401; i++ ) {
121            waitFor(30);
122            dmiPanel.setLimitedSupervisionSpeed(i);
123        }
124
125        waitFor(1000);
126        dmiPanel.messageDriver(new CabMessage("Hide Limited Supervision Speed", 1, false));
127        dmiPanel.setLimitedSupervisionSpeed(-1);
128
129        dmiPanel.messageDriver(new CabMessage("Distance to Target 1500m to 0m", 1, false));
130        for (int i = 1500; i > -100; i-- ) {
131            dmiPanel.setDistanceToTarget(i);
132            waitFor(5);
133        }
134
135        dmiPanel.setActualSpeed(96);
136        setSpeedHookSpeed(100, dmiPanel);
137        waitFor(1000);
138
139        dmiPanel.messageDriver(new CabMessage("Speed Unit to MPH", 1, false));
140        dmiPanel.setDisplaySpeedUnit("MPH");
141        waitFor(1000);
142
143        dmiPanel.messageDriver(new CabMessage("Speed Unit Empty", 1, false));
144        dmiPanel.setDisplaySpeedUnit("");
145        dmiPanel.setCoasting(false);
146        waitFor(1000);
147        
148        
149        pt2();
150    }
151
152
153    private void pt2(){
154
155        // dmiPanel.messageDriver(new CabMessage("Setting Level to NTC", 1, false));
156        // dmiPanel.setLevel(-1);
157
158        waitFor(1000);
159
160
161
162        dmiPanel.messageDriver(new CabMessage("Track Ahead Free Question Visible", 1, false));
163        dmiPanel.setTrackAheadFreeQuestionVisible(true);
164        waitFor(2000);
165
166
167        dmiPanel.messageDriver(new CabMessage("Track Ahead Free Question Hidden", 1, false));
168        dmiPanel.setTrackAheadFreeQuestionVisible(false);
169        waitFor(1000);
170
171
172        dmiPanel.messageDriver(new CabMessage("Tunnel Stopping Icon Visible Ack", 1, false));
173        dmiPanel.setTunnelStoppingIconVisible(true, true);
174        waitFor(2000);
175
176
177        dmiPanel.messageDriver(new CabMessage("Tunnel Stopping Icon No Ack", 1, false));
178        dmiPanel.setTunnelStoppingIconVisible(true, false);
179        waitFor(1000);
180
181
182        dmiPanel.messageDriver(new CabMessage("Tunnel Stopping Distance 400 to 0", 1, false));
183        for (int i = 401; i > -2; i--) {
184            waitFor(50);
185            dmiPanel.setTunnelStoppingDistance(i);
186        }
187
188        dmiPanel.messageDriver(new CabMessage("Tunnel Stopping Icon hidden", 1, false));
189        dmiPanel.setTunnelStoppingIconVisible(false, false);
190        waitFor(1000);
191
192
193        dmiPanel.messageDriver(new CabMessage("Notification Level transition to NTC", 1, false));
194        dmiPanel.setLevelTransition(-1, true);
195        waitFor(1000);
196
197        dmiPanel.messageDriver(new CabMessage("Notification Level transition to 0", 1, false));
198        dmiPanel.setLevelTransition(0, false);
199        waitFor(1000);
200
201        dmiPanel.messageDriver(new CabMessage("Level to 0", 1, false));
202        dmiPanel.setLevel(0);
203        waitFor(1000);
204
205        dmiPanel.messageDriver(new CabMessage("Notification Level transition to 1", 1, false));
206        dmiPanel.setLevelTransition(1, false);
207        waitFor(1000);
208
209        dmiPanel.messageDriver(new CabMessage("Set Level 1", 1, false));
210        dmiPanel.setLevel(1);
211        waitFor(1000);
212
213        dmiPanel.messageDriver(new CabMessage("Set Level 2", 1, false));
214        dmiPanel.setLevel(2);
215        waitFor(1000);
216
217        dmiPanel.messageDriver(new CabMessage("Hide Notification Level transition", 1, false));
218        dmiPanel.setLevelTransition(-2, false);
219        waitFor(1000);
220
221        // not valid for ERTMS4
222        // dmiPanel.messageDriver(new CabMessage("Notification Level transition to 2", 1, false));
223        // dmiPanel.setLevelTransition(2, false);
224        // waitFor(1000);
225
226        // ERTMS < 4
227        // dmiPanel.messageDriver(new CabMessage("Notification Level transition to 3", 1, false));
228        // dmiPanel.setLevelTransition(3, false);
229        // waitFor(1000);
230
231        dmiPanel.messageDriver(new CabMessage("Safe Radio Connection Lost", 1, false));
232        dmiPanel.setSafeRadioConnection(0);
233        waitFor(1000);
234
235        dmiPanel.messageDriver(new CabMessage("Safe Radio Connection Hidden", 1, false));
236        dmiPanel.setSafeRadioConnection(-1);
237        waitFor(1000);
238
239        dmiPanel.messageDriver(new CabMessage("Safe Radio Connection", 1, false));
240        dmiPanel.setSafeRadioConnection(1);
241        waitFor(1000);
242
243        
244        dmiPanel.messageDriver(new CabMessage("Adhesion Factor On", 1, false));
245        dmiPanel.setAdhesionFactorOn(true);
246        waitFor(1000);
247
248        dmiPanel.messageDriver(new CabMessage("Adhesion Factor Off", 1, false));
249        dmiPanel.setAdhesionFactorOn(false);
250        waitFor(1000);
251        
252        dmiPanel.messageDriver(new CabMessage("Display Intervetion Symbol", 1, false));
253        dmiPanel.setIntervetionSymbol(true);
254        waitFor(1000);
255
256        dmiPanel.messageDriver(new CabMessage("Hide Intervetion Symbol", 1, false));
257        dmiPanel.setIntervetionSymbol(false);
258        waitFor(1000);
259
260        dmiPanel.messageDriver(new CabMessage("Reversing Permitted", 1, false));
261        dmiPanel.setReversingPermittedSymbol(true);
262        waitFor(1000);
263
264        dmiPanel.messageDriver(new CabMessage("Reversing Permitted hidden", 1, false));
265        dmiPanel.setReversingPermittedSymbol(false);
266        waitFor(1000);
267
268        dmiPanel.messageDriver(new CabMessage("Shunting Mode", 1, false));
269        dmiPanel.setMode(1); // shunting
270        waitFor(1000);
271
272        dmiPanel.messageDriver(new CabMessage("Mode set to Trip", 1, false));
273        dmiPanel.setMode(4); // trip
274        waitFor(1000);
275
276        dmiPanel.messageDriver(new CabMessage("Mode set to Post Trip", 1, false));
277        dmiPanel.setMode(6);
278        waitFor(1000);
279
280        dmiPanel.messageDriver(new CabMessage("Mode set to On Sight", 1, false));
281        dmiPanel.setMode(7);
282        waitFor(1000);
283
284        dmiPanel.messageDriver(new CabMessage("Mode set to Staff Responsible", 1, false));
285        dmiPanel.setMode(9);
286        waitFor(1000);
287
288        dmiPanel.messageDriver(new CabMessage("Mode set to Full Supervision", 1, false));
289        dmiPanel.setMode(11);
290        waitFor(1000);
291
292        dmiPanel.messageDriver(new CabMessage("Mode set to Non-Leading", 1, false));
293        dmiPanel.setMode(12);
294        waitFor(1000);
295
296        dmiPanel.messageDriver(new CabMessage("Mode to Reversing", 1, false));
297        dmiPanel.setMode(14);
298        waitFor(1000);
299
300        dmiPanel.messageDriver(new CabMessage("Mode to Unfitted", 1, false));
301        dmiPanel.setMode(16);
302        waitFor(1000);
303
304        dmiPanel.messageDriver(new CabMessage("Mode to System Failure", 1, false));
305        dmiPanel.setMode(18);
306        waitFor(1000);
307
308        // ERTMS < 4
309        // dmiPanel.messageDriver(new CabMessage("Set Level 3", 1, false));
310        // dmiPanel.setLevel(3);
311        // waitFor(1000);
312
313
314        dmiPanel.messageDriver(new CabMessage("Release speed to 50", 1, false));
315        dmiPanel.setReleaseSpeed(50);
316        waitFor(1000);
317
318        dmiPanel.messageDriver(new CabMessage("Mode to Limited Supervision", 1, false));
319        dmiPanel.setMode(21);
320        waitFor(1000);
321
322        dmiPanel.messageDriver(new CabMessage("Hide Release speed", 1, false));
323        dmiPanel.setReleaseSpeed(-1);
324        waitFor(1000);
325
326        dmiPanel.messageDriver(new CabMessage("Set Mode to Automatic Train Operation", 1, false));
327        dmiPanel.setMode(23); // ato
328        waitFor(1000);
329
330        dmiPanel.messageDriver(new CabMessage("Display Coasting", 1, false));
331        dmiPanel.setCoasting(true);
332        waitFor(1000);
333
334        dmiPanel.messageDriver(new CabMessage("Speed Unit while coasting", 1, false));
335        dmiPanel.setCoasting(true);
336        dmiPanel.setDisplaySpeedUnit("mph");
337        waitFor(1000);
338        
339        dmiPanel.messageDriver(new CabMessage("Hide Coasting", 1, false));
340        dmiPanel.setCoasting(false);
341        dmiPanel.setDisplaySpeedUnit("");
342        waitFor(1000);
343
344        dmiPanel.messageDriver(new CabMessage("Set Mode to Supervised Manoeuvre", 1, false));
345        dmiPanel.setMode(24); // supervised manoeuvre
346        waitFor(1000);
347
348        dmiPanel.messageDriver(new CabMessage("Set Supervised Direction Forwards", 1, false));
349        dmiPanel.setSupervisedDirection(1);
350        waitFor(1000);
351
352        dmiPanel.messageDriver(new CabMessage("Set Supervised Direction Reverse", 1, false));
353        dmiPanel.setSupervisedDirection(-1);
354        waitFor(1000);
355
356        dmiPanel.messageDriver(new CabMessage("Hide Supervised Direction", 1, false));
357        dmiPanel.setSupervisedDirection(0);
358        waitFor(1000);
359
360        checkModeAcknowledge(DmiPanel.PROP_CHANGE_MODE_SHUNTING_ACK, DmiPanel.MODE_SHUNTING, dmiPanel);
361        checkModeAcknowledge(DmiPanel.PROP_CHANGE_MODE_TRIP_ACK, DmiPanel.MODE_TRIP, dmiPanel);
362        checkModeAcknowledge(DmiPanel.PROP_CHANGE_MODE_ON_SIGHT_ACK, DmiPanel.MODE_ON_SIGHT, dmiPanel);
363        checkModeAcknowledge(DmiPanel.PROP_CHANGE_MODE_STAFF_RESPONSIBLE_ACK, DmiPanel.MODE_STAFF_RESPONSIBLE, dmiPanel);
364        checkModeAcknowledge(DmiPanel.PROP_CHANGE_MODE_REVERSING_ACK, DmiPanel.MODE_REVERSING, dmiPanel);
365        checkModeAcknowledge(DmiPanel.PROP_CHANGE_MODE_UNFITTED_ACK, DmiPanel.MODE_UNFITTED, dmiPanel);
366        checkModeAcknowledge(DmiPanel.PROP_CHANGE_MODE_NATIONAL_SYSTEM_ACK, DmiPanel.MODE_NATIONAL_SYSTEM, dmiPanel);
367        checkModeAcknowledge(DmiPanel.PROP_CHANGE_MODE_LIMITED_SUPERVISION_ACK, DmiPanel.MODE_LIMITED_SUPERVISION, dmiPanel);
368
369        pt3();
370
371    }
372
373    private void checkModeAcknowledge(String str, int mode, DmiPanel main){
374        main.setModeAcknowledge(mode);
375        main.messageDriver(new CabMessage(addSpaceBeforeCapital(str), 1, false));
376        waitFor(1000);
377        main.setModeAcknowledge(DmiPanel.MODE_NONE);
378        waitFor(500);
379    }
380
381    private void pt3() {
382
383        dmiPanel.setLevel(2);
384        dmiPanel.setMode(DmiPanel.MODE_AUTOMATIC_DRIVING);
385        dmiPanel.setSafeRadioConnection(1);
386
387        waitFor(1000);
388
389        dmiPanel.setAtoMode(1);
390        dmiPanel.messageDriver(new CabMessage("ATO Selected", 1, false));
391
392        waitFor(1000);
393
394        dmiPanel.setAtoMode(2);
395        dmiPanel.messageDriver(new CabMessage("ATO ready for engagement", 1, false));
396
397        waitFor(1000);
398
399        dmiPanel.setAtoMode(3);
400        dmiPanel.messageDriver(new CabMessage("ATO Engaged", 1, false));
401
402        waitFor(1000);
403
404        dmiPanel.setAtoMode(4);
405        dmiPanel.messageDriver(new CabMessage("ATO Disengaging", 1, false));
406
407        waitFor(1000);
408
409        dmiPanel.setAtoMode(5);
410        dmiPanel.messageDriver(new CabMessage("ATO Failure", 1, false));
411        waitFor(1000);
412
413        dmiPanel.setAtoMode(0);
414        dmiPanel.messageDriver(new CabMessage("ATO Off", 1, false));
415        waitFor(1000);
416
417
418
419        dmiPanel.setAtoMode(3);
420
421
422        dmiPanel.messageDriver(new CabMessage("Undershot stopping window", 1, false));
423        dmiPanel.setStoppingAccuracy(-1);
424        waitFor(1000);
425
426        dmiPanel.messageDriver(new CabMessage("Accurate stopping window", 1, false));
427        dmiPanel.setStoppingAccuracy(0);
428        waitFor(1000);
429
430
431        dmiPanel.messageDriver(new CabMessage("Overshotshot stopping window", 1, false));
432        dmiPanel.setStoppingAccuracy(1);
433        waitFor(1000);
434
435        dmiPanel.messageDriver(new CabMessage("Hide stopping window", 1, false));
436        dmiPanel.setStoppingAccuracy(-2);
437        waitFor(1000);
438
439        dmiPanel.messageDriver(new CabMessage("Set Stopping Point", 1, false));
440        dmiPanel.setStoppingPointLabel("Welwyn North", "17:36:48");
441        waitFor(1000);
442
443        dmiPanel.messageDriver(new CabMessage("Skip Stopping Point Active", 1, false));
444        dmiPanel.setSkipStoppingPoint(17);
445        waitFor(1000);
446
447        dmiPanel.messageDriver(new CabMessage("Skip Stopping Point requested by ATO-TS", 1, false));
448        dmiPanel.setSkipStoppingPoint(18);
449        waitFor(1000);
450
451        dmiPanel.messageDriver(new CabMessage("Skip Stopping Point requested by driver", 1, false));
452        dmiPanel.setSkipStoppingPoint(19);
453        waitFor(1000);
454
455        dmiPanel.messageDriver(new CabMessage("Hide Skip Stopping Point", 1, false));
456        dmiPanel.setSkipStoppingPoint(0);
457        waitFor(1000);
458
459        dmiPanel.messageDriver(new CabMessage("Set Stopping Point Hidden", 1, false));
460        dmiPanel.setStoppingPointLabel("", "");
461        waitFor(1000);
462
463        dmiPanel.messageDriver(new CabMessage("Request driver to open both sides doors", 1, false));
464        dmiPanel.setDoorIcon(10);
465        waitFor(1000);
466
467        dmiPanel.messageDriver(new CabMessage("Request driver to open left doors", 1, false));
468        dmiPanel.setDoorIcon(11);
469        waitFor(1000);
470
471        dmiPanel.messageDriver(new CabMessage("Request driver to open right doors", 1, false));
472        dmiPanel.setDoorIcon(12);
473        waitFor(1000);
474
475        dmiPanel.messageDriver(new CabMessage("Doors are open", 1, false));
476        dmiPanel.setDoorIcon(13);
477        waitFor(1000);
478
479        dmiPanel.messageDriver(new CabMessage("Request driver to close doors", 1, false));
480        dmiPanel.setDoorIcon(14);
481        waitFor(1000);
482
483        dmiPanel.messageDriver(new CabMessage("Doors are being closed by ATO", 1, false));
484        dmiPanel.setDoorIcon(15);
485        waitFor(1000);
486
487        dmiPanel.messageDriver(new CabMessage("Doors are closed", 1, false));
488        dmiPanel.setDoorIcon(16);
489        waitFor(1000);
490
491        dmiPanel.messageDriver(new CabMessage("Dwell Time set to 1min 9secs", 1, false));
492        dmiPanel.setDwellTime(1, 9);
493        waitFor(1000);
494
495        dmiPanel.messageDriver(new CabMessage("Dwell Time set to 1min 8secs", 1, false));
496        dmiPanel.setDwellTime(1, 8);
497        waitFor(1000);
498
499        dmiPanel.messageDriver(new CabMessage("Hide Dwell Time", 1, false));
500        dmiPanel.setDwellTime(-1, -1);
501        waitFor(1000);
502
503        dmiPanel.messageDriver(new CabMessage("Doors are closed", 1, false));
504        dmiPanel.setDoorIcon(16);
505        waitFor(1000);
506
507        dmiPanel.messageDriver(new CabMessage("Doors icon hidden", 1, false));
508        dmiPanel.setDoorIcon(0);
509        waitFor(1000);
510
511        pt4();
512    }
513
514    private void pt4() {
515
516        dmiPanel.messageDriver(new CabMessage("Add Movement Authority", 1, false));
517        ArrayList<TrackSection> trackSectionList = new ArrayList<>();
518        TrackSection s1 = new TrackSection(75,100,-4);
519        TrackSection s2 = new TrackSection(50,140,-2);
520        TrackSection s3 = new TrackSection(125,100,1);
521        TrackSection s4 = new TrackSection(250,80,2);
522        TrackSection s5 = new TrackSection(250,40,4);
523        TrackSection s6 = new TrackSection(250,100,8);
524        trackSectionList.add(s1);
525        trackSectionList.add(s2);
526        trackSectionList.add(s3);
527        trackSectionList.add(s4);
528        trackSectionList.add(s5);
529        trackSectionList.add(s6);
530        dmiPanel.extendMovementAuthorities(new MovementAuthority(trackSectionList)); // 1000m
531        waitFor(1000);
532
533        dmiPanel.messageDriver(new CabMessage("Advance Movement Authority", 1, false));
534        for (int i = 0; i < 1100; i++ ) {
535            dmiPanel.advance(1);
536            waitFor(20);
537        }
538
539        s1 = new TrackSection(7700,100,1);
540
541        int pos = 0;
542
543
544        s1.addAnnouncement(TrackCondition.levelCrossing(pos+=200));
545        s1.addAnnouncement(TrackCondition.radioHole(pos+=200));
546        s1.addAnnouncement(TrackCondition.soundHorn(pos+=200));
547
548        s1.addAnnouncement(TrackCondition.pantographLower(pos+=200, true));
549        s1.addAnnouncement(TrackCondition.pantographLower(pos+=200, false));
550        s1.addAnnouncement(TrackCondition.pantographRaise(pos+=200, true));
551        s1.addAnnouncement(TrackCondition.pantographRaise(pos+=200, false));
552
553
554        s1.addAnnouncement(TrackCondition.airConClose(pos+=200, true));
555        s1.addAnnouncement(TrackCondition.airConClose(pos+=200, false));
556        s1.addAnnouncement(TrackCondition.airConOpen(pos+=200, true));
557        s1.addAnnouncement(TrackCondition.airConOpen(pos+=200, false));
558
559        s1.addAnnouncement(TrackCondition.neutralSection(pos+=200, true));
560        s1.addAnnouncement(TrackCondition.neutralSection(pos+=200, false));
561        s1.addAnnouncement(TrackCondition.neutralSectionEnd(pos+=200, true));
562        s1.addAnnouncement(TrackCondition.neutralSectionEnd(pos+=200, false));
563
564        s1.addAnnouncement(TrackCondition.nonStoppingArea(pos+=200, true));
565
566        s1.addAnnouncement(TrackCondition.inhibitMagShoeBrake(pos+=200, true));
567        s1.addAnnouncement(TrackCondition.inhibitMagShoeBrake(pos+=200, false));
568        s1.addAnnouncement(TrackCondition.inhibitEddyCurrentBrake(pos+=200, true));
569        s1.addAnnouncement(TrackCondition.inhibitEddyCurrentBrake(pos+=200, false));
570        s1.addAnnouncement(TrackCondition.inhibitRegenerativeBrake(pos+=200, true));
571        s1.addAnnouncement(TrackCondition.inhibitRegenerativeBrake(pos+=200, false));
572
573        s1.addAnnouncement(TrackCondition.tractionChange0(pos+=200, true));
574        s1.addAnnouncement(TrackCondition.tractionChange0(pos+=200, false));
575        s1.addAnnouncement(TrackCondition.tractionChange25000(pos+=200, true));
576        s1.addAnnouncement(TrackCondition.tractionChange25000(pos+=200, false));
577        s1.addAnnouncement(TrackCondition.tractionChange15000(pos+=200, true));
578        s1.addAnnouncement(TrackCondition.tractionChange15000(pos+=200, false));
579        s1.addAnnouncement(TrackCondition.tractionChange3000(pos+=200, true));
580        s1.addAnnouncement(TrackCondition.tractionChange3000(pos+=200, false));
581        s1.addAnnouncement(TrackCondition.tractionChange1500(pos+=200, true));
582        s1.addAnnouncement(TrackCondition.tractionChange1500(pos+=200, false));
583        s1.addAnnouncement(TrackCondition.tractionChange750(pos+=200, true));
584        s1.addAnnouncement(TrackCondition.tractionChange750(pos+=200, false));
585        s1.addAnnouncement(new StationTrackCondition(pos+=200,"Welwyn North"));
586
587        trackSectionList = new ArrayList<>();
588        trackSectionList.add(s1);
589        dmiPanel.extendMovementAuthorities(new MovementAuthority(trackSectionList));
590
591        waitFor(1000);
592
593        dmiPanel.setScale(5);
594        dmiPanel.messageDriver(new CabMessage("Set Planning Scale 0-3200", 1, false));
595        waitFor(1000);
596
597        dmiPanel.setScale(4);
598        dmiPanel.messageDriver(new CabMessage("Set Planning Scale 0-1600", 1, false));
599        waitFor(1000);
600
601        dmiPanel.setScale(3);
602        dmiPanel.messageDriver(new CabMessage("Set Planning Scale 0-8000", 1, false));
603        waitFor(1000);
604
605        dmiPanel.setScale(2);
606        dmiPanel.messageDriver(new CabMessage("Set Planning Scale 0-4000", 1, false));
607        waitFor(1000);
608
609        dmiPanel.setScale(1);
610        dmiPanel.messageDriver(new CabMessage("Set Planning Scale 0-2000", 1, false));
611        waitFor(1000);
612
613        dmiPanel.setScale(0);
614        dmiPanel.messageDriver(new CabMessage("Set Planning Scale 0-1000", 1, false));
615        waitFor(1000);
616
617
618        String tcString = "";
619        for (int i = 0; i < 7300; i++ ) {
620            dmiPanel.advance(1);
621            TrackCondition nextTc = dmiPanel.getNextAnnouncement(false);
622            if ( nextTc != null ) {
623                String newString = nextTc.getDescription();
624                if (!( tcString.equals(newString) )) {
625                    tcString = newString;
626                    dmiPanel.messageDriver(new CabMessage(tcString, 1, false));
627                }
628            }
629            waitFor(10);
630
631        }
632
633        dmiPanel.setMode(DmiPanel.MODE_SUPERVISED_MANOEUVRE);
634        dmiPanel.messageDriver(new CabMessage("Indication Marker", 1, false));
635        dmiPanel.setIndicationMarker(100,0);
636        waitFor(1000);
637
638        dmiPanel.messageDriver(new CabMessage("Indication Marker in ATO", 1, false));
639        dmiPanel.setMode(DmiPanel.MODE_AUTOMATIC_DRIVING);
640        waitFor(1000);
641
642        pt5();
643    }
644
645    private void pt5(){
646
647        dmiPanel.messageDriver(new CabMessage("Play Sound Too Fast", 1, false));
648        dmiPanel.playDmiSound(1);
649        waitFor(3000);
650
651        dmiPanel.messageDriver(new CabMessage("Play Sound Info", 1, false));
652        dmiPanel.playDmiSound(3);
653        waitFor(3000);
654
655        dmiPanel.messageDriver(new CabMessage("Play Sound Click", 1, false));
656        dmiPanel.playDmiSound(4);
657        waitFor(3000);
658
659        dmiPanel.messageDriver(new CabMessage("Play Sound Warning", 1, false));
660        dmiPanel.playDmiSound(2);
661        waitFor(3000);
662
663        dmiPanel.messageDriver(new CabMessage("Stop Sound Warning", 1, false));
664        dmiPanel.stopDmiSound(2);
665
666        waitFor(1000);
667        dmiPanel.messageDriver(new CabMessage("Demo Complete", 1, false));
668    }
669
670    private static void setSpeedHookSpeed(int speedHookSpeed, DmiPanel p){
671
672        java.util.ArrayList<DmiCircularSpeedGuideSection> csgSectionList = new java.util.ArrayList<>();
673
674        csgSectionList.add(new DmiCircularSpeedGuideSection(DmiCircularSpeedGuideSection.CSG_TYPE_NORMAL,
675            DmiPanel.DARK_GREY, -2, 1, false ));
676
677
678        p.setCentreCircleAndDialColor(DmiPanel.YELLOW);
679
680        if ( speedHookSpeed > 110 ) {
681
682            csgSectionList.add(new DmiCircularSpeedGuideSection(DmiCircularSpeedGuideSection.CSG_TYPE_HOOK,
683            DmiPanel.ORANGE, 110, speedHookSpeed, true ));
684
685            p.setCentreCircleAndDialColor(DmiPanel.ORANGE);
686        }
687
688        if ( speedHookSpeed > 200 ) {
689
690            csgSectionList.add(new DmiCircularSpeedGuideSection(DmiCircularSpeedGuideSection.CSG_TYPE_HOOK,
691            DmiPanel.RED, 200, speedHookSpeed, true ));
692            p.setCentreCircleAndDialColor(DmiPanel.RED);
693
694        }
695
696        if ( speedHookSpeed <= 50 ){
697
698            csgSectionList.add(new DmiCircularSpeedGuideSection(DmiCircularSpeedGuideSection.CSG_TYPE_NORMAL,
699            DmiPanel.GREY, 0, Math.min(speedHookSpeed, 110 ), false));
700
701
702        csgSectionList.add(new DmiCircularSpeedGuideSection(DmiCircularSpeedGuideSection.CSG_TYPE_SUPERVISION,
703            DmiPanel.YELLOW, 0, 50, false));
704        } else {
705            csgSectionList.add(new DmiCircularSpeedGuideSection(DmiCircularSpeedGuideSection.CSG_TYPE_NORMAL,
706            DmiPanel.YELLOW, 0, Math.min(speedHookSpeed, 110 ), true));
707            csgSectionList.add(new DmiCircularSpeedGuideSection(DmiCircularSpeedGuideSection.CSG_TYPE_RELEASE,
708            DmiPanel.YELLOW, 0, 50, false));
709        }
710
711
712        p.setCsgSections(csgSectionList);
713
714    }
715
716    private static String addSpaceBeforeCapital(String input) {
717        if (input == null || input.isEmpty()) {
718            return input; // Return the input as is for empty or null strings
719        }
720
721        StringBuilder result = new StringBuilder();
722        for (int i = 0; i < input.length(); i++) {
723            char currentChar = input.charAt(i);
724
725            // Check if the current character is an uppercase letter
726            if (Character.isUpperCase(currentChar)) {
727                // Add a space before the uppercase letter
728                result.append(' ');
729            }
730
731            // Append the current character to the result
732            result.append(currentChar);
733        }
734
735        return result.toString();
736    }
737
738    private static final int DELAY_STEP = 11;
739    private static int delayMultiplier = 1;
740
741    protected static void setDelayMultiplier(int newVal){
742        delayMultiplier = newVal;
743    }
744
745    /**
746     * Wait for a specific amount of time
747     * <p>
748     * It's better to wait for a condition, but if you can't find a condition,
749     * this will have to do.
750     * <p>
751     *
752     * @param msec Delay in milliseconds
753     */
754    private static void waitFor(final int msec) {
755        if (javax.swing.SwingUtilities.isEventDispatchThread()) {
756            log.error("Cannot use waitFor on Swing thread", new Exception());
757            return;
758        }
759        int delay = 0;
760        while (delay < msec * delayMultiplier) {
761            int priority = Thread.currentThread().getPriority();
762            try {
763                Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
764                Thread.sleep(DELAY_STEP);
765                delay += DELAY_STEP;
766            } catch (InterruptedException e) {
767                log.error("Interrupted");
768                // Restore interrupted state...
769                Thread.currentThread().interrupt();
770            } finally {
771                Thread.currentThread().setPriority(priority);
772            }
773        }
774    }
775
776    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DmiDemo.class);
777
778}