Browse Source

working on autorouting and turnout code

lookup-tables
Stephan Richter 5 years ago
parent
commit
f5dbb0916a
  1. 8
      resources/css/style.css
  2. 18
      resources/js/plan.js
  3. 2
      src/main/java/de/srsoftware/web4rail/Application.java
  4. 4
      src/main/java/de/srsoftware/web4rail/Plan.java
  5. 1
      src/main/java/de/srsoftware/web4rail/Route.java
  6. 42
      src/main/java/de/srsoftware/web4rail/moving/Train.java
  7. 6
      src/main/java/de/srsoftware/web4rail/tiles/Tile.java
  8. 35
      src/main/java/de/srsoftware/web4rail/tiles/Turnout.java
  9. 20
      src/main/java/de/srsoftware/web4rail/tiles/TurnoutL.java
  10. 11
      src/main/java/de/srsoftware/web4rail/tiles/TurnoutR.java

8
resources/css/style.css

@ -175,9 +175,9 @@ h2{
width: 15px; width: 15px;
height: 15px; height: 15px;
background: lime; background: lime;
position: absolute; position: fixed;
top: 10px; top: 10px;
right: 10px; left: 10px;
display: none; display: none;
} }
@ -206,3 +206,7 @@ fieldset{
border: 1px solid black; border: 1px solid black;
border-radius: 5px; border-radius: 5px;
} }
.error{
background: red;
}

18
resources/js/plan.js

