diff --git a/Bugs.txt b/Bugs.txt index 8e7e7e0..b28b04f 100644 --- a/Bugs.txt +++ b/Bugs.txt @@ -1,3 +1,3 @@ -2020-03-09 -- reverse funktioniert nicht immer + + diff --git a/ChangeLog b/ChangeLog index 9eebf74..f3cdb1d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2021-02-10: +- automatic mode with random destinations is working now + 2021-01-31: - automtic mode is improving, manual setting of destination autoatic routing and moving the train to the destination. diff --git a/server/block.cc b/server/block.cc index c89c5a3..b07b5b8 100644 --- a/server/block.cc +++ b/server/block.cc @@ -112,7 +112,7 @@ Block Blocks::GetBlockFromJSON(JSONParse *j) { s = ""; j->GetValue("sensor_neg_1", &s); strncpy (bl.s_neg_1, s.c_str(), REFERENCENAME_LEN); - printf ("%s:%d Sensor (%s ---> %s ---> %s\n", __FILE__, __LINE__, bl.s_pos_1, bl.s_center, bl.s_neg_1); + printf ("%s:%d block: %s flags: %d\n", __FILE__, __LINE__, bl.name, bl.flags); return bl; }; @@ -211,6 +211,7 @@ int Blocks::SetLockedby (string blname, string lockedby, int lock_onoff) { Block *bl = NULL; JSONParse jp; int res = -1; + int x, y; debug (0, "Blocks:SetLockedby block:'%s' locked for '%s' locked:%d", blname.c_str(), lockedby.c_str(), lock_onoff); @@ -221,6 +222,12 @@ int Blocks::SetLockedby (string blname, string lockedby, int lock_onoff) { else bl->lockedby[0] = 0; jp.AddObject("block",_GetJSON(bl)); if(network) network->ChangeListPushToAll(jp.ToString()); + + x = -1; y = -1; + while (server->railways.FindReference(&x, &y, blname)) { + server->railways.SetLockedby(x, y, lockedby, lock_onoff); + } + res = 1; } else { diff --git a/server/locomotive.cc b/server/locomotive.cc index c66bf18..462af97 100644 --- a/server/locomotive.cc +++ b/server/locomotive.cc @@ -288,11 +288,20 @@ int Locomotives::SetFunction(string name, int func, int value) { int Locomotives::SetDestination (string name, string block, int direction) { int i; string way; + int blflags; Lock(); for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) if (name.compare(locomotives[i].name) == 0) { + debug (0, "Locomotives::SetDestination (Name:%s Block:%s Direction:%d)\n", name.c_str(), block.c_str(), direction); + + blflags = server->blocks.GetFlags(block); + if ((blflags & BLOCK_F_SHORT) && !(locomotives[i].flags & LOCO_F_SHORTTRAIN)) break; + if ((blflags & BLOCK_F_ENDSTATION) && !(locomotives[i].flags & LOCO_F_CANREVERSE)) break; + + printf ("%s:%d blflags:%d locoflags:%d\n", __FILE__, __LINE__, blflags, locomotives[i].flags); + if (direction) snprintf (locomotives[i].blockdest, REFERENCENAME_LEN, "-:%s", block.c_str()); else snprintf (locomotives[i].blockdest, REFERENCENAME_LEN, "+:%s", block.c_str()); break; @@ -313,7 +322,7 @@ int Locomotives::SetAssign (string name, string block, int direction) { debug (0, "Locomotives::SetAssign (Name:%s Block:%s Direction:%d)\n", name.c_str(), block.c_str(), direction); if (locomotives[i].blockassign[0] != 0) // still locked unlock - server->blocks.SetLockedby(locomotives[i].blockassign, name, 0); + server->blocks.SetLockedby(locomotives[i].blockassign+2, name, 0); if (direction) snprintf (locomotives[i].blockassign, REFERENCENAME_LEN, "-:%s", block.c_str()); else snprintf (locomotives[i].blockassign, REFERENCENAME_LEN, "+:%s", block.c_str()); @@ -339,6 +348,21 @@ int Locomotives::SetAssign (string name, string block, int direction) { } +int Locomotives::GetFlags(string name) { + int flags = -1; + int i; + + Lock(); + for (i = 0; i < max; i++) if (locomotives[i].name[0] != 0) + if (name.compare(locomotives[i].name) == 0) { + flags = locomotives[i].flags; + } + UnLock(); + + return flags; +} + + int Locomotives::Reset(string name) { Railway rw; int i; @@ -410,7 +434,7 @@ int Locomotives::SetAuto(string name) { if (name.compare(locomotives[i].name) == 0) { debug (0, "Locomotives::SetAuto (Name:%s)\n", name.c_str()); locomotives[i].flags |= LOCO_F_AUTO; - locomotives[i].auto_onroute = 0; + locomotives[i].flags &= ~LOCO_F_RANDOM; break; } UnLock(); @@ -573,6 +597,7 @@ int Locomotives::Loop() { if (loco->flags & LOCO_F_REVERSE) reverse = -1; else reverse = 1; + if (loco->flags & LOCO_F_AUTO) { // // only in automate do anything alone @@ -589,7 +614,37 @@ int Locomotives::Loop() { // find way, if nothing found check if we can reverse direction // if (loco->auto_timenext.tv_sec == 0 || timer_get(&loco->auto_timenext) > LOCO_TO_TRYAGAIN) { - if (server->railways.FindWay(loco->blockassign, loco->blockdest, loco->name, &way)) { + debug (0, "* Loco Loop Search '%s' Reverse:%d", loco->name, reverse);; + if (loco->blockdest[0] == 0) { + if (loco->flags & LOCO_F_RANDOM) + if (server->railways.FindRandomWay(loco->blockassign, loco->name, &way)) { + size_t pos; + if ((pos = way.find(",b:", 1)) != string::npos) { + strncpy (loco->blocknext, way.substr(pos+3,string::npos).c_str(), REFERENCENAME_LEN); + strncpy (loco->auto_way, way.c_str(), WAYDATA_LEN); + if (server->railways.LockWay(way, loco->name) == 1) { + loco->auto_data = -1; + loco->auto_onroute = LOCO_OR_PREPARE; + } + else { + server->railways.UnLockWay(way, loco->name); + timer_start(&loco->auto_timenext); + } + } + } + else { + if (loco->blockassign[0] != 0 && (loco->flags & LOCO_F_CANREVERSE)) { + debug (0, "* Reverse Loco %s", loco->name); + if (loco->blockassign[0] == '-') loco->blockassign[0] = '+'; + else if (loco->blockassign[0] == '+') loco->blockassign[0] = '-'; + + if (loco->flags & LOCO_F_REVERSE) loco->flags &= ~LOCO_F_REVERSE; + else loco->flags |= LOCO_F_REVERSE; + } + timer_start(&loco->auto_timenext); + } + } + else if (server->railways.FindWay(loco->blockassign, loco->blockdest, loco->name, &way)) { size_t pos; if ((pos = way.find(",b:", 1)) != string::npos) { @@ -599,11 +654,16 @@ int Locomotives::Loop() { loco->auto_data = -1; loco->auto_onroute = LOCO_OR_PREPARE; } - else timer_start(&loco->auto_timenext); + else { + server->railways.UnLockWay(way, loco->name); + timer_start(&loco->auto_timenext); + } } } else { if (loco->blockassign[0] != 0 && (loco->flags & LOCO_F_CANREVERSE)) { + debug (0, "* Reverse Loco %s", loco->name); + if (loco->blockassign[0] == '-') loco->blockassign[0] = '+'; else if (loco->blockassign[0] == '+') loco->blockassign[0] = '-'; @@ -640,7 +700,7 @@ int Locomotives::Loop() { sensor = server->blocks.GetSensorPlus(block); if (server->sensors.GetActive(sensor) == 1) { // entering block? - debug (0, "* Locomotive '%s' Enter Block '%s'", loco->name, loco->blocknext); + debug (0, "* Locomotive '%s' EnterBlock '%s'", loco->name, loco->blocknext); // unlock old assigned block if (loco->blockassign[0] != 0) { server->blocks.SetLockedby((string)(loco->blockassign+2), loco->name, 0); @@ -662,7 +722,25 @@ int Locomotives::Loop() { else { // try to find new way printf ("%s:%d LOCO_OR_ONTHEWAY try to find new way\n", __FILE__, __LINE__); - if (server->railways.FindWay(loco->blockassign, loco->blockdest, loco->name, &way)) { + if (loco->blockdest[0] == 0) { + if (loco->flags & LOCO_F_RANDOM) + if (server->railways.FindRandomWay(loco->blockassign, loco->name, &way)) { + size_t pos; + if ((pos = way.find(",b:", 1)) != string::npos) { + strncpy (loco->blocknext, way.substr(pos+3,string::npos).c_str(), REFERENCENAME_LEN); + strncpy (loco->auto_way, way.c_str(), WAYDATA_LEN); + if (server->railways.LockWay(way, loco->name) == 1) { + loco->auto_data = -1; + loco->auto_onroute = LOCO_OR_ENTERBLOCKNEXT; + } + else { + server->railways.UnLockWay(way, loco->name); + timer_start(&loco->auto_timenext); + } + } + } + } + else if (server->railways.FindWay(loco->blockassign, loco->blockdest, loco->name, &way)) { size_t pos; if ((pos = way.find(",b:", 1)) != string::npos) { @@ -688,7 +766,6 @@ int Locomotives::Loop() { } } - jp.Clear(); jp.AddObject("locomotive",_GetJSON(lnum)); if(network) network->ChangeListPushToAll(jp.ToString()); @@ -710,10 +787,11 @@ int Locomotives::Loop() { sensor = server->blocks.GetSensorMinus(block); if (server->sensors.GetActive(sensor) == 1) { - debug (0, "Locomotives::Loop '%s' UnLockWay\n", loco->name); + debug (0, "Locomotives::Loop EnterBlockStop '%s' UnLockWay\n", loco->name); SetSpeed(loco->name, 0); loco->auto_onroute = LOCO_OR_STOPWAIT; server->railways.UnLockWay(loco->auto_wayold, loco->name); + server->blocks.SetLockedby(loco->blockprev+2, loco->name, 0); loco->auto_wayold[0] = 0; jp.Clear(); jp.AddObject("locomotive",_GetJSON(lnum)); @@ -740,7 +818,10 @@ int Locomotives::Loop() { sensor = server->blocks.GetSensorMinus(block); if (server->sensors.GetActive(sensor) == 1) { + debug (0, "Locomotives::Loop EnterBlockNext '%s' UnLockWay\n", loco->name); + server->railways.UnLockWay(loco->auto_wayold, loco->name); + server->blocks.SetLockedby(loco->blockprev+2, loco->name, 0); loco->auto_wayold[0] = 0; if (finish == 0) { // stop train if not finished diff --git a/server/locomotive.h b/server/locomotive.h index 256fafc..6002f1a 100644 --- a/server/locomotive.h +++ b/server/locomotive.h @@ -105,6 +105,7 @@ class Locomotives { int SetFunctionFromBus (string ifname, int addr, int func); int SetDestination (string name, string block, int direction); int SetAssign (string name, string block, int direction); + int GetFlags(string name); int AutoCheckWaySingleStep(string way, string locname, int *data); int Loop(); diff --git a/server/railway.cc b/server/railway.cc index cacbce7..b1a407d 100644 --- a/server/railway.cc +++ b/server/railway.cc @@ -502,6 +502,7 @@ int Railways::FindWay(string blockstart, string blockend, string lockedfor, stri string lockedby; int i, x ,y; int found = 0; + int locoflags = server->locomotives.GetFlags(lockedfor); // check blocklen if (blockstart.length() <= 3 || blockend.length() <= 3) return 0; @@ -678,7 +679,11 @@ int Railways::FindWay(string blockstart, string blockend, string lockedfor, stri // if block is off ignore it completly else if (rpos->type == RAILWAY_BLOCK) { printf ("%s:%d block found\n", __FILE__, __LINE__); - if (server->blocks.IsOff(rpos->name)) { + int blflags = server->blocks.GetFlags(rpos->name); + + if ((server->blocks.IsOff(rpos->name) || + ((blflags & BLOCK_F_ENDSTATION) && !(locoflags & LOCO_F_CANREVERSE)) || + ((blflags & BLOCK_F_SHORT) && !(locoflags & LOCO_F_SHORTTRAIN)))) { printf ("%s:%d block is off\n", __FILE__, __LINE__); fd_pos.enterfrom = -1; fd_pos.x = -1; @@ -743,6 +748,242 @@ int Railways::FindWay(string blockstart, string blockend, string lockedfor, stri }; +int Railways::FindRandomWay(string blockstart, string lockedfor, string *next) { + // direction 0 ... RIGHT and DOWN + // direction 1 ... LEFT and UP + struct s_findway_data fd_pos; + struct s_findway_data fd_tmp; + struct s_findway_data fd_start; + struct s_findway_data fd_end; + Railway *rpos, *rnext; + std::list fd_list; + struct s_findway_map *fd_data = NULL; + string lockedby; + int i, x ,y; + int found = 0; + int locoflags = server->locomotives.GetFlags(lockedfor); + + debug (0, "Railway::FindRandomWay"); + + // check blocklen + if (blockstart.length() <= 3) return 0; + + // allocate and clear memory for checked data + fd_data = (struct s_findway_map *) malloc (sizeof(struct s_findway_map) * width * height); + if (fd_data == NULL) { + printf ("%s:%d (%s) FATAL ERROR: could not allocate enough memory\n", __FILE__, __LINE__, __FUNCTION__); + exit (1); + } + memset (fd_data, 0x0, sizeof(struct s_findway_map) * width*height); + + // + // find start and endpoint mark on fd_data, also startpoint to fd_list + fd_end.x = fd_start.x = -1; + fd_end.y = fd_start.y = -1; + fd_end.enterfrom = fd_start.enterfrom = -1; + fd_end.parma = fd_start.parma = -1; + + if (FindReference(&fd_start.x, &fd_start.y, blockstart.substr(2, string::npos))) { + if (Get(fd_start.x, fd_start.y).dir == 1) { + if (blockstart[0] == '+') fd_start.enterfrom = 0; + else fd_start.enterfrom = 2; + } + else { + if (blockstart[0] == '+') fd_start.enterfrom = 3; + else fd_start.enterfrom = 1; + } + fd_start.way = "b:" + blockstart; + fd_data[GetRIdx(fd_start.x, fd_start.y)].e = (1 << fd_start.enterfrom); + fd_data[GetRIdx(fd_start.x, fd_start.y)].score = 1; + fd_start.parma = 1; + } + else { + debug (0, "Railway::FindRandomWay could not find startblock (%s).", blockstart.c_str()); + free (fd_data); + return 0; + } + + fd_pos = NextPos(fd_start, Get(fd_start.x, fd_start.y).dir); + Lock(); + + // + // loop through the map to find all possible ways to the destination + // this will be done in respect of lockedby blocks and ways. + // + while ((fd_list.size() > 0 || fd_pos.enterfrom >= 0) && found == 0) { + // DebugPrintFindWay(fd_data); + if (fd_pos.enterfrom < 0) { + std::list::iterator iter; + + iter = fd_list.begin(); + if (iter != fd_list.end()) { + fd_pos = *iter; + fd_list.pop_front(); + // printf ("get from stack (%d,%d)\n", fd_pos.x, fd_pos.y); + } + } + + // printf ("%s:%d fd_start (%d,%d) enterfrom:%d\n", __FILE__, __LINE__, fd_start.x, fd_start.y, fd_start.enterfrom); + // printf ("%s:%d fd_end (%d,%d) enterfrom:%d\n", __FILE__, __LINE__, fd_end.x, fd_end.y, fd_end.enterfrom); + // printf ("%s:%d fd_pos (%d,%d) enterfrom:%d\n", __FILE__, __LINE__, fd_pos.x, fd_pos.y, fd_pos.enterfrom); + if (fd_pos.enterfrom < 0 && fd_pos.enterfrom > 3) { + fd_pos.enterfrom = -1; + fd_pos.x = -1; + fd_pos.y = -1; + fd_pos.way = ""; + } + else if (fd_pos.enterfrom >= 0 && fd_start.x == fd_pos.x && fd_start.y == fd_pos.y && fd_start.enterfrom == fd_pos.enterfrom) { + // start found + fd_pos.enterfrom = -1; + fd_pos.x = -1; + fd_pos.y = -1; + fd_pos.way = ""; + } + else if (fd_data[GetRIdx(fd_pos.x, fd_pos.y)].e & (1 << fd_pos.enterfrom)) { + // old entry found + fd_pos.enterfrom = -1; + fd_pos.x = -1; + fd_pos.y = -1; + fd_pos.way = ""; + } + else if (fd_pos.enterfrom >= 0) { + rpos = &railways[GetRIdx(fd_pos.x, fd_pos.y)]; + fd_data[GetRIdx(fd_pos.x, fd_pos.y)].e |= (1 << fd_pos.enterfrom); + + if (rpos->type == RAILWAY_NORMAL || rpos->type == RAILWAY_SENSOR) { + fd_pos = NextPos(fd_pos, rpos->dir); + fd_pos.parma++; + rnext = &railways[GetRIdx(fd_pos.x, fd_pos.y)]; + if (rnext->lockedby[0] != 0) { + fd_pos.enterfrom = -1; + fd_pos.x = -1; + fd_pos.y = -1; + fd_pos.way = ""; + } + } + + else if (rpos->type == RAILWAY_TURNOUT) { + // random turn or no turn + if (rand() & 1 == 1) { + fd_tmp = NextPos(fd_pos, rpos->altdir); + fd_tmp.way += (string)",t:" + (string)rpos->name + (string)":1"; + fd_tmp.parma += 10; // 10 bad point for using the turnout + fd_list.push_back(fd_tmp); + fd_pos = NextPos(fd_pos, rpos->dir); + fd_pos.way += (string)",t:" + (string)rpos->name + (string)":0"; + fd_pos.parma++; + } + else { + fd_tmp = NextPos(fd_pos, rpos->dir); + fd_tmp.way += (string)",t:" + (string)rpos->name + (string)":0"; + fd_tmp.parma += 10; // 10 bad point for using the turnout + fd_list.push_back(fd_tmp); + fd_pos = NextPos(fd_pos, rpos->altdir); + fd_pos.way += (string)",t:" + (string)rpos->name + (string)":1"; + fd_pos.parma++; + } + } + + else if (rpos->type == RAILWAY_CONNECTOR) { + int found = 0; + + x = -1; + y = -1; + while (found == 0 && _FindReference(&x, &y, rpos->name) == 1) { + if (fd_pos.x != x || fd_pos.y != y) { + fd_pos.oldx = fd_pos.x; + fd_pos.oldy = fd_pos.y; + fd_pos.oldenterfrom = fd_pos.enterfrom; + fd_pos.x = x; + fd_pos.y = y; + rpos = &railways[GetRIdx(fd_pos.x, fd_pos.y)]; + fd_pos = NextPos(fd_pos, rpos->dir); + fd_pos.parma++; + found = 1; + break; + } + } + + if (found == 0) { + fd_pos.enterfrom = -1; + fd_pos.x = -1; + fd_pos.y = -1; + fd_pos.way = ""; + } + } + // + // if block is off ignore it completly + else if (rpos->type == RAILWAY_BLOCK) { + int blflags = server->blocks.GetFlags(rpos->name); + + if ((server->blocks.IsOff(rpos->name) || + ((blflags & BLOCK_F_ENDSTATION) && !(locoflags & LOCO_F_CANREVERSE)) || + ((blflags & BLOCK_F_SHORT) && !(locoflags & LOCO_F_SHORTTRAIN)))) { + fd_pos.enterfrom = -1; + fd_pos.x = -1; + fd_pos.y = -1; + fd_pos.way = ""; + } + else { + // lockedby = server->blocks.GetLockedby(rpos->name); + lockedby = server->blocks.GetLockedby(rpos->name); + if (lockedby.length() == 0 || lockedby.compare(lockedfor) == 0) { + if (fd_pos.enterfrom == 0 || fd_pos.enterfrom == 3) + fd_pos.way += (string)",b:+:" + (string)rpos->name; + else fd_pos.way += (string)",b:-:" + (string)rpos->name; + + *next = fd_pos.way + ",b:" + (string)rpos->name; + fd_pos.enterfrom = -1; + fd_pos.x = -1; + fd_pos.y = -1; + fd_pos.way = ""; + found = 1; + } + else { + fd_pos.enterfrom = -1; + fd_pos.x = -1; + fd_pos.y = -1; + fd_pos.way = ""; + } + } + } + + else { // finished nothing more to check + fd_pos.enterfrom = -1; + fd_pos.x = -1; + fd_pos.y = -1; + fd_pos.way = ""; + } + } + } + + if (found == 0) *next = ""; + else { + // + // next = "b:+blockname,t:name:0,t:name:1,b:-blockname" + debug (0, "* Random Temp Next: %s", next->c_str()); + int i; + i = 0; + size_t npos; + if ((npos = next->find(",b:")) != string::npos) { + *next = next->substr(0, next->find(",", npos+1)); + debug (0, "* Random next: '%s' found", next->c_str()); + } + else { + // nothing found? + debug (0, "* Random Nothing Found next: '%s' but no next block?", next->c_str()); + *next = ""; + } + } + UnLock(); + + free (fd_data); + + return found; +} + + + int Railways::LockWay (string way, string lockedby, int lockonoff) { int res = 0; size_t pos1, pos2; @@ -832,17 +1073,20 @@ int Railways::LockWay (string way, string lockedby, int lockonoff) { // do lock start and endpoint... unlock only start if (pos.x == end.x && pos.y == end.y && r->type == RAILWAY_BLOCK) { if (lockonoff == 1) { + UnLock(); server->blocks.SetLockedby(r->name, lockedby, 1); strncpy (r->lockedby, lockedby.c_str(), REFERENCENAME_LEN); + Lock(); jp.Clear(); jp.AddObject("railway",_GetJSONRailway(pos.x, pos.y)); if(network) network->ChangeListPushToAll(jp.ToString()); } } else if (pos.x == start.x && pos.y == start.y && r->type == RAILWAY_BLOCK) { - server->blocks.SetLockedby(r->name, lockedby, lockonoff); + UnLock(); + if (lockonoff) server->blocks.SetLockedby(r->name, lockedby, lockonoff); if (lockonoff) strncpy (r->lockedby, lockedby.c_str(), REFERENCENAME_LEN); - else r->lockedby[0] = 0; + Lock(); jp.Clear(); jp.AddObject("railway",_GetJSONRailway(pos.x, pos.y)); if(network) network->ChangeListPushToAll(jp.ToString()); diff --git a/server/railway.h b/server/railway.h index 8e2d73a..df259b7 100644 --- a/server/railway.h +++ b/server/railway.h @@ -127,6 +127,7 @@ class Railways { int FindReference(int *x, int *y, string name); int FindWay(string blockstart, string blockend, string lockedfor, string *next); + int FindRandomWay(string blockstart, string lockedfor, string *next); int LockWay (string way, string lockedby, int lockonoff); int LockWay (string way, string lockedby) { return LockWay(way, lockedby, 1); }; int UnLockWay (string way, string lockedby) { return LockWay(way, lockedby, 0); }; diff --git a/webinterface/block.js b/webinterface/block.js index 651d688..41b58ec 100644 --- a/webinterface/block.js +++ b/webinterface/block.js @@ -394,9 +394,13 @@ function blockdetail_getData() { if (name) res.name = name.value; if (flagoff.checked) res.flags |= BLOCK_F_OFF; + else res.flags &= ~BLOCK_F_OFF; if (flagshort.checked) res.flags |= BLOCK_F_SHORT; + else res.flags &= ~BLOCK_F_SHORT; if (flaglong.checked) res.flags |= BLOCK_F_LONG; + else res.flags &= ~BLOCK_F_LONG; if (flagend.checked) res.flags |= BLOCK_F_ENDSTATION; + else res.flags &= ~BLOCK_F_ENDSTATION; if (flagspeedlimit.checked) res.flags |= BLOCK_F_SPEEDLIMIT; if (sensorLU) res.sensor_pos_1 = sensorLU.value; if (sensorC) res.sensor_center = sensorC.value;