chiark / gitweb /
before abandon "count_time" and "justdetected"
authorian <ian>
Sun, 20 Apr 2008 16:05:29 +0000 (16:05 +0000)
committerian <ian>
Sun, 20 Apr 2008 16:05:29 +0000 (16:05 +0000)
hostside/safety.c
hostside/safety.h
hostside/trackloc.c

index a2d9969231abf67b43c5ec2d2b79f7068f149429..ee93426fd983f261780366fb24f40d8fff43b51c 100644 (file)
@@ -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="";
index eb51e000d8a40977789e60252e59ab73f317a589..d5edc66911d42dfbcaa1f28ccdcae536f73a71fd 100644 (file)
@@ -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 ==========*/
 
index 2553511b3419645ff64b10059f2f7cd8aba5b70b..1808d370c102ab515d09847a6c6b9e380cbd560c 100644 (file)
@@ -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;