return u->was_distance - c->distance;
}
+#define SKELETON_PREDICT_USER_CONTEXT(u,tra) \
+ (memset(&(u),0,sizeof((u))), \
+ (u).problem_callback= ppc, \
+ (u).problem_callback_u= ppcu, \
+ (u).train= tra)
+ /* for callers of predict_problem rather than predict */
+
/*---------- prediction problem reporting ----------*/
static ErrorCode predict_vproblem(PredictUserContext *u, Segment *seg,
/*
* If tra->uncertainty > tra->maxinto then in theory the foredetect
* might be in the previous segment. We don't take that into account,
- * which extends the effective length of the train.
+ * so we must instead extend our idea of the length of the train.
*/
int effective_length= MARGIN_TAIL + tail_length(tra) + tra->detectable;
ouprintf("\n");
}
+
+/*========== reversing a train ==========*/
+
+static int reverse_nextseg(TrackLocation *t, struct TrackAdvanceContext *c,
+ MovPosComb *mpc_io, const TrackLocation *before) {
+ PredictUserContext *u= c->u;
+ if (*mpc_io==-1 || t->seg->motion)
+ return predict_problem(u,t->seg, "segment under train is not stable");
+ return 0;
+}
+
+static int reverse_trackend(TrackLocation *t, struct TrackAdvanceContext *c) {
+ abort();
+}
+
+ErrorCode safety_setdirection(Train *tra, int backwards,
+ PredictionProblemCallback *ppc, void *ppcu) {
+ /* We adjust:
+ * tra->foredetect, maxinto, uncertainty
+ * tra->backwards
+ * tra->plan_lookahead_nsegs
+ * seg->tr_backwards
+ * The following remain unchanged as all their users have
+ * regard to the train's direction:
+ * tra->head, tail
+ */
+ TrackLocation newfdet;
+ TrackAdvanceContext c;
+ PredictUserContext u;
+ const SegPosCombInfo *pci;
+ Segment *oldfdet;
+ int oldmaxinto;
+ ErrorCode ec, ec2;
+ int r;
+ struct timeval tnow;
+
+ SKELETON_PREDICT_USER_CONTEXT(u,tra);
+
+ MUSTECR( safety_checktrain(tra,ppc,ppcu) );
+
+ if (tra->backwards == backwards)
+ return 0;
+
+ if (!speedmanager_stopped(tra))
+ return predict_problem(&u,0, "train is not stopped");
+ newfdet.seg= tra->foredetect;
+ newfdet.remain= tra->maxinto;
+ newfdet.backwards= !tra->backwards;
+
+ c.distance= tra->detectable + tra->uncertainty;
+ c.nextseg= reverse_nextseg;
+ c.getmovpos= 0;
+ c.trackend= reverse_trackend;
+ c.u= &u;
+
+ MUSTECR( trackloc_advance(&newfdet,&c) );
+
+ mgettimeofday(&tnow);
+
+ /* right, now let's start fiddling */
+ oldfdet= tra->foredetect;
+ oldmaxinto= tra->maxinto;
+
+ r= trackloc_getlink(&newfdet,&c,&pci,0,-1); assert(!r);
+ tra->foredetect= newfdet.seg;
+ tra->maxinto= pci->dist - newfdet.remain;
+
+ ec= predict(tra,tnow, PREDF_NEWPLAN,0,0, ppc,ppcu);
+ if (!ec) return 0; /* yay! */
+
+ /* It can happen eg that the uncertainty is more troublesome when
+ * considered one way than the other. In which case just put it back now. */
+ assert(ec == EC_SignallingPredictedProblem);
+
+ tra->foredetect= oldfdet;
+ tra->maxinto= oldmaxinto;
+ ec2= predict(tra,tnow, 0,0,0, 0,(char*)"abandon reverse");
+ assert(!ec2);
+
+ return ec;
+}
/*========== entrypoints from rest of the program ==========*/
speedmanager_safety_stop(tra,tnow);
ec= predict(tra,tnow, PREDF_JUSTDET,0,0, 0,(char*)"safety commanding stop");
assert(!ec);
-
- assert(!ec);
}
ErrorCode safety_movposchange(Segment *seg, MovPosComb comb,
struct timeval tnow;
ErrorCode ec, ec2;
- memset(&u,0,sizeof(u));
- u.problem_callback= ppc;
- u.problem_callback_u= ppcu;
- u.train= seg->owner;
+ SKELETON_PREDICT_USER_CONTEXT(u,seg->owner);
if (!seg->owner)
return movpos_change(seg,comb,-1,0);
if (allow_queueing<2) {
if (seg->det_ignore)
- return predict_problem(&u,seg, " route set for train");
+ return predict_problem(&u,seg, "route set for train");
if (seg->det_expected)
- return predict_problem(&u,seg, " route set for immiment train");
+ return predict_problem(&u,seg, "route set for immiment train");
}
if (allow_queueing<1)
- return predict_problem(&u,seg, " route set for approaching train");
+ return predict_problem(&u,seg, "route set for approaching train");
mgettimeofday(&tnow);
ec= predict(seg->owner,tnow, PREDF_NEWPLAN,seg,comb, ppc,ppcu);
return ec;
}
+ErrorCode safety_checktrain(Train *tra,
+ PredictionProblemCallback *ppc, void *ppcu) {
+ if (!tra->foredetect) {
+ ppc(tra,0,ppcu,"train is not on layout");
+ return EC_SignallingPredictedProblem;
+ }
+ return 0;
+}
+
void safety_abandon_run(void) {
SEG_IV;
typedef void PredictionProblemCallback(Train *tra, Segment *seg /* may be 0 */,
void *pu, const char *message);
-void safety_setdirection(Train* tra, int backwards);
- /* NYI */
+ErrorCode safety_checktrain(Train *tra,
+ PredictionProblemCallback *ppc, void *ppcu);
void safety_notify_detection(Segment *seg);
/* Called by startup.c when new train detection occurs in state Run. */
* ==2 allows queueing a change for when the train has left
*/
+ErrorCode safety_setdirection(Train *tra, int backwards,
+ PredictionProblemCallback *ppc, void *ppcu);
+
#define PREDF_JUSTDET 001u
/* we have just detected the train entering its foredetect so we
* can subtract the uncertainty from the stopping distance */
double speedmanager_speed_maxestimate(Train *tra, struct timeval tnow);
double speedmanager_stoppingdistance(Train *tra, struct timeval tnow);
int speedmanager_stopping(Train *tra);
+int speedmanager_stopped(Train *tra);
void actual_speed(Train *tra, int step);