added decouple and EngageDecoupler action

This commit is contained in:
Stephan Richter
2021-01-15 10:48:32 +01:00
parent 323a48dcd6
commit 0902017bba
12 changed files with 346 additions and 2 deletions

View File

@@ -4,7 +4,6 @@ import de.srsoftware.tools.Tag;
public interface Device {
public static final String ADDRESS = "address";
public static final String PORT = "port";
public static final String PROTOCOL = "proto";
public int address();

View File

@@ -50,6 +50,8 @@ import de.srsoftware.web4rail.tiles.ContactV;
import de.srsoftware.web4rail.tiles.CrossH;
import de.srsoftware.web4rail.tiles.CrossPlus;
import de.srsoftware.web4rail.tiles.CrossV;
import de.srsoftware.web4rail.tiles.DecouplerH;
import de.srsoftware.web4rail.tiles.DecouplerV;
import de.srsoftware.web4rail.tiles.DiagES;
import de.srsoftware.web4rail.tiles.DiagNE;
import de.srsoftware.web4rail.tiles.DiagSW;
@@ -931,6 +933,8 @@ public class Plan extends BaseClass{
new TurnoutLW().tag(null).addTo(tiles);
new TurnoutLE().tag(null).addTo(tiles);
new Turnout3E().tag(null).addTo(tiles);
new DecouplerH().tag(null).addTo(tiles);
new DecouplerV().tag(null).addTo(tiles);
new Relay().setLabel(true,"RL").tag(null).addTo(tiles);
new Contact().tag(null).addTo(tiles);
new TextDisplay().text("tx").tag(null).addTo(tiles);

View File

@@ -48,6 +48,7 @@ public abstract class Action extends BaseClass {
ConditionalAction.class,
DelayedAction.class,
DetermineTrainInBlock.class,
EngageDecoupler.class,
FinishRoute.class,
Loop.class,
PreserveRoute.class,

View File

@@ -0,0 +1,84 @@
package de.srsoftware.web4rail.actions;
import java.util.HashMap;
import java.util.List;
import org.json.JSONObject;
import de.srsoftware.web4rail.Application;
import de.srsoftware.web4rail.BaseClass;
import de.srsoftware.web4rail.Window;
import de.srsoftware.web4rail.tags.Fieldset;
import de.srsoftware.web4rail.tiles.Decoupler;
public class EngageDecoupler extends Action {
private static final String DECOUPLER = Decoupler.class.getSimpleName();
public EngageDecoupler(BaseClass parent) {
super(parent);
}
private Decoupler decoupler = null;
@Override
public boolean fire(Context context) {
if (isNull(decoupler)) return false;
decoupler.engage();
return true;
}
@Override
public JSONObject json() {
JSONObject json = super.json();
if (isSet(decoupler)) {
json.put(Decoupler.class.getSimpleName(), decoupler.id());
}
return json;
}
@Override
public Action load(JSONObject json) {
super.load(json);
if (json.has(DECOUPLER)) {
String decouplerId = json.getString(DECOUPLER);
decoupler = BaseClass.get(new Id(decouplerId));
if (isNull(decoupler)) Application.threadPool.execute(new Thread() { // if relay not loaded, yet: wait one sec and try again
public void run() {
try {
sleep(1000);
} catch (InterruptedException e) {}
decoupler = BaseClass.get(new Id(decouplerId));
};
});
}
return this;
}
@Override
protected Window properties(List<Fieldset> preForm, FormInput formInputs, List<Fieldset> postForm) {
formInputs.add(t("Select decoupler"),Decoupler.selector(decoupler,null));
return super.properties(preForm, formInputs, postForm);
}
@Override
protected void removeChild(BaseClass child) {
if (child == decoupler) decoupler = null;
super.removeChild(child);
}
public String toString() {
if (isNull(decoupler)) return "["+t("Click here to setup decoupler")+"]";
return t("Engage {}",decoupler);
};
@Override
protected Object update(HashMap<String, String> params) {
LOG.debug("update: {}",params);
Id decouplerId = new Id(params.get(DECOUPLER));
decoupler = BaseClass.get(decouplerId);
return context().properties();
}
}

View File

@@ -0,0 +1,174 @@
package de.srsoftware.web4rail.tiles;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.TimeoutException;
import org.json.JSONObject;
import de.srsoftware.tools.Tag;
import de.srsoftware.web4rail.BaseClass;
import de.srsoftware.web4rail.Command;
import de.srsoftware.web4rail.Command.Reply;
import de.srsoftware.web4rail.Device;
import de.srsoftware.web4rail.Protocol;
import de.srsoftware.web4rail.Window;
import de.srsoftware.web4rail.tags.Fieldset;
import de.srsoftware.web4rail.tags.Input;
import de.srsoftware.web4rail.tags.Radio;
import de.srsoftware.web4rail.tags.Select;
public abstract class Decoupler extends Tile implements Device{
protected int address = 0;
private Protocol protocol = Protocol.DCC128;
protected int port = 0;
private boolean initialized = false;
@Override
public int address() {
return address;
}
@Override
public Object click() throws IOException {
Object o = super.click();
engage();
return o;
}
public Reply engage() {
Reply reply = init();
if (reply != null && !reply.succeeded()) return reply;
try {
return plan.queue(new Command("SET {} GA "+address+" "+port+" 1 "+100) {
@Override
public void onSuccess() {
super.onSuccess();
plan.place(Decoupler.this);
}
@Override
protected void onFailure(Reply reply) {
super.onFailure(reply);
plan.stream(t("Unable to engage \"{}\": {}",Decoupler.this,reply.message()));
}
}).reply();
} catch (TimeoutException e) {
LOG.warn(e.getMessage());
}
return new Reply(417,t("Timeout while trying to switch {}.",this));
}
protected Reply init() {
if (address == 0) return new Reply(200,"OK");
if (!initialized) {
Command command = new Command("INIT {} GA "+address+" "+proto()) {
@Override
public void onSuccess() {
super.onSuccess();
initialized = true;
}
@Override
public void onFailure(Reply r) {
super.onFailure(r);
initialized = false;
}
};
try {
return plan.queue(command).reply();
} catch (TimeoutException e) {
LOG.warn(e.getMessage());
}
}
return new Reply(200, "OK");
}
@Override
public JSONObject json() {
JSONObject json = super.json();
json.put(PROTOCOL, protocol);
if (address != 0) json.put(ADDRESS, address);
json.put(PORT, port);
return json;
}
@Override
public Tile load(JSONObject json) {
if (json.has(ADDRESS)) address = json.getInt(ADDRESS);
if (json.has(PROTOCOL)) protocol = Protocol.valueOf(json.getString(PROTOCOL));
if (json.has(PORT)) port = json.getInt(PORT);
return super.load(json);
}
@Override
protected Window properties(List<Fieldset> preForm, FormInput formInputs, List<Fieldset> postForm) {
Tag div = new Tag("div");
for (Protocol proto : Protocol.values()) {
new Radio(PROTOCOL, proto.toString(), t(proto.toString()), proto == protocol).addTo(div);
}
formInputs.add(t("Protocol"),div);
formInputs.add(t("Address:"),new Input(ADDRESS, address).numeric());
formInputs.add(t("Port:"),new Input(PORT, port).numeric());
return super.properties(preForm, formInputs, postForm);
}
private char proto() {
switch (protocol) {
case DCC14:
case DCC27:
case DCC28:
case DCC128:
return 'N';
case MOTO:
return 'M';
case SELECTRIX:
return 'S';
default:
return 'P';
}
}
public static Select selector(Decoupler preselected, Collection<Decoupler> exclude) {
if (isNull(exclude)) exclude = new Vector<Decoupler>();
Select select = new Select(Decoupler.class.getSimpleName());
new Tag("option").attr("value","0").content(t("unset")).addTo(select);
for (Decoupler decoupler : BaseClass.listElements(Decoupler.class)) {
if (exclude.contains(decoupler)) continue;
Tag opt = select.addOption(decoupler.id(), decoupler);
if (decoupler == preselected) opt.attr("selected", "selected");
}
return select;
}
@Override
public Tile update(HashMap<String, String> params) {
if (params.containsKey(PROTOCOL)) protocol = Protocol.valueOf(params.get(PROTOCOL));
if (params.containsKey(ADDRESS)) {
int newAddress = Integer.parseInt(params.get(ADDRESS));
if (newAddress != address) {
initialized = false;
address = newAddress;
}
}
String newPort = params.get(PORT);
if (isSet(newPort)) {
int npa = Integer.parseInt(newPort);
if (npa != port) {
port = npa;
initialized = false;
}
}
return super.update(params);
}
}

View File

@@ -0,0 +1,30 @@
package de.srsoftware.web4rail.tiles;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import de.srsoftware.web4rail.Connector;
import de.srsoftware.web4rail.Plan.Direction;
import de.srsoftware.web4rail.tiles.Turnout.State;
public class DecouplerH extends Decoupler{
@Override
public Map<Connector, State> connections(Direction from) {
if (isNull(from) || oneWay == from) return new HashMap<>();
switch (from) {
case WEST:
return Map.of(new Connector(x+width(),y,Direction.WEST),State.UNDEF);
case EAST:
return Map.of(new Connector(x-1,y,Direction.EAST),State.UNDEF);
default:
return new HashMap<>();
}
}
@Override
public List<Direction> possibleDirections() {
return List.of(Direction.EAST,Direction.WEST);
}
}

View File

@@ -0,0 +1,30 @@
package de.srsoftware.web4rail.tiles;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import de.srsoftware.web4rail.Connector;
import de.srsoftware.web4rail.Plan.Direction;
import de.srsoftware.web4rail.tiles.Turnout.State;
public class DecouplerV extends Decoupler{
@Override
public Map<Connector, State> connections(Direction from) {
if (isNull(from) || oneWay == from) return new HashMap<>();
switch (from) {
case NORTH:
return Map.of(new Connector(x+width(),y,Direction.NORTH),State.UNDEF);
case SOUTH:
return Map.of(new Connector(x-1,y,Direction.SOUTH),State.UNDEF);
default:
return new HashMap<>();
}
}
@Override
public List<Direction> possibleDirections() {
return List.of(Direction.SOUTH,Direction.NORTH);
}
}

View File

@@ -24,6 +24,7 @@ import de.srsoftware.web4rail.Connector;
import de.srsoftware.web4rail.PathFinder;
import de.srsoftware.web4rail.Plan;
import de.srsoftware.web4rail.Plan.Direction;
import de.srsoftware.web4rail.actions.AlterDirection;
import de.srsoftware.web4rail.Route;
import de.srsoftware.web4rail.Window;
import de.srsoftware.web4rail.moving.Train;
@@ -195,6 +196,9 @@ public abstract class Tile extends BaseClass implements Comparable<Tile>{
if (object instanceof JSONObject) {
JSONObject json = (JSONObject) object;
String clazz = json.getString(TYPE);
if (clazz.equals("TurnTrain")) {
clazz = AlterDirection.class.getSimpleName();
}
try {
Tile.inflate(clazz,json,plan);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException | ClassNotFoundException | IOException e) {