package oebb; /** * Logic.java: Logic for OEBB project. * * Author: Martin Schoeberl (martin.schoeberl@chello.at) * * Changelog: * */ import util.*; import joprt.*; import ejip.*; public class Logic extends RtThread { // values for state static final int DL_CHECK = -1; static final int ANM_WAIT = 19; static final int DEAKT = 18; static final int ES_VERSCHUB = 17; static final int ES_RDY = 16; static final int ALARM = 15; static final int ES221 = 14; static final int LERN = 13; static final int INFO = 12; static final int ZIEL = 11; static final int NOTHALT_OK = 10; static final int NOTHALT = 9; static final int ABGEMELDET = 8; static final int WIDERRUF_OK = 7; static final int WIDERRUF = 6; static final int ERLAUBNIS = 5; static final int ANM_OK = 4; static final int FDL_CONN = 3; static final int CONNECT = 2; static final int GPS_OK = 1; static final int INIT = 0; /** * State of the Logic */ volatile static int state; /** * We are in a manual mode */ volatile boolean hilfsbtr; /** * Next state after alarm quit. */ private int stateAfterQuit; private LinkLayer ipLink; private boolean connSent; private boolean checkMelnr; /** * Richtungsueberwachung */ private boolean checkDirection; /** * Bewegungsueberwachung bei keiner Fahrerlaubnis */ private boolean checkMove; /** * Verschub is active and not canceled by pressing 'C'. */ private boolean isVerschub; private int alarmType; private boolean alarmZielQuit; private boolean alarmFaehrtQuit; private boolean alarmRichtungQuit; private boolean alarmMlrQuit; private int[] buf; // length is one display line without status character private static final int BUF_LEN = 19; private String[] mnuBereit; private static final int MNU_BEREIT_CNT = 2; private String[] mnuTxt; private static final int MNU_CNT = 8; private String[] mnuESTxt; private static final int MNU_ES_CNT = 3; private String bsyIndication; private StringBuffer tmpStr; static final int DL_STRNR = 999; static final int DL_TIMEOUT = 60; static final int CHECK_TIMEOUT = 3; static boolean dlChecked; Logic(int prio, int period, LinkLayer ipl) { super(prio, period); ipLink = ipl; init(); } private void init() { buf = new int[BUF_LEN]; mnuBereit = new String[MNU_BEREIT_CNT]; mnuBereit[0] = "Deaktivieren"; mnuBereit[1] = "Neustart"; mnuTxt = new String[MNU_CNT]; mnuTxt[0] = "Ankunft"; mnuTxt[1] = "Verlassen"; mnuTxt[2] = "Infobetrieb"; mnuTxt[3] = "Lernbetrieb"; mnuTxt[4] = "Umschalten -> ES221"; mnuTxt[5] = "Neustart"; mnuTxt[6] = "Hilfsbetrieb"; mnuTxt[7] = "Fahrerlaubnis"; mnuESTxt = new String[MNU_ES_CNT]; mnuESTxt[0] = "Haltepunkt"; mnuESTxt[1] = "Verschub"; mnuESTxt[2] = "Neustart"; bsyIndication = "+*"; tmpStr = new StringBuffer(200); Status.dirMutex = new Object(); initVals(); } private void initVals() { System.out.println("Logic.initVals()"); Logic.state = Logic.INIT; dlChecked = false; Status.selectStr = false; Status.doCommAlarm = false; Status.direction = Gps.DIR_UNKNOWN; Status.dispMenu = false; hilfsbtr = false; stateAfterQuit = Logic.state; connSent = false; checkMelnr = false; checkMove = false; checkDirection = false; Status.esMode = false; } public void run() { int old_state = Logic.state; for (;;) { // // Beep on every change // if (Logic.state != old_state) { Led.shortBeep(); old_state = Logic.state; } if (Status.commErr!=0) { commError(); } else if (Status.dispMenu) { menu(); } else if (Main.state.isDownloading() && Logic.state!=ES221 && Logic.state!=ES_RDY && !Status.esMode) { download(); } else { switch (Logic.state) { case Logic.DL_CHECK: queryDownload(); break; case Logic.INIT: waitForGps(); break; case Logic.GPS_OK: bereit(); break; case Logic.CONNECT: startConn(); break; case Logic.FDL_CONN: anmelden(); break; case Logic.ANM_WAIT: anmeldenWait(); break; case Logic.ANM_OK: if (Status.esMode) { // we get into ANM_OK after an alarm the removes // our Fahrerlaubnis Logic.state = Logic.ES_RDY; } else { Display.write("Anmeldung OK", "", ""); } break; case Logic.ERLAUBNIS: // load the names with the known direction // TODO: with additional points we can avoid this Flash.loadStrNames(Main.state.strnr, Main.state.start, Main.state.end); erlaubnis(); break; case Logic.WIDERRUF: widerruf(); break; case Logic.NOTHALT: nothalt(); break; case Logic.NOTHALT_OK: Display.write("Nothalt OK", "", ""); break; case Logic.ABGEMELDET: abmelden(); break; case Logic.ZIEL: ziel(); break; case Logic.INFO: info(); break; case Logic.LERN: lern(); break; case Logic.ES221: es221(); break; case Logic.ALARM: alarm(); break; case Logic.ES_RDY: esRdy(); break; case Logic.ES_VERSCHUB: esVerschub(); break; case Logic.DEAKT: deakt(); break; default: Display.write(0, "STATE "); Display.intVal(40, Logic.state); } } loop(); } } /** * update display status, wait period and * check for ATC condition. */ private boolean loop() { waitForNextPeriod(); // // set status in display // Display.setInetOk(ipLink.getIpAddress()!=0 && Status.connOk); Display.setHbOk(hilfsbtr); Display.setGpsOk(Gps.fix>0); Display.setDgpsOk(Gps.fix==2); // reset Hilfsbetrieb when connection is ok // and ignore flag is not set if (Status.connOk && !State.ignore) { // TODO some synchronization? hilfsbtr = false; } // // do the LED and Beep thing // Led.loop(); // // update Timer // Timer.loop(); if (Status.commErr != 0) { // some async message should be displayed (like comm err, Nothalt...) return false; } if (Keyboard.peek()==Keyboard.B) { if (!Status.dispMenu) { Keyboard.rd(); Status.dispMenu = true; return false; } } updateStates(); if (!check()) return false; // Dbg.intVal(com.jopdesign.sys.Native.getSP()); return true; } /** * Send a postion change event from State. * Reset alarm quit fields. */ void posChanged() { alarmFaehrtQuit = false; alarmRichtungQuit = false; alarmZielQuit = false; alarmMlrQuit = false; } /** * 'calculate' what to check from the state we are in. * */ private void updateStates() { if (Main.state.getPos()>0) { Flash.Point p = Flash.getPoint(Main.state.getPos()); if (p!=null) { checkDirection = p.checkDirection; // Stillstand: Enable checkMove if (Gps.speed<Gps.MIN_SPEED && Logic.state!=Logic.ERLAUBNIS) { checkMove = p.checkMove; } } } if (Logic.state!=Logic.ERLAUBNIS) { checkDirection = false; } } /** * Check for error conditions. */ private boolean check() { State state = Main.state; int pos, start, end; // TODO: use the following locals for the checks synchronized (state) { pos = state.getPos(); start = state.start; end = state.end; } // // check for MelNr range and direction // direction check also in ZIEL // if (checkMelnr && !isVerschub && Logic.state!=Logic.ALARM && pos!=-1) { synchronized (Status.dirMutex) { if (Status.direction==Gps.DIR_UNKNOWN) { if (Main.state.end > Main.state.start) { // going from left to right. Status.direction = Gps.DIR_FORWARD; } else if (Main.state.end < Main.state.start) { // going from left to right. Status.direction = Gps.DIR_BACK; } } } if (Status.direction==Gps.DIR_FORWARD) { // going from left to rigth. // check direction with melnr if (checkDirection && pos<Main.state.start && !alarmRichtungQuit) { // FERL bleibt stateAfterQuit = Logic.state; Logic.state = Logic.ALARM; alarmType = State.ALARM_RICHTUNG; return false; } // check melnr in the other direction if (pos<Main.state.start && Main.state.start!=0 && !alarmMlrQuit) { stateAfterQuit = Logic.state; Logic.state = Logic.ALARM; alarmType = State.ALARM_MLR; return false; } // check Melderaum Ziel // if (Main.state.pos<Main.state.start || Main.state.pos>Main.state.end) { // change 13.12.2006 - Ziel only in the direction if (pos>Main.state.end && Main.state.end!=0 && !alarmZielQuit) { stateAfterQuit = Logic.state; Logic.state = Logic.ALARM; alarmType = State.ALARM_UEBERF; return false; } // check direction if (checkDirection && Gps.direction==Gps.DIR_BACK && !(state.type==State.TYPE_NF && pos==Main.state.end) &&!alarmRichtungQuit) { // FERL bleibt stateAfterQuit = Logic.state; Logic.state = Logic.ALARM; alarmType = State.ALARM_RICHTUNG; return false; } } else { // going from right to left // check direction with melnr if (checkDirection && pos>Main.state.start && !alarmRichtungQuit) { // FERL bleibt stateAfterQuit = Logic.state; Logic.state = Logic.ALARM; alarmType = State.ALARM_RICHTUNG; return false; } // check melnr in the other direction if (pos>Main.state.start && Main.state.start!=0 && !alarmMlrQuit) { stateAfterQuit = Logic.state; Logic.state = Logic.ALARM; alarmType = State.ALARM_MLR; return false; } // check Melderaum // change 13.12.2006 - Ziel only in the direction // if (Main.state.pos>Main.state.start || Main.state.pos<Main.state.end) { if (pos<Main.state.end && Main.state.end!=0 && !alarmZielQuit) { stateAfterQuit = Logic.state; Logic.state = Logic.ALARM; alarmType = State.ALARM_UEBERF; return false; } // check direction if (checkDirection && Gps.direction==Gps.DIR_FORWARD && !(state.type==State.TYPE_NF && pos==Main.state.end) && !alarmRichtungQuit) { stateAfterQuit = Logic.state; // FERL bleibt // stateAfterQuit = Status.ANM_OK; Logic.state = Logic.ALARM; alarmType = State.ALARM_RICHTUNG; return false; } } } // every state different form Erlaubnis/Verschub.. check moving // except Verschub, Info, Lern, NOTHALT (?...?) if (!isVerschub && Logic.state!=Logic.ALARM && Logic.state!=Logic.NOTHALT && Logic.state!=Logic.NOTHALT_OK && Logic.state!=Logic.INFO && Logic.state!=Logic.LERN && Logic.state!=Logic.ES_VERSCHUB && checkMove && Gps.speed>Gps.MIN_SPEED && !alarmFaehrtQuit && // the following should not be necessary, but for sure start==end) { stateAfterQuit = Logic.state; Logic.state = Logic.ALARM; alarmType = State.ALARM_FAEHRT; checkMove = false; // disable further Alarms return false; } // check Verschub if (isVerschub && Logic.state!=Logic.ALARM && !alarmMlrQuit) { if (pos>end || pos<start) { Logic.state = Logic.ALARM; alarmType = State.ALARM_MLR; isVerschub = false; // clear Verschub stateAfterQuit = Logic.FDL_CONN; return false; } } // // Ziel erreicht // if (Logic.state == Logic.ERLAUBNIS && pos == Main.state.end && (state.type==State.TYPE_ZUG || state.type==State.TYPE_ES221)) { Logic.state = Logic.ZIEL; if (Status.connOk) { Main.state.sendZiel(); } } return true; } /** * menu handling */ private void menu() { int cnt, val, tim; cnt = 0; tim = Timer.getTimeoutSec(10); boolean bereit = false; boolean download = Main.state.isDownloadSticky(); if (Logic.state==Logic.DL_CHECK || Logic.state==Logic.INIT || Logic.state==Logic.GPS_OK) { // Logic.state==Logic.CONNECT) { bereit = true; } // System.out.println("Menue"); while (loop()) { if (Status.esMode) { Display.write("Betriebsfunktion:", mnuESTxt[cnt],""); } else if (bereit) { Display.write("Betriebsfunktion:", mnuBereit[cnt],""); } else { Display.write("Betriebsfunktion:", mnuTxt[cnt],""); } if (Timer.timeout(tim)) { Status.dispMenu = false; return; } val = Keyboard.rd(); if (val==-1) { continue; } tim = Timer.getTimeoutSec(10); if (val==Keyboard.C) { Status.dispMenu = false; return; } if (val==Keyboard.B) { ++cnt; if (Status.esMode) { if (cnt==MNU_ES_CNT) cnt=0; } else if (bereit) { if (cnt==MNU_BEREIT_CNT) cnt=0; } else { if (cnt==MNU_CNT) cnt=0; } } if (val==Keyboard.E) { Status.dispMenu = false; if ((Logic.state==Logic.NOTHALT) && cnt!=4) { Display.write("", "Nicht m�glich", "(Quitt. [E])"); waitEnter(); return; } if (Status.esMode) { if (cnt==0) { Logic.state = Logic.ES_RDY; } else if (cnt==1) { Logic.state = Logic.ES_VERSCHUB; } else if (cnt==2) { if (Main.state.isDownloading()) { Display.write("Download", "Nicht erlaubt", ""); waitEnter(); return; } Display.write("Neustart", "", ""); restart(); } } else if (bereit) { if (download) { Display.write("Download", "Nicht erlaubt", ""); waitEnter(); return; } if (cnt==0) { Logic.state = Logic.DEAKT; } else if (cnt==1) { Display.write("Neustart", "", ""); restart(); } } else { // only ES mode is allowed if (download && cnt!=4) { Display.write("Download", "Nicht erlaubt", ""); waitEnter(); return; } if (cnt==0) { ankunft(); return; } else if (cnt==1) { verlassen(); return; } else if (cnt==2) { Logic.state = Logic.INFO; } else if (cnt==3) { if (!Status.isMaster) { Display.write("", "Nicht erlaubt", ""); waitEnter(); return; } Logic.state = Logic.LERN; } else if (cnt==4) { Logic.state = Logic.ES221; } else if (cnt==5) { Display.write("Neustart", "", ""); restart(); } else if (cnt==6) { // Hilfsbetrieb if (Status.connOk || Gps.speed>Gps.MIN_SPEED) { Display.write("", "Nicht m�glich", ""); waitEnter(); } else { Display.write("Wechsel zu", "Hilfsbetrieb?", "(Quitt. [E])"); if (waitEnter()) { hilfsbtr = true; } } } else if (cnt==7) { // HB Ferl if (!hilfsbtr || Main.state.zugnr==0) { Display.write("", "Nicht m�glich", ""); waitEnter(); } else { hbFerl(); } } } return; } } } /** * Wait for GPS to be ready. * */ private void waitForGps() { System.out.println("waitGps"); int tim; Gps.wait = false; Display.initMsg(); Led.shortBeep(); boolean first = true; tim = Timer.getSec()+10; // wait for GPS data for (;;) { if (Gps.fix!=-1) { break; } if (Timer.secTimeout(tim) && first) { Display.write("GPS gest�rt!", "", "(Quitt. [E])"); Led.alarm(); waitEnterOnly(); Led.alarmOff(); first = false; } loop(); } tim = Timer.getSec()+120; first = true; // wait for GPS melnr found for (;;) { if (Gps.fix!=0) { break; } if (Timer.secTimeout(tim) && first) { if (Gps.fix==0) { Display.write("Keine Satelliten!", "",""); Led.shortBeep(); first = false; } } if (!loop()) return; } Logic.state = Logic.GPS_OK; } /** * GPS is ready, we are waiting for a valid Strecke * and a valid melNr. */ private void bereit() { int tim = Timer.getSec()+CHECK_TIMEOUT; // wait for GPS melnr found for (;;) { if (Main.state.getPos()>0) { // now we can check for a change of Melnr checkMelnr = true; break; } if (Main.state.strnr>0) { Display.write("Betriebsbereit", "Strecke ", Main.state.strnr, ""); } else { Display.write("Betriebsbereit", "",""); // check for a download server after some seconds // when no Strecke found if (Timer.secTimeout(tim) && !dlChecked) { Logic.state = Logic.DL_CHECK; return; } } if (Main.state.strnr<=0 && Status.selectStr) { enterStrNr(); } if (!loop()) return; } if (Flash.getIp()!=0) { // that's a ZLB Strecke Logic.state = Logic.CONNECT; } else { Status.esMode = true; Logic.state = Logic.ES_RDY; } } /** * Strecke nicht eindeutig => eingeben */ private void enterStrNr() { int nr=-1; while (nr<=0) { Display.write("Strecke eingeben","Strecke:",""); Led.shortBeep(); nr = getNumber(8, 3); if (nr>0) { int cnt = Flash.getCnt(); int i; for (i=0; i<cnt; ++i) { if (nr==Flash.getStrNr(i)) { Flash.loadStr(nr); Flash.loadStrNames(nr, 0, 0); // if (Flash.getIp()==0) { // Flash.esStr(); // } break; } } if (i==cnt) { Display.write("Streckennummer","ung�ltig","(Quitt. [E])"); Led.shortBeep(); waitEnterOnly(); nr = -1; } } } Main.state.strnr = nr; } private void queryDownload() { // just check it once from GPS_OK, // but goes back to INIT dlChecked = true; int tim = Timer.getSec()+DL_TIMEOUT; System.out.println("Check download server"); // Isn't Flash.java a strange point for communication start! if (!Flash.startComm(DL_STRNR)) { System.out.println("kein Download Server"); Logic.state = Logic.INIT; return; } Display.write("Verbindungsaufbau", "Download check", "(Bitte warten)"); // wait for ip link established for (;;) { if (ipLink.getIpAddress()!=0) { break; } if (Timer.secTimeout(tim)) { System.out.println("Link timeout"); break; } loop(); } Display.write("Download check", "", ""); Display.ipVal(40, Main.state.destIp); // CONN is sent in check() // Here we wait for the reply for (;;) { if (Status.connOk) { if (Main.state.isDownloadSticky()) { // go the normal way to download Logic.state = Logic.FDL_CONN; return; } else { break; } } if (Timer.secTimeout(tim)) { System.out.println("Download server connect timeout"); break; } loop(); } // we fall through when there is no download // or a connection timeout // disconnect and wait for GPS Status.connOk = false; connSent = false; Status.commErr = 0; // ignore it ipLink.disconnect(); Main.state.destIp = 0; Logic.state = Logic.INIT; } /** * Start the connection. In Hilsbetrieb the connection start is * 'faked'. */ private void startConn() { Display.write("Verbindungsaufbau", "", ""); Main.logger.print("start connection"); // Isn't Flash.java a strange point for communication start! Flash.startComm(Main.state.strnr); // wait for ip link established while (loop()) { int cnt = ipLink.getConnCount(); if (cnt!=0) { Display.write(20, "Versuch ", cnt); } if (ipLink.getIpAddress()!=0) { break; } if (hilfsbtr) { break; } } if (Status.dispMenu) return; Display.write("Verbinden zu", "", ""); Display.ipVal(40, Main.state.destIp); // CONN is sent in check() // Here we wait for the reply while (loop()) { if (Status.connOk || hilfsbtr) { Logic.state = Logic.FDL_CONN; break; } } } /** * Check Verschub is allowed and display the message. * * returns true to continue the check. * returns false if canceled by pressing 'C' => * enter zug data * */ private boolean verschub() { State state = Main.state; int from, to; synchronized (state) { isVerschub = state.isVerschub(); from = state.start; to = state.end; } if (!isVerschub) return true; // Status.state change in loop() if (Logic.state!=Logic.FDL_CONN || Status.dispMenu) return true; Display.write("Verschub erlaubt", "", ""); while (loop()) { Flash.Point p = Flash.getPoint(from); if (p!=null) { Display.write(20, p.verschubVon); } p = Flash.getPoint(to); if (p!=null) { Display.write(40, p.verschubBis); } // check again synchronized (state) { isVerschub = state.isVerschub(); from = state.start; to = state.end; } if (!isVerschub) break; int val = Keyboard.rd(); if (val==Keyboard.C) { isVerschub = false; return false; } else if (val==Keyboard.B) { Keyboard.unread(val); loop(); return true; } // Status.state change in loop() if (Logic.state!=Logic.FDL_CONN || Status.dispMenu) return true; } return true; } private void anmelden() { int nr, val, tim; State state = Main.state; // System.out.println("Anmelden"); // load default strings for Verschub Flash.loadStrNames(Main.state.strnr, 0, 0); boolean askVerschub = verschub(); if (Logic.state!=Logic.FDL_CONN || Status.dispMenu) return; val = 0; state.type = State.TYPE_UNKNOWN; nr = 0; tim = Timer.getTimeoutSec(5); // Strecke is known!!! while (loop()) { // stop loop when downloading if (state.isDownloadSticky()) { return; } // did we reset and get the data from the ZLB? if (state.zugnr!=0 && state.type!=0) { if (state.start!=state.end) { Logic.state = Logic.ERLAUBNIS; } else { Logic.state = Logic.ANM_OK; } return; } if (askVerschub && Timer.timeout(tim)) { askVerschub = verschub(); // Status.state change in verschub() if (Logic.state!=Logic.FDL_CONN || Status.dispMenu) return; tim = Timer.getTimeoutSec(5); } Flash.Point p = Flash.getPoint(Main.state.getPos()); if (p==null || !(p.anmelden)) { Display.write("Anmelden bei", "dieser Position", "nicht m�glich"); } else { Display.write("Anmelden", "Strecke ", state.strnr, "Zug: 1, Nf: 2"); val = Keyboard.rd(); if (val==Keyboard.B) { Keyboard.unread(val); return; } else if (val==Keyboard.C) { return; } val = Keyboard.num(val); if (val>=1 && val <=2) { nr = zugnummer(val); if (nr == -1) return; break; } } // check for going back to 'Bereit' if (Gps.changeToBereit) { reset(); } } // Status.state change in loop() if (Logic.state!=Logic.FDL_CONN || Status.dispMenu) return; // also return on a comm error if (!loop()) return; int type = val; if (val==1) { Display.write("StreckenNr: ", state.strnr, "ZugNr: ",nr , "(Anmelden mit [E])"); } else { Display.write("StreckenNr: ", state.strnr, "Nebenfahrt: N", nr, "(Anmelden mit [E])"); } while (loop()) { // stop loop when downloading if (state.isDownloadSticky()) { return; } val = Keyboard.rd(); if (val==Keyboard.B) { Keyboard.unread(val); continue; } if (val==Keyboard.E) { state.zugnr = nr; state.type = type; Logic.state = Logic.ANM_WAIT; // if (Logic.state!=Logic.FDL_CONN) return; return; } else if (val==Keyboard.C) { return; } } } private void anmeldenWait() { while (loop()) { Display.write("Anmelden", "(bitte warten)", "(Fdl verst�ndigen)"); // wait for Anmelden OK or we already got a FERL if (Events.anmeldenOk || Main.state.start!=0 || hilfsbtr) { Logic.state = Logic.ANM_OK; Events.anmeldenOk = false; if (Main.state.start!=Main.state.end) { // we also got a FERL Logic.state = Logic.ERLAUBNIS; } break; } else if (Logic.state == Logic.ABGEMELDET) { abmelden(); } } } private int zugnummer(int val) { if (val==1) { Display.write("", "ZugNr:",""); return getNumber(7, 5); } else if (val==2) { Display.write("", "Nebenfahrt:",""); return getNumber(12, 5); } else { return 0; // no number fuer Verschub } } final static int COMM_NOERR = 0; final static int COMM_FDLERR = 1; final static int COMM_SHORT = 2; final static int COMM_WRCMD = 3; final static int COMM_WRBGID = 4; private void commError() { // In ES mode or when checking the download // server we just ignore the communication error // 19.4.2008 also ZLB not responsing ignored! if (Status.esMode || Logic.state == Logic.DL_CHECK || Status.commErr==COMM_FDLERR) { Status.commErr = 0; System.out.println("comm err ignored"); return; } if (Status.doCommAlarm) { int nr = Status.commErr; Led.shortBeep(); Led.startBlinking(); if (nr==COMM_SHORT) { Display.write("FDL Msg Fehler", "Paket zu kurz", ""); } else if (nr==COMM_WRBGID) { Display.write("FDL Msg Fehler", "falsches CMD", ""); } else if (nr==COMM_WRBGID) { Display.write("FDL Msg Fehler", "falsche bgid", ""); } else { Display.write("FDL Rechner", "antwortet nicht", "(FDL verst�ndigen)"); } // Display.intVal(40, Status.commErr); } Status.connOk = false; connSent = false; // clear error Status.commErr = 0; if (Status.doCommAlarm) { for (;;) { loop(); // // we got another communication error during wait for Enter // just reset our vars and let check()/Comm do the reconnect // if (Status.commErr!=0) { connSent = false; // clear error Status.commErr = 0; } if (Keyboard.rd()==Keyboard.E) break; if (Status.connOk) break; } Led.stopBlinking(); } // keep Status even if not connected /* Status.state = Status.INIT; Main.state.strnr = 0; Main.state.pos = 0; Main.state.posSent = 0; */ } /** * Handle the alarms. */ private void alarm() { Dbg.wr("Alarm "); Dbg.intVal(alarmType); Dbg.lf(); if (alarmType==State.ALARM_UEBERF) { Display.write("", "ZIEL �BERFAHREN", ""); } else if (alarmType==State.ALARM_FAEHRT) { Display.write("KEINE", "FAHRERLAUBNIS", ""); } else if (alarmType==State.ALARM_RICHTUNG) { Display.write("Falsche", "Richtung", ""); } else if (alarmType==State.ALARM_MLR) { Display.write("Falscher", "Melderaum", ""); } else { Display.write("Alarm", "Nummer", alarmType, ""); } if (Status.esMode) { setGpsData(); tmpStr.append("Alarm: "); tmpStr.append(alarmType); tmpStr.append("\n"); Flash.log(tmpStr); } Led.alarm(); if (Status.connOk) { Main.state.setAlarm(alarmType); } for (;;) { // only NOTHAL overwrites an Alarm if (Logic.state == Logic.NOTHALT) return; // wait for Enter to quit Alarm if (waitEnter()) break; } if (alarmType==State.ALARM_UEBERF) { alarmZielQuit = true; } else if (alarmType==State.ALARM_FAEHRT) { alarmFaehrtQuit = true; } else if (alarmType==State.ALARM_RICHTUNG) { alarmRichtungQuit = true; } else if (alarmType==State.ALARM_MLR) { alarmMlrQuit = true; } else { Display.write("Alarm", "Nummer", alarmType, ""); } Led.alarmOff(); if (Status.connOk) { // reset alarm - even is not quit? Main.state.setAlarm(0); } // // update state with stateAfterQuit only if // state did not change since alarm // if (Logic.state==Logic.ALARM) { Logic.state = stateAfterQuit; if (Logic.state==Logic.ZIEL) { Logic.state = Logic.ANM_OK; } } } private void erlaubnis() { checkMove = false; Flash.Point p = Flash.getPoint(Main.state.end); if (p==null) { Display.write("Falsche", "Fahrerlaubnis", ""); } else { Display.write("Fahrerlaubnis", p.stationLine1, p.stationLine2); } } private void ziel() { Flash.Point p = Flash.getPoint(Main.state.getPos()); if (p==null) return; if (Status.esMode) { Display.write("Ziel erreicht:", p.stationLine1, "(HP-Ausw. Pfeilt.)"); setGpsData(); tmpStr.append("Ziel erreicht: "); tmpStr.append(Main.state.getPos()); tmpStr.append("\n"); Flash.log(tmpStr); if (waitAnyKey()) { Logic.state = Logic.ES_RDY; } } else { Display.write("Ziel erreicht:", p.stationLine1, p.stationLine2); } } private void widerruf() { // System.out.println("Widerruf"); Display.write("Fahrtwiderruf", "ZugNr: ", Main.state.zugnr, "(Quitt. mit [E])"); Led.startBlinking(); // wait for Enter while (loop()) { if (Keyboard.rd()==Keyboard.E) { Main.state.fwrQuit(); Display.write("Fahrtwiderruf OK", "", ""); Logic.state = Logic.ANM_OK; Led.stopBlinking(); return; } } } private void nothalt() { // System.out.println("Nothalt"); Display.write("", "NOTHALT", ""); Led.alarm(); // wait for Enter for(;;) { loop(); if (Keyboard.rd()==Keyboard.E) { Main.state.nothaltQuit(); Led.alarmOff(); Logic.state = Logic.NOTHALT_OK; return; } } } private void abmelden() { // System.out.println("Abmelden"); Display.write("Abmelden", "", "(bitte warten)"); restart(); } private void restart() { if (Status.esMode) { setGpsData(); tmpStr.append("Neustart: "); tmpStr.append(Main.state.getPos()); tmpStr.append("\n"); Flash.log(tmpStr); } reset(); } private void deakt() { Display.write("Deaktiviert", "", "Aktivieren mit [E]"); setGpsData(); tmpStr.append("Deaktiviert: "); tmpStr.append(Main.state.getPos()); tmpStr.append("\n"); Flash.log(tmpStr); initVals(); waitEnterOnly(); reset(); } /** * reset() is without Logging in ES mode * */ private void reset() { // wait some time to send outstanding messages // and reply int tim = Timer.getTimeoutSec(10); while (!Timer.timeout(tim)) { loop(); if (State.forceReset) { break; } } // wait for reset Main.reset = true; for (;;) { loop(); } } private void ankunft() { int tim; // System.out.println("AnkVerl"); if (Main.state.getPos()<=0 || Main.state.start<=0 || Main.state.end<=0 || Status.direction == Gps.DIR_UNKNOWN) { Display.write("Bei dieser Position", "keine Meldung", "m�glich!"); waitEnter(5); return; } Flash.Point p = Flash.getPoint(Main.state.getPos()); if (p==null) { Display.write("Bei dieser Position", "keine Meldung", "m�glich!"); waitEnter(5); return; } if (Status.direction == Gps.DIR_FORWARD) { // going from left to rigth. while (p!=null && !p.station) { p = p.getPrev(); } } else { while (p!=null && !p.station) { p = p.getNext(); } } if (p==null) { Display.write("Bei dieser Position", "keine Meldung", "m�glich!"); waitEnter(5); return; } Display.write("Ankunftsmeldung bei", p.stationLine1, "(Absenden mit [E])"); if (!waitEnter()) return; Display.write("Ankunftsmeldung OK", p.stationLine1, ""); // minimum display time tim = Timer.getTimeoutSec(5); Main.state.ankunft(p.melnr); // and wait for a reply from FDL while (loop()) { if (Main.state.ankuftAck() && Timer.timeout(tim)) { return; } } } private void verlassen() { int tim; // System.out.println("AnkVerl"); if (Main.state.getPos()<=0 || Main.state.start<=0 || Main.state.end<=0 || Status.direction == Gps.DIR_UNKNOWN) { Display.write("Bei dieser Position", "keine Meldung", "m�glich!"); waitEnter(5); return; } Flash.Point p = Flash.getPoint(Main.state.getPos()); if (p==null || !p.verlassen) { Display.write("Bei dieser Position", "keine Meldung", "m�glich!"); waitEnter(5); return; } if (Status.direction == Gps.DIR_FORWARD) { // going from left to rigth. while (p!=null && !p.station) { p = p.getPrev(); } } else { while (p!=null && !p.station) { p = p.getNext(); } } if (p==null) { Display.write("Bei dieser Position", "keine Meldung", "m�glich!"); waitEnter(5); return; } Display.write("Verl.meldung nach", p.stationLine1, "(Absenden mit [E])"); if (!waitEnter()) return; Display.write("Verl.meldung OK", p.stationLine1, ""); // minimum display time tim = Timer.getTimeoutSec(5); Main.state.verlassen(p.melnr); // and wait for a reply from FDL while (loop()) { if (Main.state.verlassenAck() && Timer.timeout(tim)) { return; } } } private void download() { int dlType = -1; int percent = -1; int cnt = 0; // System.out.println("Download"); Display.write("�bertragung", "ES221 m�glich", ""); while (loop()) { ; } /* not type no percentage for (;;) { loop(); // there is no exit from download state! if (Status.dlType!=dlType) { dlType = Status.dlType; if (dlType==0) { Display.write("�bertragung", " Streckendaten", ""); } else { Display.write("�bertragung", " Programm", ""); } } if (percent != Status.dlPercent) { percent = Status.dlPercent; cnt = (cnt+1) & 0x01; Display.write(20, bsyIndication.charAt(cnt)); if (percent==101) { Display.write(40, "fertig"); } else if (percent>0 && percent<101) { int i = percent*19/100; for (int j=0; j<i; ++j) { Display.write(40+j, '#'); } } } } */ } private void info() { int i, j; // System.out.println("Infobtrieb"); Display.write("Infobetrieb", "", ""); checkMelnr = false; Main.state.setInfo(); // wait for Enter or 'C' while (loop()) { i = Keyboard.rd(); if (i==Keyboard.E || i==Keyboard.C) { Main.state.resetInfo(); reset(); } tmpStr.setLength(0); tmpStr.append(Gps.nearestPointDistance); tmpStr.append("m zu "); tmpStr.append(Gps.nearestPoint); tmpStr.append(' '); tmpStr.append(Gps.speed); tmpStr.append(" km/h"); Display.write(0, tmpStr); tmpStr.setLength(0); i = Gps.speedCalc; if (i<0) i = 0; tmpStr.append(Gps.speedCalc); tmpStr.append(" km/h"); if (i<1000) tmpStr.append(' '); if (i<100) tmpStr.append(' '); tmpStr.append("MNr: "); Display.write(20, tmpStr, Main.state.getPos()); Display.write(40, Gps.text); } } private void lern() { int i, val; // System.out.println("Lern"); Display.write("Lerne", "Strecke",""); checkMelnr = false; val = Main.state.strnr; Main.state.strnr = getNumber(8, 3); if (Main.state.strnr == -1) return; if (val!=Main.state.strnr || !Status.connOk) { Flash.loadStr(Main.state.strnr); Flash.loadStrNames(Main.state.strnr, 0, 0); startConn(); } int melnr = Flash.getFirst(Main.state.strnr); if (melnr==-1) { Display.write("Strecke", "nicht gefunden", ""); waitEnterAndInit(); return; } // Conn changes to FLD_CONN Logic.state = Logic.LERN; Main.state.setLern(); while (loop()) { Display.write(0, "Lernbetrieb ", melnr); Flash.Point p = Flash.getPoint(melnr); if (p==null) { Display.write(20, "Falscher Punkt"); } else { Display.write(20, p.stationLine1); } Display.write(40, Gps.text); val = Keyboard.rd(); if (val==-1) { continue; } if (val==Keyboard.C) { Main.state.resetLern(); reset(); } if (val==Keyboard.DOWN) { i = Flash.getPrev(melnr); if (i!=-1) melnr = i; } if (val==Keyboard.UP) { i = Flash.getNext(melnr); if (i!=-1) melnr = i; } if (val==Keyboard.E) { measure(melnr); } } } private void measure(int melnr) { // System.out.println("Measure"); Display.write("Mittelung ", melnr, "", ""); Gps.startAvg(); while (loop()) { Display.intVal(16, Gps.avgCnt); Display.intVal(20, Gps.getLatAvg()); Display.intVal(30, Gps.getLonAvg()); Display.intVal(40, Gps.last_lat); Display.intVal(50, Gps.last_lon); int val = Keyboard.rd(); if (val==-1) { continue; } if (val==Keyboard.C) { return; } if (val==Keyboard.E) { Gps.stopAvg(); Display.write("Wert wird", "gesendet", ""); Status.lernOk = false; Main.state.lern(melnr, Gps.getLatAvg(), Gps.getLonAvg()); // and wait for a reply from FDL while (loop()) { if (Status.lernOk) { return; } } } } } /** * Menu command to change to ES mode * */ private void es221() { Display.write("Wechsel zu", "ES221 Betrieb", ""); // we will keep the connection up Main.state.setESAlarm(); System.out.println("esInit"); Status.esMode = true; // question: when shall be do the esStr()? // is it necessary to do esStr() on ES Strecken befor findStr()? synchronized(this) { // Flash.esStr(); Main.state.setPos(-1); // disable till Gps finds the new Melnr for the // changed Strecke checkMelnr = false; } int melnr = Flash.getFirst(Main.state.strnr); Flash.Point p = Flash.getPoint(melnr); if (p==null) { Display.write("Keine ES-mode", "Streckendaten", ""); while (loop()) { ; } return; } Logic.state = Logic.ES_RDY; for (;;) { if (Main.state.getPos()>0) { // now we can check for a change of Melnr checkMelnr = true; Main.state.start = Main.state.getPos(); Main.state.end = Main.state.getPos(); break; } loop(); } int tim = Timer.getTimeoutSec(2); while (loop()) { if (Timer.timeout(tim)) { return; } } } /** * ES mode: wait for entering a destination * */ private void esRdy() { int val = 0; int i = 0; System.out.println("ES Rdy"); int melnr = Flash.getFirst(Main.state.strnr); Flash.Point p = Flash.getPoint(melnr); for (;;) { if (p.station && melnr>=Main.state.getPos()) { break; } i = Flash.getNext(melnr); if (i!=-1) { melnr = i; } else { break; } p = Flash.getPoint(melnr); } while (loop()) { // check for going back to 'Bereit' if (Gps.changeToBereit) { reset(); } Display.write("Haltepunkt ausw.:", p.stationLine1, p.stationLine2); val = Keyboard.rd(); if (val==-1) { continue; } if (val==Keyboard.B) { Keyboard.unread(val); return; } // TODO: the following is almost a copy from HB select // just use different flags boolean found = false; if (val==Keyboard.UP) { while (!found) { i = Flash.getNext(melnr); if (i!=-1) { melnr = i; p = Flash.getPoint(melnr); if (p.station) { found = true; } } else { break; } } } if (val==Keyboard.DOWN) { while (!found) { i = Flash.getPrev(melnr); if (i!=-1) { melnr = i; p = Flash.getPoint(melnr); if (p.station) { found = true; } } else { break; } } } // that's the old ES select with ES strecke change // // display only the left point text // // if (val==Keyboard.UP) { // i = Flash.getNext(melnr); // i = Flash.getNext(i); // if (i!=-1) { // melnr = i; // p = Flash.getPoint(melnr); // } // } // if (val==Keyboard.DOWN) { // i = Flash.getPrev(melnr); // i = Flash.getPrev(i); // if (i!=-1) { // melnr = i; // p = Flash.getPoint(melnr); // } // } if (val==Keyboard.E) { // The left point is the station // smaller melnr is start Main.state.start = Main.state.getPos(); Main.state.end = melnr; Logic.state = Logic.ERLAUBNIS; Main.state.type = State.TYPE_ES221; Status.direction = Gps.DIR_UNKNOWN; setGpsData(); tmpStr.append("Fahrt von "); tmpStr.append(Main.state.start); tmpStr.append(" nach "); tmpStr.append(Main.state.end); tmpStr.append("\n"); Flash.log(tmpStr); return; } } } /** * */ private void setGpsData() { tmpStr.setLength(0); synchronized (Gps.lastGGA) { tmpStr.append(Gps.lastGGA); } synchronized (Gps.lastRMC) { tmpStr.append(Gps.lastRMC); } tmpStr.append("Strecke "); tmpStr.append(Main.state.strnr); tmpStr.append(" - "); } private void esVerschub() { Display.write("ES Verschub", "", ""); setGpsData(); tmpStr.append("Verschub: "); tmpStr.append(Main.state.getPos()); tmpStr.append("\n"); Flash.log(tmpStr); Logic.state = Logic.ES_VERSCHUB; checkMelnr = false; while (loop()) { Main.state.start = Main.state.getPos(); Main.state.end = Main.state.getPos(); } checkMelnr = true; } /** * HB mode ferl * */ private void hbFerl() { int val = 0; int i = 0; System.out.println("HB Ferl"); int melnr = Main.state.getPos(); Flash.Point p = Flash.getPoint(melnr); if (p==null) { System.out.println("np Problem"); return; } while (loop()) { // check for going back to 'Bereit' if (Gps.changeToBereit) { reset(); } Flash.loadStrNames(Main.state.strnr, Main.state.getPos(), melnr); Display.write("Haltepunkt ausw.:", p.stationLine1, p.stationLine2); val = Keyboard.rd(); if (val==-1) { continue; } if (val==Keyboard.B) { Keyboard.unread(val); return; } boolean found = false; // select the correct destination when it depends on // the direction boolean right = melnr > Main.state.getPos(); if (val==Keyboard.UP) { if (melnr==Main.state.getPos()) { right = true; } while (!found) { i = Flash.getNext(melnr); if (i!=-1) { melnr = i; p = Flash.getPoint(melnr); if (p.station || (right && p.hbRight) || (!right && p.hbLeft)) { found = true; } } else { break; } } } if (val==Keyboard.DOWN) { if (melnr==Main.state.getPos()) { right = false; } while (!found) { i = Flash.getPrev(melnr); if (i!=-1) { melnr = i; p = Flash.getPoint(melnr); if (p.station || (right && p.hbRight) || (!right && p.hbLeft)) { found = true; } } else { break; } } } if (val==Keyboard.E) { Main.state.start = Main.state.getPos(); Main.state.end = melnr; Logic.state = Logic.ERLAUBNIS; Main.state.type = State.TYPE_ZUG; Status.direction = Gps.DIR_UNKNOWN; setGpsData(); tmpStr.append("HB Fahrt von "); tmpStr.append(Main.state.start); tmpStr.append(" nach "); tmpStr.append(Main.state.end); tmpStr.append("\n"); Flash.log(tmpStr); return; } if (val==Keyboard.C) { return; } } } /** * Wait for Enter and set state to INIT. */ private void waitEnterAndInit() { while (loop()) { if (Keyboard.rd()==Keyboard.E) { Logic.state = Logic.INIT; Main.state.strnr = 0; Main.state.setPos(0); return; } } } /** * wait for Enter only, no unread on 'B'. * no break out with loop() */ private void waitEnterOnly() { for (;;) { loop(); if (Keyboard.rd()==Keyboard.E) return; } } /** * wait for any key press (Ziel in ES-mode) */ private boolean waitAnyKey() { int val; int state = Logic.state; while (loop()) { val = Keyboard.rd(); if (val!=-1) { return true; } // some State has changed! // dont wait anymore if (state!=Logic.state) { return false; } } return false; } /** * return false if 'C' */ private boolean waitEnter() { int val; int state = Logic.state; while (loop()) { val = Keyboard.rd(); if (val==Keyboard.E) { return true; } else if (val==Keyboard.B) { Keyboard.unread(val); return false; } else if (val==Keyboard.C) { return false; } // some State has changed! // dont wait anymore if (state!=Logic.state) { return false; } } return false; } /** * return false if 'C' */ private boolean waitEnter(int timeout) { int val; int tim; tim = Timer.getTimeoutSec(5); int state = Logic.state; while (loop()) { val = Keyboard.rd(); if (val==Keyboard.E) { return true; } else if (val==Keyboard.B) { Keyboard.unread(val); return false; } else if (val==Keyboard.C) { return false; } // some State has changed! // dont wait anymore if (state!=Logic.state) { return false; } // timout expired if (Timer.timeout(tim)) { return false; } } return false; } /** * read a number with display update at pos. * 'E' is Enter * 'C' is Backspace * 'B' cancels input (call menu) */ private int getNumber(int pos, int size) { int cnt; if (size>BUF_LEN) size = BUF_LEN; for (cnt=0; cnt<size; ++cnt) { buf[cnt] = 0; } cnt = 0; while (loop()) { Display.write(20+pos+cnt, '_'); int val = Keyboard.rd(); if (val==Keyboard.C) { Display.write(20+pos+cnt, ' '); if (cnt>0) { --cnt; } else { return -1; } } if (val==Keyboard.E || cnt==size) { val = 0; Display.write(20+pos+cnt, ' '); for (int i=0; i<cnt; ++i) { val *= 10; val += buf[i]; } return val; } if (val==Keyboard.B) { Keyboard.unread(val); continue; } val = Keyboard.num(val); if (val!=-1) { buf[cnt] = val; Display.write(20+pos+cnt, '0'+val); ++cnt; } } return -1; } }