From: ian Date: Sun, 20 Apr 2008 16:05:29 +0000 (+0000) Subject: before abandon "count_time" and "justdetected" X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ijackson/git?a=commitdiff_plain;h=568e0c9aa8363dff841970d167e0ceb4e5322744;p=trains.git before abandon "count_time" and "justdetected" --- diff --git a/hostside/safety.c b/hostside/safety.c index a2d9969..ee93426 100644 --- a/hostside/safety.c +++ b/hostside/safety.c @@ -48,7 +48,10 @@ Segment *segments; * At each new track location for our front end we hope to find a * segment which no-one currently owns and which is currently set for * us. (We check this before updating our tail trackloc as below.) - * In that case we update the segment's until_here. + * In that case we update the segment's until.) (We use the value + * `elapsed' which is the minimum time until the current nose + * prediction; if we've only just detected the train at foredetect + * we can count the time for the * * However it may be a segment which we currently own, or perhaps it * may be set against us. (If it's owned by anyone else or is not @@ -120,10 +123,8 @@ Segment *segments; * owning the segment, and if we fail * we garbage collect it * - * det_ignore we expect interference detection here due to a - * crossing (unowned segment), or - * this is part of the body of a train which we've - * already detected here (owned segment) + * det_ignore this is part of the body of a train which we've + * already detected here * * det_expected this is the next place we expect owner train * to arrive @@ -144,17 +145,18 @@ Segment *segments; * * iff either of these is set, this train is going * to own the segment when we're finished + * + * until time until the we will arrive (pred_present), or + * depart (pred_vacated), valid only if + * one of those is set + * value is as for u->elapsed */ +/*========== prediction machinery ==========*/ + #define pred_present mark0 #define pred_vacated mark1 -void update_head(Train *tra, Segment *seg) { - tra->foredetect= seg; - if (tra->foredetect->movposcomb < 0) - safety_panic(tra,seg, "track route not set and train has arrived"); -} - typedef void PredictionProblemCallback(void *pu, Train *tra, TrackSegment *seg, const char *fmt, va_list al); @@ -163,7 +165,7 @@ typedef struct { accelerating:1; TrackLocation nose, fdet, tail; TrackAdvanceContext nosec, tailc, fdetc; - TimeInterval elapsed; + TimeInterval elapsed; /* from now, minimum */ Distance was_distance; PredictionProblemCallback *problem_callback; @@ -175,6 +177,8 @@ typedef struct { int noninv_tally[2]; } PredictUserContext; +/*---------- prediction problem reporting ----------*/ + static ErrorCode predict_vproblem(PredicUserContext *u, TrackSegment *seg, const char *fmt, va_list al) { u->problem_callback(u->train,seg,fmt,al); @@ -190,13 +194,34 @@ static ErrorCode predict_problem(PredicUserContext *u, TrackSegment *seg, return ec; } +/*---------- prediction trivial callbacks ----------*/ + +static int pred_getmovpos(TrackLocation *t, TrackAdvanceContext *c, + MovPosComb *use_io) { + PredictUserContext *u= c->u; + if (t->seg->motion) *use_io= movpos_change_intent(t->seg->motion); + if (*use_io<0) return panic(tra,seg, "track route unexpectedly not known"); +} + +static int pred_trackend(TrackLocation *t, TrackAdvanceContext *c) { + return predict_problem(t,c,"end of track"); +} + +static int pred_trackend_panic(TrackLocation *t, TrackAdvanceContext *c) { + PredictUserContext *u= c->u; + return safety_panic(u->train,t->seg,"unexpected end of track"); +} + static int initpresent_nextseg(TrackLocation *t, TrackAdvanceContext *c, MovPosComb *mpc_io, Segment *before) { PredictUserContext *u= c->u; next->pred_present= 1; + next->until= 0; adjust_tally(t,c,1); } +/*---------- prediction nose advancement ----------*/ + static int nose_nextseg(TrackLocation *t, TrackAdvanceContext *c, MovPosComb *mpc_io, Segment *before) { PredictUserContext *u= c->u; @@ -206,7 +231,7 @@ static int nose_nextseg(TrackLocation *t, TrackAdvanceContext *c, /* Is it empty ? */ if (u->train->sigstopping && t->seg->owner != u->train) - return EC_SignalStopHorizonReached; + return EC_SignalStopHorizonReached; if (t->seg->owner) { if (t->seg->owner != u->train) @@ -216,6 +241,16 @@ static int nose_nextseg(TrackLocation *t, TrackAdvanceContext *c, if (t->seg->pred_present) return predict_problem(u, t->seg, "will collide with itself!"); + interferer= interferes(c,t->seg); + if (interferer) { + if (interferer->owner && interferer->owner != u->train) + return predict_problem(u, t->seg, "impeded by %s @%s", + interferer->owner->pname, interferer->i->pname); + if (interferer->pred_present) + return predict_problem(u, t->seg, "will collide with itself @%s!", + interferer->i->pname); + } + /* What about the route ? */ if (t->seg->i->n_poscombs==1) @@ -269,13 +304,12 @@ static int nose_nextseg(TrackLocation *t, TrackAdvanceContext *c, return 0; /* yay! */ } +/*---------- prediction tail advancement ----------*/ + static int tail_nextseg(TrackLocation *t, TrackAdvanceContext *c, MovPosComb *mpc_io, Segment *leaving) { PredictUserContext *u= c->u; - if (t->seg->motion) - *mpc_io= movpos_change_intent(t->seg->motion); - u->noninv_tally[leaving->tr_backwards]--; if (t->seg->pred_vacated) return 0; /* only vacate once */ @@ -286,18 +320,29 @@ static int tail_nextseg(TrackLocation *t, TrackAdvanceContext *c, return 0; } +/*---------- prediction foredetect advancement ----------*/ + static int fdet_nextseg(TrackLocation *t, TrackAdvanceContext *c, MovPosComb *mpc_io, Segment *before) { PredictUserContext *u= c->u; int advanced; - if (t->seg->motion) - *mpc_io= movpos_change_intent(t->seg->motion); - advanced= u->was_distance - c->distance; + if (u->count_time) { + u->elapsed += advanced / speedmanager_speed_maxestimate(u->train); + } + u->nosec.distance= advanced; - r= trackloc_advance(&u->nose,&u->nosec); if (r) return r; + r= trackloc_advance(&u->nose,&u->nosec); + + if (r==EC_SignalHorizonReached) { + /* stop our prediction now */ + advanced= was_distance= t->distance= 0; + r= 0; + } + + if (r) return r; if (!t->seg->invertible) { u->noninv_tally[t->backwards]++; @@ -312,16 +357,24 @@ static int fdet_nextseg(TrackLocation *t, TrackAdvanceContext *c, c->distance= speedmanager_stoppingdistance(u->train); u->was_distance= c->distance; + u->count_time= 1; return 0; } -static ErrorCode predict_confirm(Train *tra, int accelerate, +/*---------- prediction entrypoint ----------*/ + +static ErrorCode predict_confirm(Train *tra, int accelerate, int justdetected, PredictionProblemCallback *ppc, void *ppcu) { /* Caller must call this with different situations until it succeeds! */ PredictUserContext u; + FOR_SEG { + seg->pred_present= seg->pred_vacated= 0; + } + memset(&u,0,sizeof(u)); u.accelerating= accelerate; + u.count_time= justdetected; /* if just detected we have whole fdet segment */ u.problem_callback= ppc; u.problem_callback_u= ppcu; @@ -331,15 +384,14 @@ static ErrorCode predict_confirm(Train *tra, int accelerate, !tra->foredetect->tr_backwards); /* find the train's tail and mark it present */ - - u.tail.seg->pred_present= 1; u.tailc.distance= tra->detectable + (tra->backwards ? tra->head : tra->tail); u.tailc.nextseg= initpresent_nextseg; - u.tailc.trackend= 0; - u.tailc.getmovpos= 0; + u.tailc.getmovpos= pred_getmovpos; + u.tailc.trackend= pred_trackend_panic; u.tailc.u= &u; + r= initpresent_nextseg(&u.tail,&u.tailc,0,0); assert(!r); r= trackloc_advance(&u.tail,&u.tailc); assert(!r); trackloc_reverse_exact(&u.tail,0); @@ -348,8 +400,8 @@ static ErrorCode predict_confirm(Train *tra, int accelerate, u.nose= fdet; u.nosec.distance= tra->detectable + (tra->backwards ? tra->tail : tra->head); u.nosec.nextseg= nose_nextseg; + u.nosec.getmovpos= pred_getmovpos; u.nosec.trackend= pred_trackend; - u.nosec.getmovpos= 0; u.nosec.u= &u; r= trackloc_advance(&u.nose,&u.nosec); @@ -359,8 +411,8 @@ static ErrorCode predict_confirm(Train *tra, int accelerate, u.fdetc.distance= u.was_distance= INT_MAX; u.fdetc.nextseg= fdet_nextseg; + u.fdetc.getmovpos= pred_getmovpos; u.fdetc.trackend= pred_trackend; - u.fdetc.getmovpos= 0; u.fdetc.u= &u; u.tailc.nextseg= tail_nextseg; @@ -368,21 +420,19 @@ static ErrorCode predict_confirm(Train *tra, int accelerate, r= trackloc_advance(&fdet,&fdetc); if (r) return r; - /* commit here */ + /*----- commit to the plan -----*/ + FOR_SEG { - intr= interferes(seg); if (seg->owner == tra) { - seg->det_ignore= 0; - seg->det_expect= 0; + seg->det_ignore= seg->det_expect= 0; seg->owner= 0; - if (intr) { - assert(!intr->owner || intr->owner==tra); - intr->det_ignore= 0; - } } if (seg->pred_present || seg->pred_vacated) { seg->owner= tra; - if (seg->until) + if (!seg->until) + seg->det_ignore= 1; + } + predict the future fdet.seg= tra->foredetect; @@ -393,6 +443,12 @@ predict the future tail.into= 0; tail.backwards= +void update_head(Train *tra, Segment *seg) { + tra->foredetect= seg; + if (tra->foredetect->movposcomb < 0) + safety_panic(tra,seg, "track route not set and train has arrived"); +} + void safety_notify_detection(Segment *seg) { if (seg->det_ignore) return; if (!seg->det_expected) @@ -400,7 +456,6 @@ void safety_notify_detection(Segment *seg) { Train *tra= seg->owner; - seg_clear_marks(); update_head(tra,seg); predict_and_provide(tra); @@ -426,32 +481,6 @@ typedef struct { Segment *invert_forcer; /* the unswitchable which forces */ } LayTrainState; -#define INTERFERING_MOVPOSCOMB(seg,segi) \ - ((seg)->moving || \ - (seg)->movposcomb < 0 || \ - (segi)->interferes_movposcomb_map & (1u << (seg)->movposcomb)) - -static Segment *interferes(Segment *base) { - const SegmentInfo *basei, *interi; - SegmentNum intern; - Segment *inter; - - basei= base->i; - intern= basei->interferes; - - if (!SOMEP(intern)) return 0; - if (!INTERFERING_MOVPOSCOMB(base,basei)) return 0; - - inter= &segments[intern]; - interi= &info_segments[intern]; - - assert(basei == &info_segments[interi->interferes]); - if (!INTERFERING_MOVPOSCOMB(inter,interi)) - return 0; - - return inter; -} - static void lay_train_check_clash(LayTrainState *l, Segment *check, Segment *report) { const char *exi1="", *exi2=""; diff --git a/hostside/safety.h b/hostside/safety.h index eb51e00..d5edc66 100644 --- a/hostside/safety.h +++ b/hostside/safety.h @@ -256,55 +256,45 @@ void trackloc_set_maxinto(TrackLocation *tloc, Segment *seg, int backwards); typedef struct { /* all set by caller, only distance modified by trackloc: */ int distance; + /* All event callbacks are optional; if not supplied we pretend + * that they were a no-op which returned 0. */ int nextseg(TrackLocation *t, TrackAdvanceContext *c, Segment *next, MovPosComb *mpc_io); /* On entry *mpc_io is from next->movposcomb. nextseg may modify * it if it feels like it in which case the modified value will - * be used instead. If on 0-return it is still -1, getmovpos is used */ + * be used instead. If on 0-return it is still -1, getmovpos is used. + * t->remain is not valid on entry and should not be touched. */ + void getmovpos(TrackLocation *t, TrackAdvanceContext *c, MovPosComb *use_io); + /* Will be called *use_io on entry is + * - at the start of trackloc_advance value from segment + * - after nextseg value left by nextseg + * - by trackloc_getlink getlink's mpc argument + * - by interfering_segment base->movposcomb + * 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. */ int trackend(TrackLocation *t, TrackAdvanceContext *c); - int getmovpos(TrackLocation *t, TrackAdvanceContext *c, MovPosComb *use_r); - /* May be called - * - at the start of trackloc_advance if current segment position unknown - * - after nextseg has failed to determine position of next segment - * - by trackloc_getlink - * it _must_ either return non-0 or set *use_r to a valid value - */ + /* trackloc_advance stops even if this returns 0. */ void *u; } TrackAdvanceContext; int trackloc_getlink(TrackLocation *t, TrackAdvanceContext *c, const SegPosCombInfo **pci_r /* 0 ok */, const SegmentLinkInfo **link_r /* 0 ok */, - MovPosComb mpc /* -1: get from segment or getmovpos */); - /* Of c, only c->getmovpos is used. c may be 0 in which case we - * pretend getmovpos returned -1. */ + MovPosComb mpc /* -1: get from segment */); + /* Of c, only c->getmovpos is used. + * c may be 0 which works just like c->getmovpos==0. */ -int trackloc_advance(TrackLocation *t, TrackAdvanceContext *c); - /* Advances t by dist until either some callback returns non-0 - * or distance becomes 0. nextseg and getmovpos callbacks may be 0. - * If trackend callback is 0 - */ +Segment *segment_interferes(TrackAdvanceContext *c, Segment *base); + /* 0 means we know there is no interference; if we can't determine + * the relevant movposcombs we return the interfering segment. + * c is used as for trackloc_getlink. */ - -int trackloc_further(TrackLocation *tloc, long *remain_io); - /* Advances tloc, decrementing *remain_io, until one of the - * following happens: err set to - * tloc->segn changes returns +1 unchanged - * *remain_io becomes zero returns 0 unchanged - * unknown movpos found returns -1 next segment - * end of track reached returns -2 seg - * current track segment unknown movpos! returns -3 seg - * Does _not_ check that the movposcomb of the segment we - * are moving into is correct. - */ - -void trackloc_reverse(TrackLocation *tloc); - /* Reverses tloc without changing its actual location. */ - -const SegPosCombInfo *trackloc_segposcomb(const TrackLocation *tloc); -const SegmentLinkInfo *trackloc_segmentlink(const TrackLocation *tloc, - const SegPosCombInfo *pci, - unsigned far); +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. */ /*========== useful macros and declarations ==========*/ diff --git a/hostside/trackloc.c b/hostside/trackloc.c index 2553511..1808d37 100644 --- a/hostside/trackloc.c +++ b/hostside/trackloc.c @@ -29,32 +29,26 @@ void trackloc_set_maxinto(TrackLocation *tloc, Segment *seg, int backwards) { int trackloc_getlink(TrackLocation *t, TrackAdvanceContext *c, const SegPosCombInfo **pci_r, const SegmentLinkInfo **link_r, - MovPosComb mpc, int backend) { + MovPosComb mpc) { const SegPosCombInfo *pci; MovPosComb mpc; - if (mpc<0) { + if (mpc<0) mpc= t->movposcomb; - } - if (mpc<0 && c) { - if (c) { - if (!c->getmovpos) - c->panic(t,c,"unexpected lack of definite track route"); - - r= c->getmovpos(t,c, &mpc); - if (r) return r; - } + + if (c && c->getmovpos) { + r= c->getmovpos(t,c,&mpc); + if (r) return r; } if (mpc<0) { *pci_r=0; *link_r=0; - return -1; + return 0; } assert(mpc < seg->i->n_poscombs); pci= &seg->i->poscombs[seg->movposcomb]; if (*pci_r) *pci_r= pci; - if (*link_r) *link_r= (tloc->backwards ^ backend) - ? &pci->backwards : &pci->forwards; + if (*link_r) *link_r= tloc->backwards ? &pci->backwards : &pci->forwards; return 0; } @@ -62,12 +56,12 @@ int trackloc_getlink(TrackLocation *t, TrackAdvanceContext *c, int trackloc_advance(TrackLocation *t, TrackAdvanceContext *c) { Segment *next, *save; - const SegPosCombInfo *pci; const SegmentLinkInfo *link; MovPosComb mpc_nego; + int leaving_back; - r= getsegmentlink(t,c, &pci,&link, t->seg.movposcomb); - if (r) return r; + r= trackloc_getlink(t,c, 0,&link, t->seg.movposcomb); + if (r || !link) return r; for (;;) { if (!c->distance) return 0; @@ -80,11 +74,12 @@ int trackloc_advance(TrackLocation *t, TrackAdvanceContext *c) { next= link->next; if (!SOMEP(next)) { - if (!c->trackend) c->panic(t,c,"unexpected end of track"); - return c->trackend(t,c); + if (c->trackend) return c->trackend(t,c); + return 0; } leaving= t->seg; + leaving_back= t->backwards; t->seg= next; t->backwards ^= link->next_backwards; mpc_nego= next->movposcomb; @@ -94,19 +89,61 @@ int trackloc_advance(TrackLocation *t, TrackAdvanceContext *c) { if (r) return r; } - r= getsegmentlink(t,c, &pci,&link, mpc_nego); - if (r) { t->seg=save; return r; } + r= trackloc_getlink(t,c, 0,&link, mpc_nego); + if (r || !link) { + t->seg=leaving; + t->seg->backwards= leaving_back; + return r; + } t->remain= link->dist; } } } +static int interfering_movposcomb(TrackAdvanceContext *c, Segment *seg) { + MovPosComb mpc; + + mpc= t->movposcomb; + if (c && c->getmovpos) { + r= c->getmovpos(t,c,&mpc); + if (r) return 1; + } + + if (mpc < 0) return 1; + return seg->i->interferes_movposcomb_map & (1u << mpc); +} + +Segment *segment_interferes(TrackAdvanceContext *c, Segment *base) { + SegmentNum intern; + Segment *inter; + + intern= base->i->interferes; + + if (!SOMEP(intern)) return 0; + if (!interfering_movposcomb(c,base)) return 0; + + inter= &segments[intern]; + + assert(base->i == &info_segments[inter->i->interferes]); + if (!interfering_movposcomb(c,inter)) return 0; + + return inter; +} + /* ============ OLD CODE ============= */ +void trackloc_reverse(TrackLocation *tloc); + /* Reverses tloc without changing its actual location. */ + +const SegPosCombInfo *trackloc_segposcomb(const TrackLocation *tloc); +const SegmentLinkInfo *trackloc_segmentlink(const TrackLocation *tloc, + const SegPosCombInfo *pci, + unsigned far); + xxx long trackloc_remaininseg(const TrackLocation *tloc) { const SegPosCombInfo *pci; long segment_len;