* until, and remove the departing segments from tallies.
*
* If all of this works then pred_present and pred_vacated constitute
- * the new ownership and motion constitutes the new plan. We commit
- * to it by rewriting owner and det_* and actually requesting any
- * movfeat changes.
+ * the new ownership and motion_newplan constitutes the new plan. We
+ * commit to it by rewriting owner and det_* and actually requesting
+ * any movfeat changes which we can do now, and replacing motion with
+ * motion_newplan.
*
* If not then we issue an signal stop command (we'd better not be
- * doing that already!) or countermand the speed increase or whatever.
- */
+ * doing that already!) or countermand the speed increase or whatever. */
/*
* Here is how we use the stuff in the Segment:
*
* the tail leaving it and the head arriving
* in each case movpos_change_intent tells us the plan
*
- * during prediction, motion can be non-0 for
+ * motion_newplan while we are making a plan this is the new value
+ * for motion. If identical to motion it
+ * means we should keep it; if 0 we cancel
+ * or unreserve; if a different value we
+ * commit to the new plan instead
+ *
+ * during prediction, motion_newplan can be non-0 for
* unowned segments as we make our plan.
* If we succeed we will end up
* owning the segment, and if we fail
TimeInterval elapsed; /* from now, minimum */
Distance was_distance, autopoint_distance, stopping_distance;
double maxspeed;
- Segment *hindmost, *furthest;
+ Segment *hindmost, *furthest, *desire_move;
+ int desire_movposcomb;
PredictionProblemCallback *problem_callback;
void *problem_callback_u;
PredictUserContext *u= c->u;
Segment *interferer;
MovPosComb route_plan;
- MovPosChange *route_reservation;
TimeInterval max_ms;
ErrorCode ec;
if (!t->seg->owner)
return predict_problem(u, t->seg, "route not yet set");
if (!u->neednewplan) {
+ t->seg->motion_newplan= t->seg->motion;
*mpc_io= movpos_change_intent(t->seg->motion);
goto movement_ok;
}
}
- if (t->seg->motion) {
+ if (t->seg->motion_newplan) {
+ route_plan= movpos_change_intent(t->seg->motion);
+ *mpc_io= route_plan;
+ goto movement_ok;
+ } else if (t->seg == u->desire_move && !t->seg->now_present) {
+ ec= movpos_findcomb_bysegs(before->seg,t->seg,0,
+ u->desire_movposcomb, &route_plan);
+ assert(!ec);
+ if (route_plan != u->desire_movposcomb)
+ return predict_problem(u, t->seg, " proposed route would be against"
+ " approaching train");
+ } else if (t->seg->motion) {
/* We already have a plan. */
route_plan= movpos_change_intent(t->seg->motion);
if (!u->neednewplan) {
+ t->seg->motion_newplan= t->seg->motion;
*mpc_io= route_plan;
goto movement_ok;
}
}
if (route_plan == *mpc_io && !t->seg->moving) {
/* Well, that's all fine then. */
- movpos_unreserve(t->seg->motion); /* we don't need this whatever it is */
- t->seg->motion= 0;
goto movement_ok;
}
- /* We have a plan but it involves some motion: */
+ /* We can make it work but have to plan some motion: */
if (u->elapsed < 0)
- return predict_problem(u, t->seg, "arrived but route not set");
+ return predict_problem(u, t->seg, "train arriving but route not yet set");
if (t->seg->pred_vacated) {
if (!t->seg->now_present)
/* And we're not even there yet! This is too hard because we
if (!u->train->autopoint || !t->seg->autopoint)
return predict_problem(u,t->seg,"will not automatically set route");
- ec= movpos_reserve(t->seg, max_ms, &route_reservation, route_plan, *mpc_io);
- if (ec) return predict_problem(u, t->seg, "cannot promise to"
+ ec= movpos_reserve(t->seg, max_ms, &t->seg->motion_newplan,
+ route_plan, *mpc_io);
+ if (ec) return predict_problem(u, t->seg, "insufficient time to"
" set route: %s", ec2str(ec));
-
- movpos_unreserve(t->seg->motion);
- t->seg->motion= route_reservation;
*mpc_io= route_plan;
movement_ok:
/*========== prediction entrypoint ==========*/
ErrorCode predict(Train *tra, struct timeval tnow, unsigned flags,
+ Segment *desire_move, int desire_movposcomb,
PredictionProblemCallback *ppc, void *ppcu) {
PredictUserContext u;
Segment *foredet;
u.stopping= !(flags & PREDF_NEWPLAN) && speedmanager_stopping(u.train);
u.stopping_distance= speedmanager_stoppingdistance(u.train, tnow);
+ u.desire_move= desire_move;
+ u.desire_movposcomb= desire_movposcomb;
+
oprintf(DUPO("safety") " predict ***starting*** %s%s maxspeed=%f"
- " (speed %f try %f, step %d%s) stopdist=%d flags=%c%c %s\n",
+ " (speed %f try %f, step %d%s) stopdist=%d flags=%c%c"
+ " desire=%s/%s %s\n",
tra->backwards?"-":"",tra->pname,
u.maxspeed, tra->speed.speed, tra->speed.try_speed, tra->speed.step,
tra->speed.decel.running ? " decel" : "",
u.stopping_distance,
"-j"[ !!(flags & PREDF_JUSTDET) ],
"-n"[ !!(flags & PREDF_NEWPLAN) ],
- u.stopping ? " stopping" : "");
+ u.stopping ? " stopping" : "",
+ u.desire_move ? u.desire_move->i->pname : "",
+ u.desire_move ? u.desire_move->i->poscombs[u.desire_movposcomb]
+ .pname : "");
FOR_SEG {
seg->det_expected= 0;
seg->det_ignore= 0;
seg->owner= 0;
}
- if (seg->motion && !seg->moving && !seg->now_present) {
- MovPosChange *reservation= seg->motion;
- MovPosComb target= movpos_change_intent(reservation);
- seg->motion= 0;
- ec= movpos_change(seg, target, -1, reservation);
- assert(!ec);
+ if (seg->motion_newplan == seg->motion) {
+ seg->motion_newplan= 0;
+ } else {
+ if (seg->motion && !seg->moving) {
+ movpos_unreserve(seg->motion);
+ seg->motion= 0;
+ }
+ if (seg->motion_newplan && !seg->now_present) {
+ MovPosComb target= movpos_change_intent(seg->motion_newplan);
+ ec= movpos_change(seg, target, -1, seg->motion_newplan);
+ assert(!ec);
+ seg->motion_newplan= 0;
+ }
+ if (seg->motion_newplan) {
+ assert(!seg->motion);
+ seg->motion= seg->motion_newplan;
+ seg->motion_newplan= 0;
+ }
}
if (u.need_polarise && seg->will_polarise) {
seg->seg_inverted= seg->tr_backwards ^ u.train_polarity_inverted;
seg->now_present= seg->pred_present=
seg->pred_vacated= seg->will_polarise= 0;
+ if (seg->motion_newplan==seg->motion) {
+ seg->motion_newplan= 0;
+ }
+ if (seg->motion_newplan) {
+ movpos_unreserve(seg->motion_newplan);
+ seg->motion_newplan= 0;
+ }
if (!seg->owner && !seg->moving && seg->motion) {
movpos_unreserve(seg->motion);
seg->motion= 0;
tra->uncertainty= tra->maxinto= maxinto;
report_train_position(tra);
- ec= predict(tra,tnow,PREDF_JUSTDET, detection_report_problem, 0);
+ ec= predict(tra,tnow, PREDF_JUSTDET,0,0, detection_report_problem,0);
if (!ec) return;
assert(ec == EC_SignallingPredictedProblem);
report_train_position(tra);
speedmanager_safety_stop(tra,tnow);
- ec= predict(tra,tnow,PREDF_JUSTDET, 0,(char*)"safety commanding stop");
+ ec= predict(tra,tnow, PREDF_JUSTDET,0,0, 0,(char*)"safety commanding stop");
assert(!ec);
assert(!ec);
}
-ErrorCode safety_check_movposchange(Segment *seg,
- PredictionProblemCallback *ppc, void *ppcu) {
+ErrorCode safety_movposchange(Segment *seg, MovPosComb comb,
+ int allow_queueing, PredictionProblemCallback *ppc, void *ppcu) {
PredictUserContext u;
+ struct timeval tnow;
+ ErrorCode ec, ec2;
memset(&u,0,sizeof(u));
u.problem_callback= ppc;
u.problem_callback_u= ppcu;
u.train= seg->owner;
- if (seg->owner) {
+ if (!seg->owner)
+ return 0;
+
+ if (allow_queueing<2) {
if (seg->det_ignore)
return predict_problem(&u,seg, " route set for train");
- else
- return predict_problem(&u,seg, " route set for approaching train");
+ if (seg->det_expected)
+ return predict_problem(&u,seg, " route set for immiment train");
}
- return 0;
+ if (allow_queueing<1)
+ return predict_problem(&u,seg, " route set for approaching train");
+
+ mgettimeofday(&tnow);
+ ec= predict(seg->owner,tnow, PREDF_NEWPLAN,seg,comb, ppc,ppcu);
+ if (!ec) return 0;
+
+ ec2= predict(seg->owner,tnow,0, 0,0, 0,(char*)"abandon movposchange");
+ assert(!ec2);
+
+ return ec;
}
void safety_abandon_run(void) {