/* This file is part of JOP, the Java Optimized Processor see <http://www.jopdesign.com/> Copyright (C) 2001-2008, Martin Schoeberl (martin@jopdesign.com) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package kfl; /** * All Functions for MS in Zentrale. * * WICHTIG: Fehler fuehren zu Stopp der Anlage (mit for (;;) loop). * Neustart erforderlich! */ public class Station { public static final int MIN_SENS_CNT = 3; public static final int MAX_SENS_CNT = 24; // Sensor is valid for maximum 27 public static final int MAX_DIFF = 20; // = 10 cm public static final int CONTROL_DIFF = 10; // = 5 cm public static final int MAX_COMM_ERR = 3; // maximum (continous) errors befor stop // public static final int MAX_COMM_ERR = 10; // maximum (continous) errors befor stop // bei SEHR hohem Wert Timer.wd in cmdAll und cmd!!! public static final int LUNKNOWN = 0; // unbekannt public static final int LU = 1; // unten public static final int LO = 2; // oben public static final int LZ = 3; // zwischen public static final int LUZ = 4; // unten zwischen private static int cnt; // how many MS private static int ltg; // state of Leitung private static int[] ret; public static int[] temp; private static int[] maxCnt; // up position of cnt (down pos. is 0) private static int[] upCnt; // impuls count after up sensor private static int[] downCnt; // impuls count after down sensor private static int[] lastCnt; // last known value of MS cnt private static int[] servCnt; // used for service public static void init() { int i; ltg = LUNKNOWN; ret = new int[16]; // maximum maxCnt = new int[16]; upCnt = new int[16]; downCnt = new int[16]; servCnt = new int[16]; temp = new int[16]; // maximum for (i=0; i<16; ++i) temp[i] = 0; cnt = Config.getCnt(); getVals(); dispVals(); } /* private static void setXXX() { int i; // set values for (i=0; i<3; ++i) { Config.setMSmaxCnt(i+1, maxCnt[i]); Config.setMSdwnCnt(i+1, downCnt[i]); Config.setMSupCnt(i+1, upCnt[i]); } } */ private static void getVals() { int i; for (i=0; i<cnt; ++i) { maxCnt[i] = Config.getMSmaxCnt(i+1); upCnt[i] = Config.getMSupCnt(i+1); downCnt[i] = Config.getMSdwnCnt(i+1); } /* maxCnt[0] = 1051; maxCnt[1] = 1051; maxCnt[2] = 1052; downCnt[0] = 20; downCnt[1] = 10; downCnt[2] = 18; upCnt[0] = 8; // should be 3 minimum!!! upCnt[1] = 7; upCnt[2] = 8; */ boolean ok = true; // check possibility of values for (i=0; i<cnt; ++i) { if (maxCnt[i]==0 || maxCnt[i]>1100) { ok = false; } if (upCnt[i]<MIN_SENS_CNT || upCnt[i]>MAX_SENS_CNT) { ok = false; upCnt[i] = MIN_SENS_CNT; } if (downCnt[i]<MIN_SENS_CNT || downCnt[i]>MAX_SENS_CNT) { ok = false; downCnt[i] = MIN_SENS_CNT; } } if (!ok) { Menu.msg(Texte.notjust, Texte.secval); for (i=0; i<cnt; ++i) { maxCnt[i] = 0; } } } /** * only for info. */ private static void dispVals() { int i; Display.cls(); for (i=0; i<cnt; ++i) { Display.intVal(downCnt[i]); Display.data(' '); } Timer.sleepWd(1000); Display.cls(); for (i=0; i<cnt; ++i) { Display.intVal(upCnt[i]); Display.data(' '); } Timer.sleepWd(1000); Display.cls(); for (i=0; i<cnt; ++i) { Display.intVal(maxCnt[i]); Display.data(' '); } Timer.sleepWd(1000); Display.cls(); } // // some properties // public static boolean isDown() { return ltg==LU; } public static boolean isUp() { return ltg==LO; } public static boolean isBetween() { return ltg==LZ; } public static boolean upOk() { return ltg==LU || ltg==LUZ || ltg==LZ; } public static boolean downOk() { return ltg==LO || ltg==LZ; } public static int getCnt() { return cnt; } // // cmd handling // private static int cmd(int nr, int val) { return cmd(nr, val, 0); } private static int cmd(int nr, int val, int data) { int ret = Msg.exchg(nr, val, data); if (ret>=0) { return ret; } // more tries int tryCnt = MAX_COMM_ERR-1; for (; ret<0 && tryCnt>0; --tryCnt) { ret = Msg.exchg(nr, val, data); Timer.wd(); // bei zu hohem MAX_COMM_ERR } return ret; } private static boolean cmdAll(int val) { return cmdAll(val, 0); } /** * send a command to all MS. */ private static boolean cmdAll(int val, int data) { int i, j; boolean ok = true; // first try for (i=0; i<cnt; ++i) { j = Msg.exchg(i+1, val, data); ret[i] = j; if (j<0) ok = false; } // more tries int tryCnt = MAX_COMM_ERR-1; for (; !ok && tryCnt>0; --tryCnt) { ok = true; for (i=0; i<cnt; ++i) { j = ret[i]; if (j<0) { j = Msg.exchg(i+1, val, data); ret[i] = j; } if (j<0) ok = false; } Timer.wd(); // bei zu hohem MAX_COMM_ERR } return ok; } private static boolean cmdAll(int val, int[] data) { int i, j; boolean ok = true; // first try for (i=0; i<cnt; ++i) { j = Msg.exchg(i+1, val, data[i]); ret[i] = j; if (j<0) ok = false; } // more tries int tryCnt = MAX_COMM_ERR-1; for (; !ok && tryCnt>0; --tryCnt) { ok = true; for (i=0; i<cnt; ++i) { j = ret[i]; if (j<0) { j = Msg.exchg(i+1, val, data[i]); ret[i] = j; } if (j<0) ok = false; } Timer.wd(); // bei zu hohem MAX_COMM_ERR } return ok; } public static void powerOff() { JopSys.wr(0, BBSys.IO_TRIAC); } // be careful when using this in another program! public static void powerOn() { JopSys.wr(BBSys.BIT_TR_ON, BBSys.IO_TRIAC); } public static void error(int nr) { error(nr, 0); } /* not used private static void errorFindMS(int nr) { int i, msnr; msnr = 0; for (i=0; i<cnt; ++i) { if (ret[i]<0) { msnr = i+1; break; } } error(nr, msnr); } */ /** * error display with endless loop. * allow Menu, but no 'real' function. * be WARNED: menu function 'download' (Debug.echo()) switches Power ON!!! */ public static void error(int nr, int msnr) { powerOff(); Zentrale.chkNot(); if (msnr!=0) { Display.line1(Texte.mserr, msnr); } else { Display.line1(Texte.error); } Display.line2(Texte.errTxt(nr)); Log.write(Log.ERROR, nr, msnr); // // allow Menu cmd's for error correction // but no way out for (;;) { Keyboard.loop(); if (Keyboard.pressed) { if (Keyboard.rd()==Keyboard.B) { Menu.doit(); Display.line1(Texte.errMode); Display.line2(Texte.startNew); } } Timer.waitForNextInterval(); Timer.wd(); } } /** * communication error display with secial display! */ private static void comErr() { int i; int msnr = 0; powerOff(); Zentrale.chkNot(); Display.cls(); Display.line1(Texte.comErr); Display.line2(); for (i=0; i<cnt; ++i) { Timer.wd(); if (ret[i]<0) { msnr = i+1; Display.intVal(msnr); Display.data(' '); } } Log.write(Log.ERROR, Err.COMM, msnr); for (;;) { Timer.wd(); } } /* * Werte Sensoren der Masten aus. * Leitung unten nur wenn ALLE Sensoren unten anzeigen. * Das Freigaberelais wird aber nur in down() nach einer erfolgreichen Fahrt * gesetzt. Die LEDs in der Zentrale aber auch nach Einschalten und in LUZ. */ private static void chkLtg() { int i, val; boolean u, o; int cntU, cntO, cntZ; cntU = 0; cntO = 0; cntZ = 0; if (!cmdAll(BBSys.CMD_INP)) { comErr(); } for (i=0; i<cnt; ++i) { val = ret[i]>> 4; // TASTER und Sensoren! o = (val & BBSys.BIT_SENSO) != 0; u = (val & BBSys.BIT_SENSU) != 0; if (o && u) { error(Err.SENS_UP_AND_DOWN, i+1); } else if (o) { ++cntO; } else if (u) { ++cntU; } else { ++cntZ; } } if (cntU==0 && cntO==0) { ltg = LZ; JopSys.wr(BBSys.BIT_LED_U + BBSys.BIT_LED_O, BBSys.IO_LED); } else if (cntU==cnt && cntO==0) { ltg = LU; JopSys.wr(BBSys.BIT_LED_U, BBSys.IO_LED); } else if (cntU!=0 && cntO==0) { ltg = LUZ; } else if (cntU==0 && cntO!=0) { ltg = LO; JopSys.wr(BBSys.BIT_LED_O, BBSys.IO_LED); } else { JopSys.wr(0, BBSys.IO_LED); error(Err.SENS_UP_AND_DOWN); } } /** * see if a new MS is at address 0 after boot timeout. * more than one MS can be changed, BUT only one at a time AND * lowest number first! */ private static void chkNewMS() { int i, j, missing; i = 0; missing = -1; for (j=0; j<cnt; ++j) { if (ret[j]<0) { missing = j; break; // stop on first found! } } if (missing!=-1 && cmd(0, BBSys.CMD_STATUS)>=0) { // found ! ++missing; // base 1 Display.line1(Texte.newms, missing); cmd(0, BBSys.CMD_SET_STATE, BBSys.MS_DBG); cmd(0, BBSys.CMD_SETAD, missing); Timer.sleepWd(2000); Display.line1(Texte.reboot); for(;;) ; } } /** * something went wrong during boot. */ private static void bootErr() { int i, j; i = 0; for (j=0; j<cnt; ++j) { if (ret[j]<0) ++i; } if (i==cnt) error(Err.NO_MS); for (j=0; j<cnt; ++j) { if (ret[j]<0) { error(Err.NO_ANSW_MS, j+1); // endless loop } } error(Err.NO_ANSW_MS); // endless loop } private static final int BOOT_TIME = 100; // max. 10s /** * boot all MS and check MS error */ private static boolean boot() { int i, j; powerOn(); Display.line1(); Display.intVal(cnt); Display.data(' '); Display.data(Texte.chkms); // wait for boot for (i=0; i<BOOT_TIME; ++i) { if (cmdAll(BBSys.CMD_STATUS)) { break; } Timer.wd(); Clock.loop(); Timer.sleepWd(100); Msg.flush(); // flush the input buffer } if (i==BOOT_TIME) { chkNewMS(); bootErr(); } Timer.sleepWd(200); // for shure if (!cmdAll(BBSys.CMD_SET_STATE, BBSys.MS_RDY)) { comErr(); } Timer.wd(); Timer.sleepWd(100); // wait for error detection after set MS_RDY if (!cmdAll(BBSys.CMD_ERRNR)) { comErr(); } for (i=0; i<cnt; ++i) { if (ret[i] != 0) { error(ret[i], i+1); // endless loop } } Timer.wd(); if (!cmdAll(BBSys.CMD_STATUS)) { comErr(); } // not MS_RDY means some strange error !!! // should never happen for (i=0; i<cnt; ++i) { if (ret[i] != BBSys.MS_RDY) { error(Err.MS_ERR, i+1); // endless loop } } Timer.wd(); // see, if there are more MS than configured for (i=cnt+1; i<=16; ++i) { if (cmd(i, BBSys.CMD_STATUS)>=0) { error(Err.WRONG_MS_CNT); } } return true; } /** * init all MS for real action. */ private static boolean initMS() { getTemp(); return setVals(); } private static void getTemp() { int i; if (cmdAll(BBSys.CMD_TEMP)) { for (i=0; i<cnt; ++i) { temp[i] = Temp.calc((ret[i]<<3)+17000); Timer.wd(); } } } private static boolean setVals() { boolean ok = true; int i; if (!cmdAll(BBSys.CMD_SET_DOWNCNT, downCnt)) { comErr(); } if (!cmdAll(BBSys.CMD_SET_UPCNT, upCnt)) { comErr(); } if (!cmdAll(BBSys.CMD_SET_MAXCNT, maxCnt)) { comErr(); } Timer.wd(); return true; } /** * check all MS and state of Leitung. */ public static void chkMS() { boot(); chkLtg(); Timer.wd(); powerOff(); } /** * all MS in service mode */ public static void serviceUp() { for (int i=0; i<cnt; ++i) { maxCnt[i] = 0; // keine Ueberw. im Serv.mode } boot(); initMS(); if (!cmdAll(BBSys.CMD_SET_STATE, BBSys.MS_SERVICE)) { comErr(); } Menu.msg(Texte.serviceUp, Texte.posein); powerOff(); } public static void serviceDown() { for (int i=0; i<cnt; ++i) { maxCnt[i] = 0; // keine Ueberw. im Serv.mode } boot(); initMS(); if (!cmdAll(BBSys.CMD_SET_STATE, BBSys.MS_SERVICE)) { comErr(); } Menu.msg(Texte.serviceDown, Texte.posein); powerOff(); } /** * set values */ public static void servAfterUp(int nr) { downCnt[nr] = servCnt[nr]; maxCnt[nr] = lastCnt[nr]; if (downCnt[nr]<MIN_SENS_CNT) { downCnt[nr] = MIN_SENS_CNT; maxCnt[nr] = 0; Menu.msgMast(nr+1, Texte.sukl); } else if (downCnt[nr]>MAX_SENS_CNT) { downCnt[nr] = MAX_SENS_CNT; maxCnt[nr] = 0; Menu.msgMast(nr+1, Texte.sugr); } Timer.wd(); Config.setMSmaxCnt(nr+1, maxCnt[nr]); Config.setMSdwnCnt(nr+1, downCnt[nr]); Timer.wd(); } public static void servAfterDown(int nr) { upCnt[nr] = servCnt[nr]; maxCnt[nr] = maxCnt[nr]-lastCnt[nr]; if (upCnt[nr]<MIN_SENS_CNT) { upCnt[nr] = MIN_SENS_CNT; maxCnt[nr] = 0; Menu.msgMast(nr+1, Texte.sokl); } else if (upCnt[nr]>MAX_SENS_CNT) { upCnt[nr] = MAX_SENS_CNT; maxCnt[nr] = 0; Menu.msgMast(nr+1, Texte.sogr); } Timer.wd(); Config.setMSmaxCnt(nr+1, maxCnt[nr]); Config.setMSupCnt(nr+1, upCnt[nr]); Timer.wd(); } /** * save data on mast 1. */ public static void backZs() { boot(); if (cmd(1, BBSys.CMD_SET_STATE, BBSys.MS_DBG)<0) { comErr(); } Display.cls(); Display.line1(Texte.backZs); int startPage = Flash.MS_DATA>>7; int pages = (Flash.MS_DATA_LEN+127)/128; int data; // // longer Msg timeout becaus CMD_FL_PROG takes long (about 15ms). // restart after program // Msg.slow = true; // longer Msg timeout for (int i=0; i<pages; ++i) { boolean error = false; if (cmd(1, BBSys.CMD_FL_PAGE, startPage+i)<0) { comErr(); } for (int j=0; j<128; ++j) { Timer.wd(); data = Flash.read(Flash.MS_DATA+i*128+j) & 0xff; if ((data = Msg.exchg(1, BBSys.CMD_FL_DATA, data))<0) { // only one try! addr autoincrement error = true; Timer.sleepWd(50); // to ignore late replays --i; // program pgae again break; } } if (!error) { if (Msg.exchg(1, BBSys.CMD_FL_PROG, 0)<0) { comErr(); } } } powerOff(); } /** * restore data from mast 1. */ public static void restZs() { boot(); if (cmd(1, BBSys.CMD_SET_STATE, BBSys.MS_DBG)<0) { comErr(); } Display.cls(); Display.line1(Texte.restZs); int startPage = Flash.MS_DATA>>7; int pages = (Flash.MS_DATA_LEN+127)/128; int data; Msg.slow = true; if (cmd(1, BBSys.CMD_FL_PAGE, startPage)<0) { comErr(); } for (int i=0; i<Flash.MS_DATA_LEN; ++i) { Timer.wd(); data = Msg.exchg(1, BBSys.CMD_FL_READ, 0); if (data<0) { comErr(); } Flash.write(Flash.MS_DATA+i, data); } powerOff(); } private static void getServCnt() { int i; if (!cmdAll(BBSys.CMD_SERVICECNT)) { comErr(); } for (i=0; i<cnt; ++i) { servCnt[i] = ret[i]; } } /** * now go up! */ public static void up() { int i, val; if (!boot()) return; if (!initMS()) return; ltg = LUNKNOWN; Display.line1(Texte.goesUp); Display.line2(Texte.empty); Relais.resLu(); JopSys.wr(BBSys.BIT_LED_FO, BBSys.IO_LED); Log.write(Log.UP_STARTED); // reset cnt // TODO last realy known value!!! if (!cmdAll(BBSys.CMD_SETCNT, 0)) { comErr(); } if (!cmdAll(BBSys.CMD_UP)) { comErr(); } Timer.wd(); runningLoop(BBSys.MS_UP); getTemp(); if (isUp()) { Display.line1(Texte.isUp); Relais.setLo(); Log.write(Log.IS_UP); } Display.line2(Texte.empty); powerOff(); } /** * now go down! */ public static void down() { int i, val; if (!boot()) return; if (!initMS()) return; ltg = LUNKNOWN; Display.line1(Texte.goesDown); Display.line2(Texte.empty); Relais.resLo(); JopSys.wr(BBSys.BIT_LED_FU, BBSys.IO_LED); Log.write(Log.DOWN_STARTED); // set cnt // TODO last realy known value!!! if (!cmdAll(BBSys.CMD_SETCNT, maxCnt)) { comErr(); } if (!cmdAll(BBSys.CMD_DOWN)) { comErr(); } Timer.wd(); runningLoop(BBSys.MS_DOWN); getTemp(); if (Station.isDown()) { Display.line1(Texte.isDown); Relais.setLu(); Log.write(Log.IS_DOWN); } Display.line2(Texte.empty); powerOff(); } /** * Leitung faehrt. */ private static void runningLoop(int dir) { int i, val, min, max; boolean running; int cntStopped = 0; // wait for autom stop of all do { cntStopped = 0; if (!cmdAll(BBSys.CMD_STATUS)) { comErr(); } for (i=0; i<cnt; ++i) { val = ret[i]; if (val==dir) { ; // still runnig ... OK } else if (val==BBSys.MS_RDY) { ++cntStopped; // MS stopped } else if (val==BBSys.MS_ERR) { val = cmd(i+1, BBSys.CMD_ERRNR); if (val>0) { error(val, i+1); } else { error(Err.MS_ERR, i+1); } } else { error(Err.MS_ERR, i+1); // something wrong } } max = -9999; min = 9999; if (!cmdAll(BBSys.CMD_CNT)) { comErr(); } //Display.line2(); for (i=0; i<cnt; ++i) { val = ret[i]; val = (val<<20)>>20; // sign //Display.intVal(val); //Display.data(' '); lastCnt[i] = val; if (val<min) min = val; if (val>max) max = val; } val = max-min; if (val>MAX_DIFF) { error(Err.MAX_DIFF); } else if (val>CONTROL_DIFF && cntStopped==0) { control(dir, min, max); } // display maximum differenz for now if (val<100 && val>0) { Display.line2(); Display.data('0'+val/10); Display.data('0'+val%10); } Clock.loop(); Timer.wd(); } while (cntStopped!=cnt); getServCnt(); chkLtg(); } /** * control of MS. * Send CMD_PAUSE to the 'fastest' stations. */ private static void control(int dir, int min, int max) { int i; if (dir==BBSys.MS_UP) { for (i=0; i<cnt; ++i) { if (lastCnt[i] > min+CONTROL_DIFF) { cmd(i+1, BBSys.CMD_PAUSE); } } } else if (dir==BBSys.MS_DOWN) { for (i=0; i<cnt; ++i) { if (lastCnt[i] < max-CONTROL_DIFF) { cmd(i+1, BBSys.CMD_PAUSE); } } } } }