@ -1,14 +1,14 @@
const ADD = 'add'; const ADD = 'add';
const MOVE = 'move';
const SQUARE = 30;
const BODY = 'body'; const BODY = 'body';
const CU = 'cu';
const DIV = 'DIV'; const DIV = 'DIV';
const SVG = 'svg'; const MOVE = 'move';
const OPAC = 100;
const PLAN = '#plan'; const PLAN = '#plan';
const POST = 'POST'; const POST = 'POST';
const PROPS = 'props'; const PROPS = 'props';
const CU = 'cu'; const SQUARE = 30;
const OPAC = 100; const SVG = 'svg';
var selected = null; var selected = null;
var mode = null; var mode = null;
var messageTimer = null; var messageTimer = null;
@ -157,6 +157,7 @@ function request(data){
data : data, data : data,
success: function(resp){ success: function(resp){
if (data.realm != 'car' && data.realm != 'loco') closeWindows(); if (data.realm != 'car' && data.realm != 'loco') closeWindows();
if (resp.startsWith('<html')) return;
if (resp.startsWith('<svg')){ if (resp.startsWith('<svg')){
$(PLAN).append($(resp)); $(PLAN).append($(resp));
} else if (resp.startsWith('<')) { } else if (resp.startsWith('<')) {
@ -187,12 +188,17 @@ function runAction(ev){
function stream(ev){ function stream(ev){
var data = ev.data; var data = ev.data;
//console.log("received: ",data); console.log("received: ",data);
if (data.startsWith('<svg')) {
$(PLAN).append($(data));
return false;
}
if (data.startsWith("heartbeat")) return heartbeat(data); if (data.startsWith("heartbeat")) return heartbeat(data);
if (data.startsWith("place ")) return place(data.substring(6)); if (data.startsWith("place ")) return place(data.substring(6));
if (data.startsWith("remove")) return remove(data.substring(7)); if (data.startsWith("remove")) return remove(data.substring(7));
if (data.startsWith("addclass")) return addClass(data.substring(9)); if (data.startsWith("addclass")) return addClass(data.substring(9));
if (data.startsWith("dropclass")) return dropClass(data.substring(10)); if (data.startsWith("dropclass")) return dropClass(data.substring(10));
addMessage(data);
} }
function swapTiling(ev){ function swapTiling(ev){

2
src/main/java/de/srsoftware/web4rail/Application.java

@ -72,7 +72,7 @@ public class Application implements Constants{
case REALM_ROUTE: case REALM_ROUTE:
return plan.routeAction(params); return plan.routeAction(params);
case REALM_TRAIN: case REALM_TRAIN:
return Train.action(params); return Train.action(params,plan);
} }
return t("Unknown realm: {}",params.get(REALM)); return t("Unknown realm: {}",params.get(REALM));

4
src/main/java/de/srsoftware/web4rail/Plan.java

@ -250,7 +250,7 @@ public class Plan implements Constants{
LOG.warn("Was not able to load cars!",e); LOG.warn("Was not able to load cars!",e);
} }
try { try {
Train.loadAll(filename+".trains"); Train.loadAll(filename+".trains",plan);
} catch (Exception e) { } catch (Exception e) {
LOG.warn("Was not able to load trains!",e); LOG.warn("Was not able to load trains!",e);
} }
@ -437,7 +437,7 @@ public class Plan implements Constants{
public synchronized void stream(String data) { public synchronized void stream(String data) {
data = data.replaceAll("\n", "").replaceAll("\r", ""); data = data.replaceAll("\n", "").replaceAll("\r", "");
//LOG.debug("streaming: {}",data); //if (!data.startsWith("heartbeat")) LOG.debug("streaming: {}",data);
Vector<OutputStreamWriter> badClients = null; Vector<OutputStreamWriter> badClients = null;
for (Entry<OutputStreamWriter, Integer> entry : clients.entrySet()) { for (Entry<OutputStreamWriter, Integer> entry : clients.entrySet()) {
OutputStreamWriter client = entry.getKey(); OutputStreamWriter client = entry.getKey();

1
src/main/java/de/srsoftware/web4rail/Route.java

@ -309,6 +309,7 @@ public class Route implements Constants{
CompletableFuture<Reply> reply = entry.getKey().state(entry.getValue()); // switching a turnout is an asynchronous process, so it returns a CompletableFuture here CompletableFuture<Reply> reply = entry.getKey().state(entry.getValue()); // switching a turnout is an asynchronous process, so it returns a CompletableFuture here
promise = promise == null ? reply : promise.thenCombine(reply, (a,b) -> a); promise = promise == null ? reply : promise.thenCombine(reply, (a,b) -> a);
} }
if (promise == null) promise = CompletableFuture.completedFuture(null);
promise.exceptionally(ex -> { promise.exceptionally(ex -> {
for (Tile tile : locked) try { for (Tile tile : locked) try {
tile.unlock(); tile.unlock();

42
src/main/java/de/srsoftware/web4rail/moving/Train.java

@ -12,7 +12,6 @@ import java.util.HashSet;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Random; import java.util.Random;
import java.util.Vector; import java.util.Vector;
import java.util.concurrent.CompletableFuture;
import org.json.JSONObject; import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -22,6 +21,7 @@ import de.keawe.tools.translations.Translation;
import de.srsoftware.tools.Tag; import de.srsoftware.tools.Tag;
import de.srsoftware.web4rail.Application; import de.srsoftware.web4rail.Application;
import de.srsoftware.web4rail.Constants; import de.srsoftware.web4rail.Constants;
import de.srsoftware.web4rail.Plan;
import de.srsoftware.web4rail.Plan.Direction; import de.srsoftware.web4rail.Plan.Direction;
import de.srsoftware.web4rail.Route; import de.srsoftware.web4rail.Route;
import de.srsoftware.web4rail.Window; import de.srsoftware.web4rail.Window;
@ -99,6 +99,8 @@ public class Train implements Constants {
public int speed = 0; public int speed = 0;
private Autopilot autopilot = null; private Autopilot autopilot = null;
private Plan plan;
public Train(Locomotive loco) { public Train(Locomotive loco) {
this(loco,null); this(loco,null);
} }
@ -110,7 +112,7 @@ public class Train implements Constants {
trains.put(id, this); trains.put(id, this);
} }
public static Object action(HashMap<String, String> params) throws IOException { public static Object action(HashMap<String, String> params, Plan plan) throws IOException {
String action = params.get(ACTION); String action = params.get(ACTION);
if (action == null) return t("No action passed to Train.action!"); if (action == null) return t("No action passed to Train.action!");
if (!params.containsKey(Train.ID)) { if (!params.containsKey(Train.ID)) {
@ -118,7 +120,7 @@ public class Train implements Constants {
case ACTION_PROPS: case ACTION_PROPS:
return manager(); return manager();
case ACTION_ADD: case ACTION_ADD:
return create(params); return create(params,plan);
} }
return t("No train id passed!"); return t("No train id passed!");
} }
@ -140,10 +142,10 @@ public class Train implements Constants {
return t("Unknown action: {}",params.get(ACTION)); return t("Unknown action: {}",params.get(ACTION));
} }
private static Object create(HashMap<String, String> params) { private static Object create(HashMap<String, String> params, Plan plan) {
Locomotive loco = (Locomotive) Locomotive.get(params.get(Train.LOCO_ID)); Locomotive loco = (Locomotive) Locomotive.get(params.get(Train.LOCO_ID));
if (loco == null) return t("unknown locomotive: {}",params.get(ID)); if (loco == null) return t("unknown locomotive: {}",params.get(ID));
Train train = new Train(loco); Train train = new Train(loco).plan(plan);
if (params.containsKey(NAME)) train.name(params.get(NAME)); if (params.containsKey(NAME)) train.name(params.get(NAME));
return train; return train;
} }
@ -215,7 +217,7 @@ public class Train implements Constants {
return trains.values(); return trains.values();
} }
public static void loadAll(String filename) throws IOException { public static void loadAll(String filename, Plan plan) throws IOException {
BufferedReader file = new BufferedReader(new FileReader(filename)); BufferedReader file = new BufferedReader(new FileReader(filename));
String line = file.readLine(); String line = file.readLine();
while (line != null) { while (line != null) {
@ -224,18 +226,19 @@ public class Train implements Constants {
long id = json.getLong(ID); long id = json.getLong(ID);
Train train = new Train(null,id); Train train = new Train(null,id);
train.load(json); train.load(json).plan(plan);
line = file.readLine(); line = file.readLine();
} }
file.close(); file.close();
} }
private void load(JSONObject json) { private Train load(JSONObject json) {
pushPull = json.getBoolean(PUSH_PULL); pushPull = json.getBoolean(PUSH_PULL);
if (json.has(NAME)) name = json.getString(NAME); if (json.has(NAME)) name = json.getString(NAME);
for (Object id : json.getJSONArray(CARS)) add(Car.get((String)id)); for (Object id : json.getJSONArray(CARS)) add(Car.get((String)id));
for (Object id : json.getJSONArray(LOCOS)) add((Locomotive) Car.get((String)id)); for (Object id : json.getJSONArray(LOCOS)) add((Locomotive) Car.get((String)id));
return this;
} }
public static Object manager() { public static Object manager() {
@ -278,6 +281,11 @@ public class Train implements Constants {
return result; return result;
} }
private Train plan(Plan plan) {
this.plan = plan;
return this;
}
public Tag props() { public Tag props() {
Window window = new Window("train-properties",t("Properties of {}",getClass().getSimpleName())); Window window = new Window("train-properties",t("Properties of {}",getClass().getSimpleName()));
@ -310,6 +318,9 @@ public class Train implements Constants {
actions.addTo(list); actions.addTo(list);
} }
if (route != null) {
new Tag("li").content(t("Current route: {}",route)).addTo(list);
}
if (direction != null) new Tag("li").content(t("Direction: heading {}",direction)).addTo(list); if (direction != null) new Tag("li").content(t("Direction: heading {}",direction)).addTo(list);
@ -332,8 +343,8 @@ public class Train implements Constants {
this.speed = v; this.speed = v;
} }
public CompletableFuture<String> start() throws IOException { public String start() throws IOException {
if (block == null) return CompletableFuture.failedFuture(new RuntimeException(t("{} not in a block",this))); if (block == null) return t("{} not in a block",this);
if (route != null) route.unlock().setSignals(Signal.STOP); if (route != null) route.unlock().setSignals(Signal.STOP);
HashSet<Route> routes = block.routes(); HashSet<Route> routes = block.routes();
Vector<Route> availableRoutes = new Vector<Route>(); Vector<Route> availableRoutes = new Vector<Route>();
@ -352,9 +363,10 @@ public class Train implements Constants {
availableRoutes.add(rt); availableRoutes.add(rt);
} }
Random rand = new Random(); Random rand = new Random();
if (availableRoutes.isEmpty()) return CompletableFuture.failedFuture(new RuntimeException(t("No free routes from {}",block))); if (availableRoutes.isEmpty()) return t("No free routes from {}",block);
route = availableRoutes.get(rand.nextInt(availableRoutes.size())); route = availableRoutes.get(rand.nextInt(availableRoutes.size()));
return route.lock(this).thenApply(reply -> {
route.lock(this).thenApply(reply -> {
try { try {
route.setSignals(null); route.setSignals(null);
if (direction != route.startDirection) turn(); if (direction != route.startDirection) turn();
@ -363,7 +375,13 @@ public class Train implements Constants {
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
}).thenAccept(message -> plan.stream(message))
.exceptionally(ex -> {
plan.stream(ex.getMessage());
throw new RuntimeException(ex);
}); });
return t("Trying to start {}",this);
} }
private Object stop() { private Object stop() {

6
src/main/java/de/srsoftware/web4rail/tiles/Tile.java

@ -322,10 +322,16 @@ public abstract class Tile implements Constants{
.content("?") .content("?")
.addTo(svg); .addTo(svg);
} }
String title = title();
if (title!=null) new Tag("title").content(title()).addTo(svg);
return svg; return svg;
} }
public String title() {
return null;
}
@Override @Override
public String toString() { public String toString() {
return t("{}({},{})",getClass().getSimpleName(),x,y) ; return t("{}({},{})",getClass().getSimpleName(),x,y) ;

35
src/main/java/de/srsoftware/web4rail/tiles/Turnout.java

@ -24,9 +24,10 @@ public abstract class Turnout extends Tile implements Device{
private Protocol protocol = Protocol.DCC128; private Protocol protocol = Protocol.DCC128;
protected int address = 0; protected int address = 0;
protected int portA = 0, portB = 0; protected int portA = 0, portB = 1;
protected int delay = 400; protected int delay = 400;
protected boolean initialized; protected boolean initialized = false;
protected boolean error = false;
public enum State{ public enum State{
LEFT,STRAIGHT,RIGHT,UNDEF; LEFT,STRAIGHT,RIGHT,UNDEF;
@ -36,11 +37,21 @@ public abstract class Turnout extends Tile implements Device{
@Override @Override
public Object click() throws IOException { public Object click() throws IOException {
LOG.debug("Turnout.click()"); LOG.debug(getClass().getSimpleName()+".click()");
init(); init();
return super.click(); return super.click();
} }
public void error(Reply reply) {
this.error = true;
try {
plan.stream(tag(null).toString());
} catch (IOException e) {
LOG.error("Was not able to stream: ",e);
}
throw new RuntimeException(reply.message());
}
protected void init() { protected void init() {
if (!initialized) { if (!initialized) {
plan.queue("INIT {} GA "+address+" "+proto()); plan.queue("INIT {} GA "+address+" "+proto());
@ -52,7 +63,7 @@ public abstract class Turnout extends Tile implements Device{
public JSONObject json() { public JSONObject json() {
JSONObject json = super.json(); JSONObject json = super.json();
if (portA != 0) json.put(PORT_A, portA); if (portA != 0) json.put(PORT_A, portA);
if (portB != 0) json.put(PORT_B, portB); if (portB != 1) json.put(PORT_B, portB);
if (address != 0) json.put(ADDRESS, address); if (address != 0) json.put(ADDRESS, address);
json.put(PROTOCOL, protocol); json.put(PROTOCOL, protocol);
return json; return json;
@ -102,13 +113,27 @@ public abstract class Turnout extends Tile implements Device{
public abstract CompletableFuture<Reply> state(State newState) throws IOException; public abstract CompletableFuture<Reply> state(State newState) throws IOException;
public void success() {
this.error = false;
try {
plan.stream(tag(null).toString());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override @Override
public Tag tag(Map<String, Object> replacements) throws IOException { public Tag tag(Map<String, Object> replacements) throws IOException {
Tag tag = super.tag(replacements); Tag tag = super.tag(replacements);
tag.clazz(tag.get("class")+(" "+state).toLowerCase()); tag.clazz(tag.get("class")+(" "+state).toLowerCase()+(error?" error":""));
return tag; return tag;
} }
@Override
public String title() {
return getClass().getSimpleName()+t("(Address: {}, Ports {} and {})",address,portA,portB);
}
public void toggle() { public void toggle() {
state = State.STRAIGHT; state = State.STRAIGHT;
} }

20
src/main/java/de/srsoftware/web4rail/tiles/TurnoutL.java

@ -16,7 +16,6 @@ public class TurnoutL extends Turnout {
@Override @Override
public Object click() throws IOException { public Object click() throws IOException {
LOG.debug("TurnoutL.click()");
Object o = super.click(); Object o = super.click();
if (route != null) { if (route != null) {
plan.stream(t("{} is locked by {}!",this,route)); plan.stream(t("{} is locked by {}!",this,route));
@ -45,13 +44,6 @@ public class TurnoutL extends Turnout {
return form; return form;
} }
@Override
public Tile update(HashMap<String, String> params) throws IOException {
if (params.containsKey(STRAIGHT)) portA = Integer.parseInt(params.get(STRAIGHT));
if (params.containsKey(LEFT)) portB = Integer.parseInt(params.get(LEFT));
return super.update(params);
}
@Override @Override
public CompletableFuture<Reply> state(State newState) throws IOException { public CompletableFuture<Reply> state(State newState) throws IOException {
init(); init();
@ -68,10 +60,18 @@ public class TurnoutL extends Turnout {
throw new IllegalStateException(); throw new IllegalStateException();
} }
return result.thenApply(reply -> { return result.thenApply(reply -> {
LOG.debug("{} received {}",TurnoutL.this,reply); LOG.debug("{} received {}",getClass().getSimpleName(),reply);
if (!reply.is(200)) throw new RuntimeException(reply.message()); if (!reply.is(200)) error(reply);
state = newState; state = newState;
success();
return reply; return reply;
}); });
} }
@Override
public Tile update(HashMap<String, String> params) throws IOException {
if (params.containsKey(STRAIGHT)) portA = Integer.parseInt(params.get(STRAIGHT));
if (params.containsKey(LEFT)) portB = Integer.parseInt(params.get(LEFT));
return super.update(params);
}
} }

11
src/main/java/de/srsoftware/web4rail/tiles/TurnoutR.java

@ -16,7 +16,6 @@ public class TurnoutR extends Turnout {
@Override @Override
public Object click() throws IOException { public Object click() throws IOException {
LOG.debug("Turnoutr.click()");
Object o = super.click(); Object o = super.click();
if (route != null) { if (route != null) {
plan.stream(t("{} is locked by {}!",this,route)); plan.stream(t("{} is locked by {}!",this,route));
@ -34,8 +33,8 @@ public class TurnoutR extends Turnout {
break; break;
} }
} }
new Input(STRAIGHT, portA).addTo(new Label(t("Straight port"))).addTo(fieldset); new Input(STRAIGHT, portA).numeric().addTo(new Label(t("Straight port"))).addTo(fieldset);
new Input(RIGHT, portB).addTo(new Label(t("Right port"))).addTo(fieldset); new Input(RIGHT, portB).numeric().addTo(new Label(t("Right port"))).addTo(fieldset);
return form; return form;
} }
@ -62,8 +61,10 @@ public class TurnoutR extends Turnout {
throw new IllegalStateException(); throw new IllegalStateException();
} }
return result.thenApply(reply -> { return result.thenApply(reply -> {
LOG.debug("{} received {}",reply); LOG.debug("{} received {}",getClass().getSimpleName(),reply);
if (reply.is(200)) state = newState; if (!reply.is(200)) error(reply);
state = newState;
success();
return reply; return reply;
}); });
} }

Loading…
Cancel
Save