diff --git a/server/locomotive.cc b/server/locomotive.cc index 1823535..0a875b1 100644 --- a/server/locomotive.cc +++ b/server/locomotive.cc @@ -729,29 +729,326 @@ void::Locomotives::SendUpdate (Locomotive *loc) { } -int Locomotives::Loop() { - int lnum; +/* + * locomotive searching for a new way + * loco->way and loco->blocknext will be overwritten + * loco->way must be saved to loco->wayold before calling this function + * it will not set the auto_onroute step + */ +int Locomotives::Loco_SearchAndLock(Locomotive *loco) { string way; - Locomotive *loco = NULL; + + + // + // try to find and prepare(lock) a new way. + // nothing found check if we can reverse direction, this will be done only + // once a second (LOCO_TO_TRYAGAIN) + // + // destination empty? true -> random + // false -> find way to destination + if (loco->auto_timenext.tv_sec == 0 || timer_get(&loco->auto_timenext) > LOCO_TO_TRYAGAIN) { + debug (0, "Locomotives::Loop Search '%s' Reverse:%d", loco->name, loco->flags && LOCO_F_REVERSE ? 1 : 0); + timer_start(&loco->auto_timenext); + + // + // destination set? - need to find a random block? + if (loco->blockdest[0] == 0) { + if (loco->flags & LOCO_F_RANDOM) { + if (server->railways.FindRandomWay(loco->blockassign, loco->name, &way)) { + size_t pos, pos1; + if ((pos = way.find(",b:", 1)) != string::npos) { + if ((pos1 = way.find(",", pos+3)) != string::npos) { + strncpy (loco->blocknext, way.substr(pos+3, pos1-(pos+3)).c_str(), REFERENCENAME_LEN); + } + else 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; + return 1; + } + server->railways.UnLockWay(way, loco->name); + } + } + else { + // nothing found -> try reverse + if (loco->blockassign[0] != 0 && (loco->flags & LOCO_F_CANREVERSE)) { + debug (0, "* Loco_SearchAndLock 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; + } + } + } + else { + SchedulerNextStep(loco); + } + } + + // + // we assume a destination is set, and try to find a new way to the destination + else if (server->railways.FindWay(loco->blockassign, loco->blockdest, loco->name, &way)) { + // try to lock way. + size_t pos, pos1; + debug (0, "Locomotives::Loop %s:%d Found Way:%s", __FILE__, __LINE__, way.c_str()); + if ((pos = way.find(",b:", 1)) != string::npos) { + if ((pos1 = way.find(",", pos+3)) != string::npos) { + strncpy (loco->blocknext, way.substr(pos+3, pos1-(pos+3)).c_str(), REFERENCENAME_LEN); + } + else 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; + return 1; + } + server->railways.UnLockWay(way, loco->name); + timer_start(&loco->auto_timenext); + } + } + } + + return 0; +} + + +/* + * prepare to lock the way set up in way + * the way is set and locked already, The turnouts will be set one by one with a time delay + * between the commands. All turnouts will get a SetWay command in case some turnout was set + * manualy without feedback to the server. + */ +int Locomotives::Loco_PrepareWay(Locomotive *loco) { + string block; + + block = ((string)(loco->blocknext+2)).substr(0, ((string)(loco->blocknext+2)).find(",")); + + if (loco->auto_timenext.tv_sec == 0 || timer_get(&loco->auto_timenext) > LOCO_TO_TURNOUT) { + if (AutoCheckWaySingleStep(loco->auto_way, loco->name, &loco->auto_data) == 1) { + if ((loco->flags & LOCO_F_CARGO) || + (server->blocks.GetFlags(block) & BLOCK_F_SPEEDLIMIT)) return 1; + else return 2; + } + timer_start(&loco->auto_timenext); + } + + return 0; +} + + +/* + * loco is on route, check if entered a block + * returns if we entered the block, set the locos speed + * search for next way and set auto_onroute to LOCO_OR_ENTERBLOCKNEXT or ENTERBLOCKSTOP + * copy way to wayold. If a new way is found set the way if not leave empty + */ +int Locomotives::Loco_OnRoute(Locomotive *loco) { + string block; + string s_enter; + string s_slow; + string s_stop; + string s_shortstop; + int dir_reverse = 0; + char *tmpc = NULL; + string way; + + // FIXME: move this code to the block class -> we will need a better code for multiple sensors + // + // the train is on the way, check for entering the block. + // + block = ((string)(loco->blocknext+2)).substr(0, ((string)(loco->blocknext+2)).find(",")); + + if (loco->blocknext[0] == '-') dir_reverse = 1; + else dir_reverse = 0; + + s_shortstop = server->blocks.GetSensorShortStop(dir_reverse, block); + s_stop = server->blocks.GetSensorStop(dir_reverse, block); + s_slow = server->blocks.GetSensorSlow(dir_reverse, block); + s_enter = server->blocks.GetSensorEnter(dir_reverse, block); + + if ( server->sensors.GetActive(s_enter) == 1 || server->sensors.GetActive(s_stop) == 1 || + server->sensors.GetActive(s_slow) == 1 || server->sensors.GetActive(s_shortstop) == 1) { // entering block? + + debug (0, "* Locomotive '%s' EnterBlock '%s'", loco->name, loco->blocknext); + debug (0, "* %s,%d Sensor Enter '%s' = %d", __FILE__, __LINE__, s_enter.c_str(), server->sensors.GetActive(s_enter)); + debug (0, "* %s,%d Sensor Slow '%s' = %d", __FILE__, __LINE__, s_slow.c_str(), server->sensors.GetActive(s_slow)); + debug (0, "* %s,%d Sensor Sh.Stop '%s' = %d", __FILE__, __LINE__, s_shortstop.c_str(), server->sensors.GetActive(s_shortstop)); + debug (0, "* %s,%d Sensor Stop '%s' = %d", __FILE__, __LINE__, s_stop.c_str(), server->sensors.GetActive(s_stop)); + + // assignment <-- next, the assignment has to be checked + // against long trains and split blocks + // check if we need to clear dest + strncpy (loco->blockprev, loco->blockassign, REFERENCENAME_LEN); + tmpc = strstr (loco->blocknext, ",b:"); + if (tmpc) { + strncpy (loco->blockassign, tmpc+3, REFERENCENAME_LEN); + strncpy (loco->blockassignsplit, loco->blocknext, REFERENCENAME_LEN); + } + else { + strncpy (loco->blockassign, loco->blocknext, REFERENCENAME_LEN); + loco->blockassignsplit[0] = 0; + } + strncpy (loco->auto_wayold, loco->auto_way, WAYDATA_LEN); + loco->auto_way[0] = 0; + loco->blocknext[0] = 0; + debug (0, "Locomotive::Loop Loco:'%s' Prev:'%s' Assign:'%s' AssignSplit:'%s' Next:'%s'", + loco->name, loco->blockprev, loco->blockassign, loco->blockassignsplit, loco->blocknext); + + // + if (Loco_SearchAndLock(loco) == 1) { + loco->auto_onroute = LOCO_OR_ENTERBLOCKNEXT; + debug (0, "Locomotives::Loco_OnRoute Found Way Prepare '%s'\n", loco->name); + SetSpeed(loco->name, loco->vmid); + } + else { + loco->auto_onroute = LOCO_OR_ENTERBLOCKSTOP; + debug (0, "Locomotives::Loco_OnRoute Slow Down '%s'\n", loco->name); + SetSpeed(loco->name, loco->vslow); + } + return 1; + + } + return 0; +} + + + +/* + * loco entered a block, check if need to stop + */ +int Locomotives::Loco_BlockEnterStop(Locomotive *loco) { + string block; + string s_enter; + string s_slow; + string s_stop; + string s_shortstop; + int dir_reverse = 0; + string way; + + // + // check if the train is in its stop position + // + block = ((string)(loco->blocknext+2)).substr(0, ((string)(loco->blocknext+2)).find(",")); + + if (loco->blockassign[0] == '-') dir_reverse = 1; + else dir_reverse = 0; + + s_shortstop = server->blocks.GetSensorShortStop(dir_reverse, block); + s_stop = server->blocks.GetSensorStop(dir_reverse, block); + s_slow = server->blocks.GetSensorSlow(dir_reverse, block); + s_enter = server->blocks.GetSensorEnter(dir_reverse, block); + + if ( server->sensors.GetActive(s_stop) == 1 || + ((loco->flags & LOCO_F_SHORTTRAIN) && server->sensors.GetActive(s_shortstop) == 1)) { + + 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; + timer_start(&loco->auto_timenext); + } + + return 0; +} + + +/* + * loco entered a block, check if need to stop + */ +int Locomotives::Loco_BlockEnterNext(Locomotive *loco) { + int dir_reverse; string block; string s_enter; string s_slow; string s_stop; string s_shortstop; + string way; + + // + // check if the train is in its stop position + // + block = ((string)(loco->blockassign+2)).substr(0, ((string)(loco->blockassign+2)).find(",")); + + if (loco->blockassign[0] == '-') dir_reverse = 1; + else dir_reverse = 0; + + s_shortstop = server->blocks.GetSensorShortStop(dir_reverse, block); + s_stop = server->blocks.GetSensorStop(dir_reverse, block); + s_slow = server->blocks.GetSensorSlow(dir_reverse, block); + s_enter = server->blocks.GetSensorEnter(dir_reverse, block); + + if ( server->sensors.GetActive(s_stop) == 1 || + ((loco->flags & LOCO_F_SHORTTRAIN) && server->sensors.GetActive(s_shortstop) == 1)) { + + if (loco->auto_timenext.tv_sec > 0) { + // + // end of block and not finished preparing the way. + // stop everything + debug (0, "Locomotives::Loco_BlockEnterNext ********** Loco:%s could not prepare way in time. STOP", loco->name); + server->PowerOnOff(0); + return 0; + } + else { + debug (0, "* Locomotives::Loco_BlockEnterNext endblock reached %s", 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 ((loco->flags & LOCO_F_CARGO) || + (server->blocks.GetFlags(block) & BLOCK_F_SPEEDLIMIT)) return 1; + else return 2; + } + } + + if (loco->auto_timenext.tv_sec > 0 && timer_get(&loco->auto_timenext) > LOCO_TO_TURNOUT) { + debug (0, "* Locomotives::Loco_BlockEnterNext prepare way for loco: %s", loco->name); + if (AutoCheckWaySingleStep(loco->auto_way, loco->name, &loco->auto_data) == 1) { + // + // finished preparing new way, need to stay in ENTERBLOCKNEXT to unlock old way + debug (0, "* Locomotives::Loco_BlockEnterNext finished preparing way for loco: %s", loco->name); + loco->auto_timenext.tv_sec = 0; + } + else timer_start(&loco->auto_timenext); + } + + return 0; +} + + +/* + * loco stopped on block, wait some time and continue with the next destination + */ +int Locomotives::Loco_BlockStopWait(Locomotive *loco) { + if (loco->auto_timenext.tv_sec == 0 || timer_get(&loco->auto_timenext) > 5000) { + if (loco->blockdest[0] != 0) loco->auto_onroute = LOCO_OR_SEARCH; + else loco->auto_onroute = LOCO_OR_NOTHING; + } + return 1; +} + + + +int Locomotives::Loop() { + int lnum; + string way; + Locomotive *loco = NULL; JSONParse jp; int reverse = 1; - int dir_reverse = 0; for (lnum = 0; lnum < max; lnum++) if (locomotives[lnum].name[0] != 0) { loco = &locomotives[lnum]; - if (loco->flags & LOCO_F_REVERSE) reverse = -1; - else reverse = 1; - if (loco->flags & LOCO_F_AUTO) { // // only in automate do anything alone // + debug (0, "* Locomotives::Loop (%s:%d) Loco:%s auto_onroute:%d assign:'%s' assignsplit:'%s' next:'%s' prev:'%s' dest:'%s' way:'%s' wayold:'%s'" + , __FILE__, __LINE__, loco->name, loco->auto_onroute, loco->blockassign, loco->blockassignsplit + , loco->blocknext, loco->blockprev, loco->blockdest, loco->auto_way, loco->auto_wayold); + if (loco->blockassign[0] == 0) { debug (0, "%s:%d Locomotive [%s] not assigned to any block. Set Mode to Man", __FILE__, __LINE__, loco->name); SetModeMan(loco->name); @@ -759,8 +1056,7 @@ int Locomotives::Loop() { } if (loco->auto_onroute == LOCO_OR_NOTHING) { - // - // check if the loco mode is set to autostop + // loco mode is set to autostop -> set loco to man if (loco->flags & LOCO_F_AUTOSTOP) { SetModeMan(loco->name); continue; @@ -771,307 +1067,88 @@ int Locomotives::Loop() { } } + // + // else if (loco->auto_onroute == LOCO_OR_SEARCH) { - // - // check if the loco mode is set to autostop + // loco mode is set to autostop -> set loco to man if (loco->flags & LOCO_F_AUTOSTOP) { SetModeMan(loco->name); continue; } - // - // try to find and prepare(lock) a new way. - // nothing found check if we can reverse direction, this will be done only - // once a second (LOCO_TO_TRYAGAIN) - // - // destination empty? true -> random - // false -> find way to destination - if (loco->auto_timenext.tv_sec == 0 || timer_get(&loco->auto_timenext) > LOCO_TO_TRYAGAIN) { - debug (0, "Locomotives::Loop Search '%s' Reverse:%d", loco->name, reverse); - timer_start(&loco->auto_timenext); - - // - // destination set? - need to find a random block? - 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); - } - } - } - else { - // nothing found -> try reverse - 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; - } - } - } - else { - SchedulerNextStep(loco); - } - } - - // - // we assume a destination is set, and try to find a new way to the destination - else if (server->railways.FindWay(loco->blockassign, loco->blockdest, loco->name, &way)) { - // try to lock way. - size_t pos; - debug (0, "Locomotives::Loop %s:%d Found Way:%s", __FILE__, __LINE__, way.c_str()); - 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 { - // no way found, can we reverse? - 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); - } + // try to find and lock a way + if (Loco_SearchAndLock(loco)) { + loco->auto_onroute = LOCO_OR_PREPARE; } } + // + // else if (loco->auto_onroute == LOCO_OR_PREPARE) { - // - // the way is set and locked already, The turnouts will be set one by one with a time delay - // between the commands. All turnouts will get a SetWay command in case some turnout was set - // manualy without feedback to the server. - // - block = ((string)(loco->blocknext+2)).substr(0, ((string)(loco->blocknext+2)).find(",")); - - if (loco->auto_timenext.tv_sec == 0 || timer_get(&loco->auto_timenext) > LOCO_TO_TURNOUT) { - if (AutoCheckWaySingleStep(loco->auto_way, loco->name, &loco->auto_data) == 1) { - // all turnouts are set, start the train. - debug (0, "* Locomotive '%s' Way Locked Start", loco->name); - if ((loco->flags & LOCO_F_CARGO) || - (server->blocks.GetFlags(block) & BLOCK_F_SPEEDLIMIT)) - SetSpeed(loco->name, reverse * loco->vmid); - else SetSpeed(loco->name, reverse * loco->vfast); - loco->auto_onroute = LOCO_OR_ONTHEWAY; - } - else timer_start(&loco->auto_timenext); + switch (Loco_PrepareWay(loco)) { + case 1: + SetSpeed(loco->name, reverse * loco->vmid); + loco->auto_onroute = LOCO_OR_ONTHEWAY; + debug (0, "* Locomotive '%s' Way Prepared -> Speed: VMID", loco->name); + jp.Clear(); + jp.AddObject("locomotive",_GetJSON(lnum)); + if(network) network->ChangeListPushToAll(jp.ToString()); + break; + case 2: + SetSpeed(loco->name, reverse * loco->vfast); + loco->auto_onroute = LOCO_OR_ONTHEWAY; + debug (0, "* Locomotive '%s' Way Prepared -> Speed: VFAST", loco->name); + jp.Clear(); + jp.AddObject("locomotive",_GetJSON(lnum)); + if(network) network->ChangeListPushToAll(jp.ToString()); + break; + default: + break; } } else if (loco->auto_onroute == LOCO_OR_ONTHEWAY) { - // FIXME: move this code to the block class -> we will need a better code for multiple sensors - // - // the train is on the way, check for entering the block. - // - block = ((string)(loco->blocknext+2)).substr(0, ((string)(loco->blocknext+2)).find(",")); - - if (loco->blocknext[0] == '-') dir_reverse = 1; - else dir_reverse = 0; - - s_shortstop = server->blocks.GetSensorShortStop(dir_reverse, block); - s_stop = server->blocks.GetSensorStop(dir_reverse, block); - s_slow = server->blocks.GetSensorSlow(dir_reverse, block); - s_enter = server->blocks.GetSensorEnter(dir_reverse, block); - - if ( server->sensors.GetActive(s_enter) == 1 || server->sensors.GetActive(s_stop) == 1 || - server->sensors.GetActive(s_slow) == 1 || server->sensors.GetActive(s_shortstop) == 1) { // entering block? - - debug (0, "* Locomotive '%s' EnterBlock '%s'", loco->name, loco->blocknext); - debug (0, "* %s,%d Sensor Enter '%s' = %d", __FILE__, __LINE__, s_enter.c_str(), server->sensors.GetActive(s_enter)); - debug (0, "* %s,%d Sensor Slow '%s' = %d", __FILE__, __LINE__, s_slow.c_str(), server->sensors.GetActive(s_slow)); - debug (0, "* %s,%d Sensor Sh.Stop '%s' = %d", __FILE__, __LINE__, s_shortstop.c_str(), server->sensors.GetActive(s_shortstop)); - debug (0, "* %s,%d Sensor Stop '%s' = %d", __FILE__, __LINE__, s_stop.c_str(), server->sensors.GetActive(s_stop)); - - // unlock old assigned block - if (loco->blockassign[0] != 0) server->blocks.SetLockedby((string)(loco->blockassign+2), loco->name, 0); - - // assignment <-- next - // check if we need to clear dest - strncpy (loco->blockprev, loco->blockassign, REFERENCENAME_LEN); - strncpy (loco->blockassign, loco->blocknext, REFERENCENAME_LEN); - strncpy (loco->auto_wayold, loco->auto_way, WAYDATA_LEN); - loco->auto_way[0] = 0; - loco->blocknext[0] = 0; - - // - // if destination reached or AUTO-MAN mode: stop train. - if ((strncmp(loco->blockassign, loco->blockdest, REFERENCENAME_LEN) == 0) - || (loco->flags & LOCO_F_AUTOSTOP)) { - printf ("%s:%d LOCO_OR_ONTHEWAY enter assign == dest stop train\n", __FILE__, __LINE__); - loco->blockdest[0] = 0; - loco->auto_onroute = LOCO_OR_ENTERBLOCKSTOP; - SetSpeed(loco->name, reverse * loco->vslow); - } - - // - // if not try to find next block. - else { - printf ("%s:%d LOCO_OR_ONTHEWAY try to find new way\n", __FILE__, __LINE__); - if (loco->blockdest[0] == 0) { - if ((loco->flags & LOCO_F_RANDOM) && ((loco->flags & LOCO_F_CARGO) || !(server->blocks.GetFlags(block) & BLOCK_F_STATION))) - 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) { - 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 { - loco->auto_onroute = LOCO_OR_ENTERBLOCKSTOP; - SetSpeed(loco->name, reverse * loco->vslow); - } - } - else { - loco->auto_onroute = LOCO_OR_ENTERBLOCKSTOP; - SetSpeed(loco->name, reverse * loco->vslow); - } - } - else { - loco->auto_onroute = LOCO_OR_ENTERBLOCKSTOP; - SetSpeed(loco->name, reverse * loco->vslow); - } - } - + if (Loco_OnRoute(loco)) { jp.Clear(); jp.AddObject("locomotive",_GetJSON(lnum)); if(network) network->ChangeListPushToAll(jp.ToString()); - - if (loco->auto_onroute == LOCO_OR_ONTHEWAY) { - loco->auto_onroute = LOCO_OR_ENTERBLOCKSTOP; - SetSpeed(loco->name, reverse * loco->vslow); - } } + } else if (loco->auto_onroute == LOCO_OR_ENTERBLOCKSTOP) { - // - // check if the train is in its stop position - // - block = ((string)(loco->blocknext+2)).substr(0, ((string)(loco->blocknext+2)).find(",")); - - if (loco->blockassign[0] == '-') dir_reverse = 1; - else dir_reverse = 0; - - s_shortstop = server->blocks.GetSensorShortStop(dir_reverse, block); - s_stop = server->blocks.GetSensorStop(dir_reverse, block); - s_slow = server->blocks.GetSensorSlow(dir_reverse, block); - s_enter = server->blocks.GetSensorEnter(dir_reverse, block); - - if ( server->sensors.GetActive(s_stop) == 1 || - ((loco->flags & LOCO_F_SHORTTRAIN) && server->sensors.GetActive(s_shortstop) == 1)) { - - 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; + if (Loco_BlockEnterStop(loco)) { jp.Clear(); jp.AddObject("locomotive",_GetJSON(lnum)); if(network) network->ChangeListPushToAll(jp.ToString()); - timer_start(&loco->auto_timenext); } } else if (loco->auto_onroute == LOCO_OR_ENTERBLOCKNEXT) { - // check enter block - int finish = 0; - - if (loco->auto_timenext.tv_sec == 0 || timer_get(&loco->auto_timenext) > LOCO_TO_TURNOUT) { - if (AutoCheckWaySingleStep(loco->auto_way, loco->name, &loco->auto_data) == 1) - finish = 1; - else - timer_start(&loco->auto_timenext); - } - - block = ((string)(loco->blocknext+2)).substr(0, ((string)(loco->blocknext+2)).find(",")); - if (loco->blockassign[0] == '-') dir_reverse = 1; - else dir_reverse = 0; - - s_shortstop = server->blocks.GetSensorShortStop(dir_reverse, block); - s_stop = server->blocks.GetSensorStop(dir_reverse, block); - s_slow = server->blocks.GetSensorSlow(dir_reverse, block); - s_enter = server->blocks.GetSensorEnter(dir_reverse, block); - - if ( server->sensors.GetActive(s_stop) == 1 || - ((loco->flags & LOCO_F_SHORTTRAIN) && server->sensors.GetActive(s_shortstop) == 1)) { - - debug (0, "Locomotives::Loop EnterBlockNext Loco:'%s' Block: '%s' UnLockWay", loco->name, block.c_str()); - debug (0, "* %s,%d Sensor Enter '%s' = %d", __FILE__, __LINE__, s_enter.c_str(), server->sensors.GetActive(s_enter)); - debug (0, "* %s,%d Sensor Slow '%s' = %d", __FILE__, __LINE__, s_slow.c_str(), server->sensors.GetActive(s_slow)); - debug (0, "* %s,%d Sensor Sh.Stop '%s' = %d", __FILE__, __LINE__, s_shortstop.c_str(), server->sensors.GetActive(s_shortstop)); - debug (0, "* %s,%d Sensor Stop '%s' = %d", __FILE__, __LINE__, s_stop.c_str(), server->sensors.GetActive(s_stop)); - - 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 - debug (0, "Locomotives::Loop '%s' UnLockWay\n", loco->name); - SetSpeed(loco->name, 0); - loco->auto_onroute = LOCO_OR_STOPWAIT; - jp.Clear(); - jp.AddObject("locomotive",_GetJSON(lnum)); - if(network) network->ChangeListPushToAll(jp.ToString()); - timer_start(&loco->auto_timenext); - } - else { - if (server->blocks.GetFlags(block) & BLOCK_F_SPEEDLIMIT) { - SetSpeed(loco->name, reverse * loco->vmid); - } - - loco->auto_onroute = LOCO_OR_ONTHEWAY; - } + switch (Loco_BlockEnterNext(loco)) { + case 1: + SetSpeed(loco->name, reverse * loco->vmid); + loco->auto_onroute = LOCO_OR_ONTHEWAY; + debug (0, "* Locomotive LOCO_OR_ENTERBLOCKNEXT '%s' Way Prepared -> Speed: VMID", loco->name); + jp.Clear(); + jp.AddObject("locomotive",_GetJSON(lnum)); + if(network) network->ChangeListPushToAll(jp.ToString()); + break; + case 2: + SetSpeed(loco->name, reverse * loco->vfast); + loco->auto_onroute = LOCO_OR_ONTHEWAY; + debug (0, "* Locomotive LOCO_OR_ENTERBLOCKNEXT '%s' Way Prepared -> Speed: VFAST", loco->name); + jp.Clear(); + jp.AddObject("locomotive",_GetJSON(lnum)); + if(network) network->ChangeListPushToAll(jp.ToString()); + break; + default: + break; } } + else if (loco->auto_onroute == LOCO_OR_STOPWAIT) { - if (loco->auto_timenext.tv_sec == 0 || timer_get(&loco->auto_timenext) > 5000) { - if (loco->blockdest[0] != 0) loco->auto_onroute = LOCO_OR_SEARCH; - else loco->auto_onroute = LOCO_OR_NOTHING; - } + Loco_BlockStopWait(loco); } } } @@ -1080,6 +1157,7 @@ int Locomotives::Loop() { } + int Locomotives::Test(string loco) { int res = 0; int i; diff --git a/server/locomotive.h b/server/locomotive.h index fd0bed9..e5077f9 100644 --- a/server/locomotive.h +++ b/server/locomotive.h @@ -56,6 +56,7 @@ struct s_Locomotive { int speed; // current speed int64_t func; // function enabled ... light... char blockassign[REFERENCENAME_LEN]; // currently assigned block [+BLOCKREFNAME ... -BLOCKREFNAME] + char blockassignsplit[REFERENCENAME_LEN]; // if assigned block is a split block, save full way. char blocknext[REFERENCENAME_LEN]; // next block to go to char blockprev[REFERENCENAME_LEN]; // prev block (mostly assigned block char blockdest[REFERENCENAME_LEN]; // destination block @@ -83,7 +84,12 @@ class Locomotives { JSONParse _GetJSON(int idx); int SchedulerNextStep(Locomotive *loc); // automode, calculate next step void SendUpdate(Locomotive *loc); - + int Loco_SearchAndLock(Locomotive *loco); + int Loco_PrepareWay(Locomotive *loco); + int Loco_OnRoute(Locomotive *loco); + int Loco_BlockEnterStop(Locomotive *loco); + int Loco_BlockEnterNext(Locomotive *loco); + int Loco_BlockStopWait(Locomotive *loco); public: Locomotives(); ~Locomotives(); diff --git a/server/railway.cc b/server/railway.cc index 4403dc7..4421c81 100644 --- a/server/railway.cc +++ b/server/railway.cc @@ -512,8 +512,10 @@ string Railways::GetDestBlock(int locoflags, string blockend) { block = blockend; } - debug (0, "Railway::GetDestBlock Final split:%d blockend:%s" + debug (0, "Railway::GetDestBlock Final split:%d loco short:%d blockend:%s -> block:%s" , (block_f & BLOCK_F_SPLIT) ? 1 : 0 + , (locoflags & LOCO_F_SHORTTRAIN) ? 1: 0 + , blockend.c_str() , block.c_str()); return block; @@ -621,7 +623,7 @@ int Railways::FindWay(string org_blockstart, string org_blockend, string lockedf // 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); + // DebugPrintFindWay(fd_data); if (fd_pos.enterfrom < 0) { std::list::iterator iter; @@ -1102,6 +1104,7 @@ int Railways::FindRandomWay(string blockstart, string lockedfor, string *next) { /* * try to lock or unlock the way for the loco(lockedby) + * this lock will only go from one to the next block. * Will also do the check for long trains and split blocks. */ int Railways::LockWay (string way, string lockedby, int lockonoff) { @@ -1111,12 +1114,13 @@ int Railways::LockWay (string way, string lockedby, int lockonoff) { struct s_findway_data start; struct s_findway_data end; struct s_findway_data pos; - string startblock, endblock, endblock2; + string startblock, startblock2, endblock, endblock2; Railway *r; int finished = 0; JSONParse jp; int locoflags = 0; - int blockflags = 0; + int blockendflags = 0; + int blockstartflags = 0; debug (0, "* LockWay Way:'%s' for '%s' lockonoff:%d", way.c_str(), lockedby.c_str(), lockonoff); @@ -1128,7 +1132,7 @@ int Railways::LockWay (string way, string lockedby, int lockonoff) { if ((pos2 = way.find(",", pos1+1)) == string::npos) return 0; startblock = way.substr (pos1+2, pos2-pos1-2); - if ((pos1 = way.rfind(",b:")) == string::npos) return 0; + if ((pos1 = way.find(",b:",pos2)) == string::npos) return 0; if ((pos2 = way.find(",", pos1+1)) == string::npos) endblock = way.substr (pos1+3, pos2); else endblock = way.substr (pos1+3, pos2-pos1-3); @@ -1136,13 +1140,16 @@ int Railways::LockWay (string way, string lockedby, int lockonoff) { // take care of split blocks and long trains. // if the second block is not needed endblock2 will remain empty locoflags = server->locomotives.GetFlags(lockedby); - blockflags = server->blocks.GetFlags(endblock.substr(2, string::npos)); - if (!(locoflags & LOCO_F_SHORTTRAIN) && (blockflags & BLOCK_F_SPLIT)) + blockendflags = server->blocks.GetFlags(endblock.substr(2, string::npos)); + if (!(locoflags & LOCO_F_SHORTTRAIN) && (blockendflags & BLOCK_F_SPLIT)) endblock2 = server->blocks.GetSecondBlock(endblock.substr(2, string::npos)); else endblock2 = ""; - debug (0, "%s:%d LockWay Way: '%s' Startblock: '%s' Endblock: '%s' Endblock2: '%s'", __FILE__, __LINE__, way.c_str(), - startblock.c_str(), endblock.c_str(), endblock2.c_str()); - + blockstartflags = server->blocks.GetFlags(startblock.substr(2, string::npos)); + if (!(locoflags & LOCO_F_SHORTTRAIN) && (blockstartflags & BLOCK_F_SPLIT)) + startblock2 = server->blocks.GetSecondBlock(startblock.substr(2, string::npos)); + else startblock2 = ""; + debug (0, "%s:%d LockWay Way: '%s' Startblock: '%s' Startblock2: '%s' Endblock: '%s' Endblock2: '%s'", __FILE__, __LINE__, way.c_str(), + startblock.c_str(), startblock2.c_str(), endblock.c_str(), endblock2.c_str()); // // find start position @@ -1181,7 +1188,7 @@ int Railways::LockWay (string way, string lockedby, int lockonoff) { return 0; } - printf ("%s:%d LockWay Way:'%s' start [%d,%d -> %d] to [%d,%d -> %d] LockenOnOff:%d\n", __FILE__, __LINE__, way.c_str(), + printf ("%s:%d LockWay Way:'%s' start [%d,%d -> %d] to [%d,%d -> %d] LockOnOff:%d\n", __FILE__, __LINE__, way.c_str(), start.x, start.y, start.enterfrom, end.x, end.y, end.enterfrom, lockonoff); // @@ -1198,7 +1205,7 @@ int Railways::LockWay (string way, string lockedby, int lockonoff) { finished = 0; do { r = &railways[GetRIdx(pos.x, pos.y)]; - printf ("LockWay Position [%d,%d] Name:%s LockedBy:'%s'\n", pos.x, pos.y, r->name, r->lockedby); + debug (0, "LockWay Position [%d,%d] Name:%s LockedBy:'%s'", pos.x, pos.y, r->name, r->lockedby); // check if railway is free or locked by me if (r->lockedby[0] != 0 && lockedby.compare(r->lockedby) != 0 && !(lockonoff == 0 && pos.x == start.x && pos.y == start.y && r->type == RAILWAY_BLOCK)) { @@ -1207,7 +1214,7 @@ int Railways::LockWay (string way, string lockedby, int lockonoff) { return 0; } - // do lock start and endpoint... unlock only start + // lock start and endpoint... unlock only start if ((pos.x == end.x && pos.y == end.y) || (r->type == RAILWAY_BLOCK && ((endblock.compare(r->name) == 0) || (endblock2.length() > 0 && endblock2.compare(r->name) == 0)))) { @@ -1245,12 +1252,24 @@ int Railways::LockWay (string way, string lockedby, int lockonoff) { break; } - if ((pos.x == end.x && pos.y == end.y) || - (lockonoff == 0 && - ((endblock.compare(r->name) == 0) || - (endblock2.length() > 0 && endblock2.compare(r->name) == 0)))) { - finished = 1; - break; + // + // to prevent unlocking split blocks on enter, check if the start and the end are different blocks. + // ignore this if startblock and endblock are the same split block. + if (locoflags & LOCO_F_SHORTTRAIN) { + if (pos.x == end.x && pos.y == end.y) { + finished = 1; + break; + } + } + else { + // freeing way on stop: abort if block is part of the split endblock + if ((pos.x == end.x && pos.y == end.y) || + (lockonoff == 0 && (endblock.compare(startblock.substr(0,2) + startblock2) != 0) && + ((endblock.compare(r->name) == 0) || + (endblock2.length() > 0 && endblock2.compare(r->name) == 0)))) { + finished = 1; + break; + } } // go to next position