-
-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathProgrammaticControlExample.java
More file actions
295 lines (231 loc) · 12.6 KB
/
Copy pathProgrammaticControlExample.java
File metadata and controls
295 lines (231 loc) · 12.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
package org.traincontrol.examples;
import java.util.List;
import java.util.function.Consumer;
import org.traincontrol.base.Accessory;
import org.traincontrol.base.Locomotive;
import org.traincontrol.base.Locomotive.decoderType;
import org.traincontrol.marklin.MarklinAccessory;
import static org.traincontrol.marklin.MarklinControlStation.init;
import org.traincontrol.marklin.MarklinControlStation;
import org.traincontrol.marklin.MarklinLocomotive;
/**
* This class contains example code showing how to control your layout programmatically
* @author Adam
*/
public class ProgrammaticControlExample
{
private static void execCode(MarklinControlStation mcs)
{
mcs.log("Custom code running...");
Consumer<MarklinControlStation> func = ( (data) ->
{
//
// Central Station
//
// data.stop(); // Turns off the power
// data.stopAllLocs(); // Issues stop command to all locomotives
// data.allFunctionsOff(); // Turns off all active functions for all locomotives
// data.syncWithCS2(); // Fetches the latest locomotive state from the Central Station
data.go(); // Turns on the power
data.lightsOn(data.getLocList()); // Turns on lights of all known locomotives
//
// Locomotives
//
// Retrieve all available locomotive names
List<String> allLocomotiveNames = data.getLocList();
// Retieve all available locomotives
List<Locomotive> allLocomotives = data.getLocomotives();
// Retrieve a locomotive that already exists in the CS2/CS3
Locomotive myLoc = data.getLocByName("BR 64");
// Turn on a function (F4)
myLoc.setF(4, true);
// Fire pulse function (F3 for 1 second)
myLoc.toggleF(3, 1000);
// Turn lights on (same as .setF(0, true)
myLoc.lightsOn();
// Sets a speed (0-100%)
myLoc.setSpeed(50);
// Slow deceleration
myLoc.setSpeed(0);
// Instant stop for DCC/MFX, slow deceleration for MM2
myLoc.stop();
// Instant stop for all locomotives, including MM2
((MarklinLocomotive) myLoc).instantStop();
// Sets the direction
myLoc.setDirection(Locomotive.locDirection.DIR_FORWARD);
myLoc.setDirection(Locomotive.locDirection.DIR_BACKWARD);
myLoc.switchDirection();
// Does something after a 1 second delay
myLoc.delay(1000).stop();
// Get the locomotive's raw address and decoder type
int address = ((MarklinLocomotive) myLoc).getAddress();
decoderType type = ((MarklinLocomotive) myLoc).getDecoderType();
// Define a MM2 locomotive with a specific address, even if it does not yet exist in the CS2/CS3
// This approach is generally not needed unless you absolutely don't want to interact with the CS2/CS3 :)
Locomotive myMM2Loc = data.newMM2Locomotive("BR 86", 60);
boolean f4Status = myMM2Loc.getF(4);
//
// Accessories by raw address
//
// These commands are useful if the accessory does not already exist on any layout
// Retrieve the current state of an arbitrary accessory by address
boolean state = data.getAccessoryState(3, Accessory.accessoryDecoderType.MM2);
// Change the state
data.setAccessoryState(3, Accessory.accessoryDecoderType.MM2, !state);
// The accessory will now automatically be saved in the database
MarklinAccessory mySwitch3 = data.getAccessoryByName("Switch 3");
mySwitch3.setSwitched(true);
// Manually add a new signal to the database so that it can be referenced by name
// When creating an accessory, the MM2 address will be 1 less than the logical address
data.newSignal(4, Accessory.accessoryDecoderType.MM2, false);
MarklinAccessory mySignal4 = data.getAccessoryByName("Signal 4");
// Send command to ensure the state is consistent
mySignal4.green();
// Manually add a new switch to the database so that it can be referenced by name
data.newSwitch(5, Accessory.accessoryDecoderType.MM2, false);
MarklinAccessory mySwitch5 = data.getAccessoryByName("Switch 5");
// Send command to ensure the state is consistent
mySwitch5.turn();
// DCC addresses are now supported. DCC must be added to the end of the item name.
data.newSwitch(400, Accessory.accessoryDecoderType.DCC, false);
MarklinAccessory mySwitch400 = data.getAccessoryByName("Switch 400 DCC");
// Send command to ensure the state is consistent
mySwitch400.straight();
//
// Accessories that are already on a layout
//
// Retrieve a signal by its MM2/DCC address (Note: everything but switches will always start with "Signal")
// This assumes that the signal exists within the layout
MarklinAccessory mySignal = data.getAccessoryByName("Signal 1");
// These two are equivalent
mySignal.red();
mySignal.setSwitched(true);
// These two are equivalent
mySignal.green();
mySignal.setSwitched(false);
// = Set signal 1 to green via the Locomotive API
// Why would you do this? See the "Chaining Commands" section
myLoc.setAccessoryState(1, Accessory.accessoryDecoderType.MM2, false);
// Retrieve a switch by its MM2/DCC address
// This assumes that the switch exists within the layout
MarklinAccessory mySwitch = data.getAccessoryByName("Switch 2");
// These two are equivalent
mySwitch.straight();
mySwitch.setSwitched(false);
// These two are equivalent
mySwitch.turn();
mySwitch.setSwitched(true);
// = Set switch 2 to turnout via the Locomotive API
myLoc.setAccessoryState(2, Accessory.accessoryDecoderType.MM2, true);
//
// Feedback
//
// Query the status of S88 feedback with address 1
boolean feedbackStatus = data.getFeedbackState("1");
if (feedbackStatus)
{
System.out.println("Feedback 1 shows occupied");
data.log("Write a message to the log in the UI.");
}
// = Query the status of S88 feedback via the Locomotive API
feedbackStatus = myLoc.isFeedbackSet("1");
feedbackStatus = myLoc.isFeedbackSet(1); // integers are also allowed in the Locomotive API
if (feedbackStatus)
{
System.out.println("Feedback 1 shows occupied");
}
//
// Routes
//
// Lists all routes stored in the CS2/CS3
List<String> routes = data.getRouteList();
// Execute a route by name
data.execRoute("SomeRoute");
// = Execute a route via the Locomotive API
myLoc.execRoute("SomeRoute");
// Routes can be created via the CS2, via the TrainControl UI,
// or by creating a new MarklinRoute object and then calling data.newRoute
//
// Chaining Commands
//
// Commands for a locomotive of accessory can be chained
// This is an easy way to support event-driven behavior on the layout
// For example, this locomotive will first wait for Feedback 1 to show as occupied, and then it will toggle a function and start rolling
myLoc.waitForOccupiedFeedback("1").toggleF(3, 1000).setSpeed(5).delay(1000).setSpeed(0);
// This can be put in a loop if the same logic can be repeated
// to enable "hard-coded" autonomous operation
while (true)
{
// Fetch the locomotive at Station 1
data.getLocByName("Loc1")
// Flip some signals
.setAccessoryState(1, Accessory.accessoryDecoderType.MM2, true)
.setAccessoryState(2, Accessory.accessoryDecoderType.MM2, false)
// Turnout
.setAccessoryState(10, Accessory.accessoryDecoderType.MM2, true)
// Wait 2-20 seconds
.delay(2,20)
// Turn on locomotive sound and lights
.setF(3, true)
.lightsOn()
// Start rolling
.setSpeed(40)
.waitForOccupiedFeedback("3")
// Signal should now be red
.setAccessoryState(1, Accessory.accessoryDecoderType.MM2, false)
// Slow down
.setSpeed(20)
// Stop the locomotive when it arrives at the station
// (S88 address 1)
.waitForOccupiedFeedback("1")
.setSpeed(0);
// Fetch the locomotive at Station 2
data.getLocByName("Loc2")
// Do not proceed unless Loc1 is at its station
.waitForOccupiedFeedback("1")
// Flip some signals
.setAccessoryState(1, Accessory.accessoryDecoderType.MM2, false)
.setAccessoryState(2, Accessory.accessoryDecoderType.MM2, true)
// Go straight
.setAccessoryState(10, Accessory.accessoryDecoderType.MM2, false)
// Wait 2-20 seconds
.delay(2,20)
// Turn on locomotive sound and lights
.setF(3, true)
.lightsOn()
// Start rolling
.setSpeed(40)
.waitForOccupiedFeedback("3")
// Signal should now be red
.setAccessoryState(2, Accessory.accessoryDecoderType.MM2, false)
// Slow down
.setSpeed(20)
// Stop the locomotive when it arrives at the station
// (S88 address 1)
.waitForOccupiedFeedback("2")
.setSpeed(0);
}
});
func.accept(mcs);
}
public static void main(String[] args)
{
// Initialize the central station
try
{
// Initialize with no UI
MarklinControlStation model = init(null, false, false, true, false);
// Or, initialize with a predetermined IP
// MarklinControlStation model = init("192.168.1.10", false, false, true, false);
// Or, initialize with the UI
// MarklinControlStation model = init(null, false, true, true, false);
execCode(model);
}
catch (Exception e)
{
System.out.println("Error occurred: " + e.getMessage());
e.printStackTrace();
System.exit(1);
}
}
}