return 0;
}
-static int rtf_nextseg(TrackLocation *t, struct TrackAdvanceContext *c,
- MovPosComb *mpc_io, Segment *before) {
- if (t->seg->owner != before->owner)
- return -1;
- t->seg->owner->foredetect= t->seg;
+typedef struct {
+ Train *train;
+ Segment *foredetect;
+ int minclear, backwards;
+} FindEndUserContext;
+
+static int segdist(Segment *seg) {
+ assert(seg->movposcomb >= 0);
+ return seg->i->poscombs[seg->movposcomb].dist;
+}
+
+static int foundend(FindEndUserContext *u, Segment *seg) {
+ u->foredetect= seg;
+ return -1;
+}
+static int findend_nextseg(TrackLocation *t, struct TrackAdvanceContext *c,
+ MovPosComb *mpc_io, Segment *before) {
+ FindEndUserContext *u= c->u;
+ t->seg->tr_backwards= t->backwards ^ u->backwards;
+ if (t->seg->owner != train) return foundend(u, before);
+ if (!t->seg->res_detect) { u->minclear= 0; return foundend(u, before);
+ return 0;
+}
+static int findend_trackend(TrackLocation *t, struct TrackAdvanceContext *c) {
+ FindEndUserContext *u= c->u;
+ return foundend(u, t->seg);
}
-static void resolve_train_finalise(Train *tra) {
+static void resolve_train_finalise(Segment *startpoint) {
+ Train *tra;
TrackLocation t;
TrackAdvanceContext tc;
+ FindEndUserContext u;
- t.seg= tra->foredetect;
+ assert(startpoint->owner);
+ tra= startpoint->owner;
+
+ startpoint->res_detect= 0; /* clear these as we use them up */
+
+ t.seg= startpoint;
t.remain= 0;
- t.backwards= t.seg->tr_backwards;
+ t.backwards= t.seg->tr_backwards ^ tra->backwards;
+ /* we're going to clear tra->backwards */
+
tc.distance= INT_MAX;
- tc.nextseg= rtf_nextseg;
+ tc.nextseg= findend_nextseg;
+ tc.trackend= findend_trackend;
tc.getmovpos= 0;
- tc.trackend= 0;
+ tc.u= &u;
+
+ u.minclear= MARGIN_NOSE + tra->head;
+ u.backwards= 0;
+
+ r= trackloc_advance(&t,&tc); assert(!r);
+
+ tra->foredetect= u->foredetect;
+ tra->maxinto= segdist(tra->foredetect) - u->minclear;
+ if (tra->maxinto < 0) tra->maxinto= 0;
+ tra->uncertainty= tra->maxinto;
+
+ t.seg= tra->foredetect;
+ t.remain=
+
+ u->maxinto= u->uncertainty= segdist(before);
+
+
+ u->detcanoccupy= tra->head;
+ return -1;
+
+t->seg->res_detect
+ if (
+
+
+ if (t->seg->owner != before->owner)
+ return -1;
+ t->seg->owner->foredetect= t->seg;
+}
+
+
+
+
+
+ tra->backwards= 0;
+
+ t.seg= tra->foredetect;
+ t.remain= 0;
trackloc_advance(&t,&tc);
+ }
if (seg->moving) return;
FOR_SEG
- if (seg->res_detect) {
- assert(seg->owner);
+ if (seg->res_detect)
+ resolve_train_finalise(seg);
+
+
seg->owner->foredetect= seg; /* initial guess */
}
FOR_TRA
- resolve_train_finalise(tra);
FOR_SEG {
if (seg->res_detect) {
* committed to in an earlier prediction but which we have not yet
* reached in this prediction.
*
- * (These are the values when not in the middle of nose_nextseg.) */
+ * (These are the values when not in the middle of nose_nextseg.)
+ */
+/*
+ * Simulation:
+ *
+ * DETECT
+ * real stop dist >>>>>
+ * simul. stop dist >>>>>
+ * +++++++++++|+++++++++++|++++++++++|XXXXXX
+ * set_exactinto FNT
+ * adv. tail back T FN
+ * adv. nose find T F N
+ * +++++++++++|+++++++++++|++++++++++|XXXXXX
+ * adv. fdet 1 seg T N F
+ * adv. nose T F N
+ * adv. tail T F N
+ * adv. fdet stopdist T N F N
+ * adv. nose T F N
+ * adv. tail T F N
+ * +++++++++++|+++++++++++|++++++++++|XXXXXX
+ *
+ * At next detection:
+ * DETECT
+ * real stop dist >>>>>
+ * +++++++++++|+++++++++++|++++++++++|XXXXXX
+ * set_exactinto FNT
+ * adv. tail back T FN
+ * adv. nose find T F N
+ * +++++++++++|+++++++++++|++++++++++|XXXXXX
+ * adv. fdet 1 seg T N F
+ * adv. nose T N ProblemPredicted
+ *
+ * Oops, so set sigstopping and speed 0:
+ * DETECT
+ * real stop dist >>>>>
+ * +++++++++++|+++++++++++|++++++++++|XXXXXX
+ * set_exactinto FNT
+ * adv. tail back T FN
+ * adv. nose find T F N
+ * +++++++++++|+++++++++++|++++++++++|XXXXXX
+ * adv. fdet 1 seg T N F
+ * adv. nose T N HorizonReached
+ *
+ */
/*========== prediction machinery ==========*/
PredictUserContext *u= c->u;
if (t->seg->motion) *use_io= movpos_change_intent(t->seg->motion);
if (*use_io<0) safety_panic(u->train, t->seg,
- "track route unexpectedly not known");
+ "track route unexpectedly not known");
return 0;
}
u->nosec.distance= advanced;
r= trackloc_advance(&u->nose,&u->nosec);
-
- if (r==EC_SignallingHorizonReached) {
- /* stop our prediction now */
- advanced= u->was_distance= t->remain= 0;
- r= 0;
+ if (r == SignallingHorizonReached &&
+ u->was_distance==INT_MAX) {
+ /* Our very first `next segment' lookahead found the end. So we
+ * know that our nose hasn't left this segment because that's what
+ * the stopping distance is supposed to prove. */
+ assert(before == u->train->foredetect);
+ int adjust= nose_length(u->train);
+ if (adjust > u->train->maxinto) adjust= u->train->maxinto;
+ u->train->maxinto -= adjust;
+ u->train->uncertainto += adjust;
}
-
if (r) return r;
- /* Now we have advanced the nose and have recoreded any appropriate
+ /* Now we have advanced the nose and have recorded any appropriate
* motion(s). But we advancing the nose has updated the segment's
* notion of the motion but not trackloc_advance's cached version of
* the movposcomb in *mpc_io. That doesn't matter because we don't
u->know_best_polarity= 1;
}
}
- if (u->know_best_polarity &&
+ if (u->know_best_polarity &&
!t->seg->i->invertible &&
u->noninv_tally[ t->backwards ^ u->train_polarity_inverted ]) {
/* incompatible, stop now */
/*---------- prediction entrypoint ----------*/
+static int nose_length(Train *tra) {
+ return MARGIN_NOSE + (tra->backwards ? tra->tail : tra->head);
+}
+
ErrorCode predict_confirm(Train *tra, int accelerate,
PredictionProblemCallback *ppc, void *ppcu) {
PredictUserContext u;
}
foredet= tra->foredetect;
-
+
memset(&u,0,sizeof(u));
u.train= tra;
u.accelerating= accelerate;
/* find the train's nose */
u.nose= u.fdet;
- u.nosec.distance= MARGIN_NOSE + (tra->backwards ? tra->tail : tra->head);
+ u.nosec.distance= nose_length(tra);
u.nosec.nextseg= nose_nextseg;
u.nosec.getmovpos= pred_getmovpos;
u.nosec.trackend= pred_trackend;
u.tailc.nextseg= tail_nextseg;
ec= trackloc_advance(&u.fdet,&u.fdetc);
- if (ec) goto xproblem;
+ if (ec && ec != EC_SignallingHorizonReached) goto xproblem;
/*----- commit to the plan -----*/
if (u.need_polarise)
actual_inversions_start();
-
+
FOR_SEG {
if (seg->owner == tra) {
seg->det_ignore= seg->det_expected= 0;
Train *tra;
TrackLoc tloc;
ErrorCode ec;
-
+
if (seg->det_ignore) return;
if (!seg->det_expected)
safety_panic(0,seg, "unexpected detection");
if (seg->movposcomb < 0)
safety_panic(tra,seg, "track route not set and train has arrived");
-
+
tra= seg->owner;
tra->foredetect= seg;
tra->uncertainty= tra->maxinto=
ec= predict_confirm(tra, 0, detection_report_problem, 0);
if (!ec) return;
-
+
assert(ec == EC_SignallingPredictedProblem);
tra->sigstopping= 1;
* May modify *use_io if it wishes. It is OK to leave it as
* -1 in which case advance will return whatever getmovpos did
* (even if 0). When called by interfering_segment, non-0 returns
- * will be treated as an indication that the movposcomb is unknown. */
+ * will be treated as an indication that the movposcomb is unknown.
+ * On entry t->remain is invalid; it should not be modified. */
int (*trackend)(TrackLocation *t, struct TrackAdvanceContext *c);
/* trackloc_advance stops even if this returns 0. */
void *u;
int trackloc_advance(TrackLocation *t, TrackAdvanceContext *c);
/* Advances t by dist until distance becomes 0, some callback
- * returns non-0, or sometimes 0 if we cannot continue and
- * the relevant callback is missing or returned 0. */
+ * returns non-0, or sometimes 0 if we cannot continue and the
+ * relevant callback is missing or returned 0. If we exhausted
+ * c->distance or reached the end of the track then *t is accurate;
+ * otherwise t is the segment which was problematic (passed to
+ * nextseg and perhaps getmovpos) and t->remain is set to -1. In
+ * any case c->distance is updated by the distance successfully
+ * traversed. */
int trackloc_reverse_exact(TrackLocation *t, TrackAdvanceContext *c);
/* c is used just as for trackloc_getlink.
tra->speed.speed= tra->speedcurve[tra->speed.step];
if (tra->sigstopping) {
assert(!tra->speed.step);
- resolve_train_
+ train_nose_restricttoowner(tra);
+ tra->sigstopping= 0;
}
static const SpeedRange *stop_info(Train *tra, double speed) {
next= &segments[nextnum];
leaving= t->seg;
- leaving_back= t->backwards;
t->seg= next;
t->backwards ^= link->next_backwards;
+ t->remain= -1;
mpc_nego= next->movposcomb;
if (c->nextseg) {
}
r= trackloc_getlink(t,c, &pci,&link, mpc_nego);
- if (r || !link) {
- t->seg=leaving;
- t->backwards= leaving_back;
- return r;
- }
+ if (r || !link) return r;
t->remain= pci->dist;
}