Beispiel #1
0
void ofxTSPSOscSender::update(){
	if (strcmp(oldip.c_str(), ip.c_str()) != 0 || oldport != port){
		oldip = ip;
		oldport = port;
		reroute(ip, port);				
	}
}
void multitrain_driver() {
  MultiTrainDriver me;

  initDriver(&me);
  unsigned int naggCount = 0;
  unsigned int updateStoppingDistanceCount = 0;

  for (;;) {
    int tid = -1;
    MultiTrainDriverMsg actualMsg;
    DriverMsg* msg = (DriverMsg*)&actualMsg;
    msg->data3 = 0;
    Receive(&tid, (char *)msg, sizeof(MultiTrainDriverMsg));
    if (msg->type != REPORT_INFO &&
        msg->type != QUERY_STOP_COUNT &&
        msg->type != MULTI_TRAIN_DRIVER_COURIER &&
        msg->type != SENSOR_TRIGGER &&
        msg->type != DELTA_DISTANCE) {
      Reply(tid, (char*)1, 0);
    }

    switch (msg->type) {
      case SET_SPEED: {
        if (!me.tailMode) {
          Reply(msg->replyTid, (char*)1, 0);
        }

        groupSetSpeed(&me, msg->data2);
        break;
      }
      case SENSOR_TRIGGER: {
        if (me.tailMode && tid == me.sensorWatcher) {
          Reply(tid, (char *)NULL, 0);
          break;
        }

        if (me.tailMode) {
          int isHandled = 0;
          Send(me.trainId[0],
              (char*)msg, sizeof(DriverMsg), (char *)&isHandled, sizeof(int));
          Reply(tid, (char *)&isHandled, sizeof(int));
        } else {
          int isSensorReserved = QueryIsSensorReserved(&me, msg->data2, msg->data3);
          if (isSensorReserved) {
            // sensor is reserved
            for (int i = 0; i < me.numTrainInGroup; i ++) {
              int isHandled = 0;
              Send(me.trainId[i],
                  (char*)msg, sizeof(DriverMsg), (char *)&isHandled, sizeof(int));
              if (isHandled) {
                break;
              }
            }
          }
          Reply(tid, (char *)NULL, 0);
        }
        break;
      } // case
      case NAVIGATE_NAGGER: {
        if (me.tailMode) break;

        updateInfo(&me);

        if (me.routeRemaining != -1) {
          if (!me.stopCommited) {
            if (shouldStopNow(&me)) {
              if (me.route.nodes[me.stopNode].num == REVERSE) {
                //TrainDebug(&me, "Navi reversing.");
                groupSetSpeed(&me, -1); // reverse
              }
              else {
                //TrainDebug(&me, "Navi Nagger stopping.");
                groupSetSpeed(&me, 0); // stopping
                me.route.length = 0; // Finished the route.
                me.testMode = 0;
                me.routeRemaining = -1;
              }
              me.stopCommited = 1;
              me.useLastSensorNow = 0;
              me.stopNow = 0;
              me.stopSensorHit = 0;
            } else {
              if ((++updateStoppingDistanceCount & 15) == 0) updateStopNode(&me);
            }
          }
        }

        if (me.nextSetSwitchNode != -1 && (++me.setSwitchNaggerCount & 3) == 0) {
          trySetSwitch_and_getNextSwitch(&me);
        }
        if (me.rerouteCountdown-- == 0) {
          if (me.testMode) {
            int reserveStatus = makeReservation(&me, 440);
            if (reserveStatus == RESERVE_FAIL) {
              reroute(&me);
            } else {
              me.nextSetSwitchNode = -1;
              updateSetSwitch(&me);
              groupSetSpeed(&me, 8);
            }
          } else {
            // reroute
            if (me.route.length != 0) {
              setRoute(&me, &(me.info[0].pos), &(me.routeMsg));
            }
          }
        }
        break;
      }
      case UPDATE_PREDICTION: {
        if (me.tailMode) {
          MultiTrainDriverCourierMsg cMsg;
          cMsg.destTid = me.headTid;
          cMsg.msg = actualMsg;
          cMsg.msg.data = MyTid();
          Reply(me.courier, (char *)&cMsg, sizeof(MultiTrainDriverCourierMsg));
          break;
        }

        for (int i = 0; i < MAX_TRAIN_IN_GROUP; i++) {
          if (actualMsg.data == me.trainId[i]) {
            for (int j = 0; j < actualMsg.numSensors; j++) {
              me.sensorToReserve[i][j] = actualMsg.sensors[j];
            }
            me.numSensorToReserve[i] = actualMsg.numSensors;
          }
        }
        makeReservation(&me, me.info[0].maxStoppingDistance);
        break;
      }
      case STOP_COMPLETED: {
        // notify actual train controller.
        if (me.tailMode) {
          MultiTrainDriverCourierMsg cMsg;
          cMsg.destTid = me.headTid;
          cMsg.msg = actualMsg;
          cMsg.msg.data = MyTid();
          Reply(me.courier, (char *)&cMsg, sizeof(MultiTrainDriverCourierMsg));
          break;
        }
        me.stoppedCount++;

        if (me.stoppedCount == me.numTrainInGroup) {
          makeReservation(&me, 1);
          if (me.isReversing) {
            handleReverse(&me);
          } else if (me.route.length != 0) {
            // Reroute.
            setRoute(&me, &(me.info[0].pos), &(me.routeMsg));
          }
        }

        if (!me.reserveTrackMode) {
          clearReservation(me.trackManager, me.trainNum);
        }
        break;
      }
      case SET_ROUTE: {
        Reply(msg->replyTid, (char*)1, 0);
        me.routeMsg = *msg;
        setRoute(&me, &(me.info[0].pos), msg);
        break;
      }
      case GET_POSITION: {
        if (me.tailMode) {
          PrintDebug(me.ui, "Get position from a tail train ??");
          break;
        }
        // If don't have any valid info yet, reply empty message
        if (me.infoUpdater == -1) {
          Reply(msg->replyTid, (char*)1, 0);
        } else {
          Reply(msg->replyTid, (char*)&(me.info[0]), sizeof(DumbDriverInfo));
        }
        break;
      }
      case FIND_POSITION: {
        if (me.tailMode) {
          PrintDebug(me.ui, "find position while merge????");
          break;
        }
        me.reserveTrackMode = (msg->data2 == RESERVE);

        PrintDebug(me.ui, "Train locking %d", me.trainNum);
        // Only 1 train can lock at the same time.
        lock(me.timeserver);
        // begin finding position in a slow speed
        DumbTrainSetSpeed(me.trainId[0], 5);
        Reply(msg->replyTid, (char*)1, 0);
        for (;;) {
          Receive(&tid, (char*)msg, sizeof(MultiTrainDriverMsg));
          Reply(tid, (char*)1, 0);
          if (msg->type == SENSOR_TRIGGER) {
            Send(me.trainId[0], (char*)msg,
                sizeof(DriverMsg), (char*)NULL, 0);
            DumbTrainSetSpeed(me.trainId[0], 0);
            break;
          } else if (msg->type == GET_POSITION) {
            Reply(msg->replyTid, (char*)1, 0);
          } else {
            PrintDebug(me.ui, "WARNN Drop %d", msg->type);
          }
        }
        DriverMsg dMsg;
        dMsg.type = REPORT_INFO;
        for (int i = 0; i < me.numTrainInGroup; i++) {
          Send(me.trainId[i],
              (char *)&dMsg, sizeof(DriverMsg),
              (char*)&me.info[i], sizeof(DumbDriverInfo));
        }
        me.infoUpdater = Create(3, trainNavigateNagger);
        unlock();
        break;
      }
      case MERGE_HEAD: {
        if (me.tailMode) {
          PrintDebug(me.ui, "Cannot be a head when in tail mode??");
          break;
        }
        me.reserveTrackMode = 1; //  Head always reserves track.
        // Other train controller's id.
        me.trainId[me.numTrainInGroup] = msg->data2;
        me.numTrainInGroup++;
        Reply(msg->replyTid, (char*)1, 0);
        DriverMsg dMsg;
        dMsg.type = QUERY_STOP_COUNT;
        int tailStopCount = 0;
        Send(msg->data2, (char *)&dMsg, sizeof(DriverMsg), (char *)&tailStopCount, sizeof(int));
        me.stoppedCount += tailStopCount;

        dMsg.type = UPDATE_PARENT_ABOUT_PREDICTION;
        Send(msg->data2, (char *)&dMsg, sizeof(DriverMsg), (char *)NULL, 0);

        PrintDebug(me.ui, "merged. head is %d", me.trainNum);
        break;
      }
      case MERGE_TAIL: {
        if (me.tailMode) {
          PrintDebug(me.ui, "Double merge tail??");
          break;
        }
        // Enters courier mode that passes dumb_train msg to 'real' controller
        me.tailMode = 1;
        me.headTid = msg->data2;
        clearReservation(me.trackManager, me.trainNum);
        Reply(msg->replyTid, (char*)1, 0);
        PrintDebug(me.ui, "Train %d is tail", me.trainNum);
        break;
      }
      case SEPARATE_TAIL: {
        if (!me.tailMode) {
          PrintDebug(me.ui, "Not in tail mode..??"); break;
        }
        me.tailMode = 0;
        me.headTid = 0;
        // TODO, behaviour is not clearly defined yet.
        // reserve my own track and prediction??
        break;
      }
      case REPORT_INFO: {
        if (!me.tailMode) {
          PrintDebug(me.ui, "Report info Not in tail mode..??"); break;
        }

        // ASSUME ONLY 1 train when in tail mode.
        Send(me.trainId[0], (char*)msg, sizeof(DriverMsg),
            (char*)&me.info[0], sizeof(DumbDriverInfo));
        // Reply the head that made query.
        Reply(me.headTid, (char*)&me.info[0], sizeof(DumbDriverInfo));
        break;
      }
      case DELTA_DISTANCE: {
        if (!me.tailMode) {
          PrintDebug(me.ui, "Delta distance and not in tail mode..??"); break;
        }

        // ASSUME ONLY 1 train when in tail mode.
        Send(me.trainId[0], (char*)msg,
            sizeof(DriverMsg) - sizeof(Position), (char*)1, 0);
        // Reply the head that made query.
        Reply(me.headTid, (char*)1, 0);
        break;
      }
      case UPDATE_PARENT_ABOUT_PREDICTION: {
        if (!me.tailMode) {
          PrintDebug(me.ui, "%d Update Parent Not in tail mode..??", me.trainNum);
          break;
        }
        // ASSUME ONLY 1 train when in tail mode.
        Send(me.trainId[0], (char*)msg, sizeof(DriverMsg),
            (char*)NULL, 0);
        break;
      }
      case QUERY_STOP_COUNT: {
        // asuumption: no tree strucutre
        Reply(tid, (char *)&me.stoppedCount, sizeof(int));
        break;
      }
      case MULTI_TRAIN_DRIVER_COURIER: {
        // nothing
        break;
      }
      case REVERSE_SPEED: {
        if (!me.tailMode) {
          PrintDebug(me.ui, "Reverse Speed Not in tail mode..??"); break;
        }

        for (int i = 0; i < me.numTrainInGroup; i++) {
          Send(me.trainId[i], (char *)msg, sizeof(DriverMsg), (char*)1, 0);
        }
        break;
      }
      case QUERY_STOPPING_DISTANCE: {
        if (!me.tailMode) {
          PrintDebug(me.ui, "Query stopping dist Not in tail mode..??"); break;
        }

        int stoppingDist = 0;
        // ASSUME ONLY 1 train when in tail mode.
        Send(me.trainId[0], (char*)msg, sizeof(DriverMsg),
            (char*)&stoppingDist, sizeof(int));
        // Reply the head that made query.
        Reply(me.headTid, (char*)&stoppingDist, sizeof(int));
        break;
      }
      case HIT_SECONDARY: {
        if (me.route.length != 0) {
          PrintDebug(me.ui, "Hit secondary rerouting..");
          groupSetSpeed(&me, 0);
        }
        break;
      }
      case SET_FOLLOWING_DISTANCE: {
        me.minFollowingDist = msg->data2;
        me.maxFollowingDist = msg->data3;

        Reply(msg->replyTid, (char*)1, 0);
        break;
      }
      default: {
        PrintDebug(me.ui, "Not Handled %d", msg->type);
      }
    } // switch
  } // for
}
Beispiel #3
0
static void trainSetSpeed(const int speed, const int stopTime, const int delayer, Driver* me) {
  char msg[4];
  msg[1] = (char)me->trainNum;

  if (me->lastSensorActualTime > 0) {
    // a/d related stuff
    int newSpeed = speed >=0 ? speed : 0;
    int now = Time(me->timeserver) * 10;
    if (me->speed == newSpeed) {
      // do nothing
    }
    else if (me->speed == 0) {
      // accelerating from 0
      int v0 = getVelocity(me);
      int v1 = me->v[newSpeed][ACCELERATE];
      int t0 = now + 8; // compensate for time it takes to send to train
      int t1 = now + 8 + me->a[newSpeed];
      poly_init(&me->adPoly, t0, t1, v0, v1);
      me->isAding = 1;
      me->lastReportDist = 0;
      me->adEndTime = t1;
    } else if (newSpeed == 0) {
      // decelerating to 0
      int v0 = getVelocity(me);
      int v1 = me->v[newSpeed][DECELERATE];
      int t0 = now + 8; // compensate for time it takes to send to train
      int t1 = now + 8 + getStoppingTime(me);
      poly_init(&me->adPoly, t0, t1, v0, v1);
      me->isAding = 1;
      me->lastReportDist = 0;
      me->adEndTime = t1;
    }
  }

  TrainDebug(me, "Train Setting Speed %d", speed);

  if (speed >= 0) {
    if (delayer) {
      TrainDebug(me, "Reversing speed.------- %d", speed);
      msg[0] = 0xf;
      msg[1] = (char)me->trainNum;
      msg[2] = (char)speed;
      msg[3] = (char)me->trainNum;
      Putstr(me->com1, msg, 4);

      //TrainDebug(me, "Next Sensor: %d %d", me->nextSensorIsTerminal, me->lastSensorIsTerminal);
      // Update prediction
      if (me->nextSensorIsTerminal) {
        me->nextSensorBox = me->nextSensorBox == EX ? EN : EX;

        //TrainDebug(me, "LAst Sensor: %d ", me->lastSensorVal);
      } else {
        int action = me->nextSensorVal%2 == 1 ? 1 : -1;
        me->nextSensorVal = me->nextSensorVal + action;
      }
      if (me->lastSensorIsTerminal) {
        me->lastSensorBox = me->lastSensorBox == EX ? EN : EX;
      } else {
        int action = me->lastSensorVal%2 == 1 ? 1 : -1;
        me->lastSensorVal = me->lastSensorVal + action;
      }

      float distTemp = me->distanceFromLastSensor;
      me->distanceFromLastSensor = me->distanceToNextSensor;
      me->distanceToNextSensor = distTemp;

      char valTemp = me->nextSensorVal;
      me->nextSensorVal = me->lastSensorVal;
      me->lastSensorVal = valTemp;

      char boxTemp = me->nextSensorBox;
      me->nextSensorBox = me->lastSensorBox;
      me->lastSensorBox = boxTemp;

      if (me->nextSensorIsTerminal || me->lastSensorIsTerminal){
        char isTemp = me->nextSensorIsTerminal;
        me->nextSensorIsTerminal = me->lastSensorIsTerminal;
        me->lastSensorIsTerminal = isTemp;
      }
      // Reserve the track above train and future (covers case of init)

      // Update prediction
      updatePrediction(me);
      int reserveStatus = reserveMoreTrack(me, 0, me->d[speed][ACCELERATE][MAX_VAL]); // moving
      if (reserveStatus == RESERVE_FAIL) {
        reroute(me);
      }
    } else {
      //TrainDebug(me, "Set speed. %d %d", speed, me->trainNum);
      msg[0] = (char)speed;
      Putstr(me->com1, msg, 2);
      if (speed == 0) {
        int delayTime = stopTime + 500;
        Reply(me->stopDelayer, (char*)&delayTime, 4);
      }
    }
    if (speed > me->speed) {
      me->speedDir = ACCELERATE;
    } else if (speed < me->speed) {
      me->speedDir = DECELERATE;
    }
    me->speed = speed;
  } else {
    //TrainDebug(me, "Reverse... %d ", me->speed);
    DriverMsg delayMsg;
    delayMsg.type = SET_SPEED;
    delayMsg.timestamp = stopTime + 500;
    if (me->speedAfterReverse == -1) {
      delayMsg.data2 = (signed char)me->speed;
    } else {
      delayMsg.data2 = (signed char)me->speedAfterReverse;
    }
    //TrainDebug(me, "Using delayer: %d for %d", me->delayer, stopTime);

    Reply(me->delayer, (char*)&delayMsg, sizeof(DriverMsg));

    msg[0] = 0;
    msg[1] = (char)me->trainNum;

    Putstr(me->com1, msg, 2);
    me->speed = 0;
    me->speedDir = DECELERATE;
  }
}
Beispiel #4
0
void
GUIVehicle::rerouteDRTStop(MSStoppingPlace* busStop) {
    SUMOTime intermediateDuration = TIME2STEPS(20);
    SUMOTime finalDuration = SUMOTime_MAX;
    if (myParameter->stops.size() >= 2) {
        // copy durations from the original stops
        intermediateDuration = myParameter->stops.front().duration;
        finalDuration = myParameter->stops.back().duration;
    }
    // if the stop is already in the list of stops, cancel all stops that come
    // after it and set the stop duration
    std::string line = "";
    int destinations = 0;
    bool add = true;
    for (auto it = myStops.begin(); it != myStops.end(); it++) {
        if (!it->reached && destinations < 2 && it->busstop != nullptr) {
            line += it->busstop->getID();
            destinations++;
        }
        if (it->busstop == busStop) {
            it->duration = finalDuration;
            myStops.erase(++it, myStops.end());
            add = false;
            break;
        } else {
            it->duration = MIN2(it->duration, intermediateDuration);
        }
    }
    if (destinations < 2) {
        line += busStop->getID();
    }
    if (add) {
        // create new stop
        SUMOVehicleParameter::Stop stopPar;
        stopPar.busstop = busStop->getID();
        stopPar.lane = busStop->getLane().getID();
        stopPar.startPos = busStop->getBeginLanePosition();
        stopPar.endPos = busStop->getEndLanePosition();
        stopPar.duration = finalDuration;
        stopPar.until = -1;
        stopPar.triggered = false;
        stopPar.containerTriggered = false;
        stopPar.parking = false;
        stopPar.index = STOP_INDEX_FIT;
        stopPar.parametersSet = STOP_START_SET | STOP_END_SET;
        // clean up prior route to improve visualisation, ensure that the stop can be added immediately
        ConstMSEdgeVector edges = myRoute->getEdges();
        edges.erase(edges.begin(), edges.begin() + getRoutePosition());
        edges.push_back(&busStop->getLane().getEdge());
        replaceRouteEdges(edges, -1, 0, "DRT.tmp", false, false, false);
        std::string errorMsg;
        // add stop
        addStop(stopPar, errorMsg);
    }
    const bool hasReroutingDevice = getDevice(typeid(MSDevice_Routing)) != nullptr;
    SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = hasReroutingDevice
            ? MSRoutingEngine::getRouterTT()
            : MSNet::getInstance()->getRouterTT();
    // reroute to ensure the new stop is reached
    reroute(MSNet::getInstance()->getCurrentTimeStep(), "DRT", router);
    myParameter->line = line;
    assert(haveValidStopEdges());
}
Beispiel #5
0
void driver() {
  Driver me;
  initDriver(&me, 1);

  unsigned int naggCount = 0;
  unsigned int updateStoppingDistanceCount = 0;

  for (;;) {
    int tid = -1;
    DriverMsg msg;
    msg.data2 = -1;
    msg.data3 = -1;
    msg.replyTid = -1;
    Receive(&tid, (char*)&msg, sizeof(DriverMsg));
    if (tid != me.delayer && tid != me.stopDelayer) {
      Reply(tid, (char*)1, 0);
    }
    const int replyTid = msg.replyTid;

    switch (msg.type) {
      case SET_SPEED: {
        //TrainDebug(&me, "Set speed from msg");
        trainSetSpeed(msg.data2,
                      getStoppingTime(&me),
                      (msg.data3 == DELAYER),
                      &me);
        if (msg.data3 != DELAYER) {
          //TrainDebug(&me, "Replied to %d", replyTid);
          Reply(replyTid, (char*)1, 0);
          sendUiReport(&me);
          break;
        } else if (me.route.length != 0) {
          // Delayer came back. Reverse command completed
          me.stopCommited = 0; // We're moving again.
          // We've completed everything up to the reverse node.
          me.routeRemaining = me.stopNode+1;
          me.previousStopNode = me.routeRemaining;
          me.distanceFromLastSensorAtPreviousStopNode = me.distanceFromLastSensor;
          // Calculate the next stop node.
          updateStopNode(&me);
          me.nextSetSwitchNode = -1;
          updateSetSwitch(&me);
          // if the reverse is last node, nothing to do
          // if it isn't.. it should speed up again.
        }
      }
      case DELAYER: {
        //TrainDebug(&me, "delayer come back.");
        break;
      }
      case STOP_DELAYER: {
        // To prevent the first receive from this delayer
        if (me.lastSensorActualTime > 0 && me.speed == 0 && !me.isAding) {
          TrainDebug(&me, "releasing reserveration");
          int reserveStatus = reserveMoreTrack(&me, 1, 0);
          if (reserveStatus == RESERVE_FAIL) {
            TrainDebug(&me, "WARNING: unable to reserve during init");
          }
        }
        break;
      }
      case SENSOR_TRIGGER: {

        // only handle sensor reports in primary + secondary prediction if not position finding
        int sensorReportValid = 0;
        TrackLandmark conditionLandmark;
        int condition;
        int isSensorReserved = QueryIsSensorReserved(&me, msg.data2, msg.data3);
        if (me.positionFinding) {
          sensorReportValid = 1;
          me.lastSensorUnexpected = 1;
          //FinishPositionFinding(me.trainNum, me.trainController);
        } else if (isSensorReserved) {
          //TrainDebug(&me, "Predictions.");
          for (int i = 0; i < me.numPredictions; i ++) {
            TrackLandmark predictedSensor = me.predictions[i].sensor;
            //printLandmark(&me, &predictedSensor);
            if (predictedSensor.type == LANDMARK_SENSOR && predictedSensor.num1 == msg.data2 && predictedSensor.num2 == msg.data3) {
              sensorReportValid = 1;
              if (i != 0) {
                TrainDebug(&me, "Trigger Secondary");
                // secondary prediction, need to do something about them
                conditionLandmark = me.predictions[i].conditionLandmark;
                condition = me.predictions[i].condition;
                me.lastSensorUnexpected = 1;
                if (conditionLandmark.type == LANDMARK_SWITCH) {
                  TrackMsg setSwitch;
                  setSwitch.type = UPDATE_SWITCH_STATE;
                  TrainDebug(&me, "UPDATE SWITCH STATE");
                  setSwitch.landmark1 = conditionLandmark;
                  setSwitch.data = condition;

                  Send(me.trackManager, (char*)&setSwitch, sizeof(TrackMsg), (char *)1, 0);
                }

                // Stop and then try to reroute.
                reroute(&me);
              } else {
                me.lastSensorUnexpected = 0;
              }
            }
          }
        }
        if (sensorReportValid) {
          updateRoute(&me, msg.data2, msg.data3);
          me.lastSensorBox = msg.data2; // Box
          me.lastSensorVal = msg.data3; // Val
          me.lastSensorIsTerminal = 0;
          me.lastSensorActualTime = msg.timestamp;
          dynamicCalibration(&me);
          me.lastSensorPredictedTime = me.nextSensorPredictedTime;

          TrackNextSensorMsg trackMsg;
          QueryNextSensor(&me, &trackMsg);
          // Reserve the track above train and future (covers case of init)

          for (int i = 0; i < trackMsg.numPred; i++) {
            me.predictions[i] = trackMsg.predictions[i];
          }
          me.numPredictions = trackMsg.numPred;

          int reserveStatus = reserveMoreTrack(&me, me.positionFinding, getStoppingDistance(&me));
          if (reserveStatus == RESERVE_FAIL) {
            if (!me.positionFinding) {
              reroute(&me);
            } else {
              TrainDebug(&me, "WARNING: unable to reserve during init");
            }
          }

          TrackSensorPrediction primaryPrediction = me.predictions[0];
          me.calibrationStart = msg.timestamp;
          me.calibrationDistance = primaryPrediction.dist;
          int dPos = 50 * getVelocity(&me) / 100000.0;
          me.lastSensorDistanceError =  -(int)me.distanceToNextSensor - dPos;
          me.distanceFromLastSensor = dPos;
          me.distanceToNextSensor = primaryPrediction.dist - dPos;
          me.lastPosUpdateTime = msg.timestamp;
          if (primaryPrediction.sensor.type != LANDMARK_SENSOR &&
              primaryPrediction.sensor.type != LANDMARK_END) {
            TrainDebug(&me, "QUERY_NEXT_SENSOR_FROM_SENSOR ..bad");
          }
          me.nextSensorIsTerminal = (primaryPrediction.sensor.type == LANDMARK_END);
          me.nextSensorBox = primaryPrediction.sensor.num1;
          me.nextSensorVal = primaryPrediction.sensor.num2;
          me.nextSensorPredictedTime =
            msg.timestamp + me.distanceToNextSensor*100000 /
            getVelocity(&me);

          updatePosition(&me, msg.timestamp);
          sendUiReport(&me);
          if (me.positionFinding) {
            trainSetSpeed(0, getStoppingTime(&me), 0, &me); // Found position, stop.
            me.positionFinding = 0;
            me.currentlyLost = 0;
          }
        }
        break;
      }
      case NAVIGATE_NAGGER: {
        updatePosition(&me, msg.timestamp);
        if (me.routeRemaining != -1) {
          if (!me.stopCommited) {
            if (shouldStopNow(&me)) {
              if (me.route.nodes[me.stopNode].num == REVERSE) {
                //TrainDebug(&me, "Navi reversing.");
                const int speed = -1;
                trainSetSpeed(speed, getStoppingTime(&me), 0, &me);
              }
              else {
                //TrainDebug(&me, "Navi Nagger stopping.");
                const int speed = 0;  // Set speed zero.
                trainSetSpeed(speed, getStoppingTime(&me), 0, &me);
                me.route.length = 0; // Finished the route.
                me.testMode = 0;
              }
              me.stopCommited = 1;
              me.useLastSensorNow = 0;
              me.stopNow = 0;
              me.stopSensorHit = 0;
            } else {
              if ((++updateStoppingDistanceCount & 15) == 0) updateStopNode(&me);
            }
          }
        }

        if (me.nextSetSwitchNode != -1 && (++me.setSwitchNaggerCount & 3) == 0) {
          trySetSwitch_and_getNextSwitch(&me);
        }
        if (me.rerouteCountdown-- == 0) {
          if (me.testMode) {
            int reserveStatus = reserveMoreTrack(&me, 0, me.d[8][ACCELERATE][MAX_VAL]); // moving
            if (reserveStatus == RESERVE_FAIL) {
              reroute(&me);
            } else {
              me.nextSetSwitchNode = -1;
              updateSetSwitch(&me);
              trainSetSpeed(8, 0, 0, &me);
            }
          } else {
            // reroute
            if (me.route.length != 0) {
              setRoute(&me, &(me.routeMsg));
            }
          }
        }
        if ((++naggCount & 15) == 0) sendUiReport(&me);
        break;
      }
      case SET_ROUTE: {
        Reply(replyTid, (char*)1, 0);
        me.routeMsg = msg;
        setRoute(&me, &msg);
        break;
      }
      case BROADCAST_UPDATE_PREDICTION: {
        updatePrediction(&me);
        int reserveStatus = reserveMoreTrack(&me, 0, getStoppingDistance(&me)); // moving
        if (reserveStatus == RESERVE_FAIL) {
          reroute(&me);
        }
        break;
      }
      case BROADCAST_TEST_MODE: {
        me.testMode = 1;
        setRoute(&me, &msg);
        break;
      }
      case FIND_POSITION: {
        me.positionFinding = 1;
        trainSetSpeed(5, 0, 0, &me);
        break;
      }
      default: {
        TrainDebug(&me, "Not suppported train message type.");
      }
    }
  }
}