chiark / gitweb /
wip new safety before tackle speed
authorian <ian>
Sun, 20 Apr 2008 21:38:34 +0000 (21:38 +0000)
committerian <ian>
Sun, 20 Apr 2008 21:38:34 +0000 (21:38 +0000)
hostside/errorcodes.h.gen
hostside/realtime.c
hostside/safety.c
hostside/safety.h

index d8570b513c806b8e5aa42be1f48ec5adeebcd6fe..5ccde34df6cda8c340094dd7d31714533c40ab39 100755 (executable)
@@ -8,8 +8,8 @@
        BufferFull
        BadCmd
        NotFound
-       ProblemPredicted
-       SignalStopHorizonReached
+       SignallingProblemPredicted
+       SignallingHorizonReached
        );
 
 
index fbeb8c5254ff9a9cede20c3786b0bb273edab3be..c16b4a76543892dbf996bb2609077271b6103c0b 100644 (file)
@@ -64,9 +64,9 @@ static char *transegn2suffixstring(Train *tra, Segment *seg) {
   return s;
 }
 
-void vlogmsg(ErrorCode ec, Train *tra, const SegmentInfo *segi,
+void vlogmsg(const char *intro, Train *tra, const SegmentInfo *segi,
             const char *fmt, va_list al) {
-  oprintf(UPO, "message %s", ec ? errorcodelist[ec] : "info");
+  oprintf(UPO, "log %s", intro);
   if (segi) oprintf(UPO, " @%s", segi->pname);
   if (tra) oprintf(UPO, " %s",  tra->pname);
   if (segi || tra) oprintf(UPO, ":");
@@ -75,11 +75,11 @@ void vlogmsg(ErrorCode ec, Train *tra, const SegmentInfo *segi,
   oprintf(UPO, "\n");
 }
 
-void logmsg(ErrorCode ec, Train *tra, const SegmentInfo *segi,
+void logmsg(const char *intro, Train *tra, const SegmentInfo *segi,
            const char *fmt,...) {
   va_list al;
   va_start(al,fmt);
-  vlogmsg(ec,tra,segi,fmt,al);
+  vlogmsg(intro,tra,segi,fmt,al);
   va_end(al);
 }
 
@@ -103,14 +103,6 @@ void safety_panic(Train *tra, Segment *seg, const char *fmt, ...) {
   safety_vpanic(tra, seg, fmt, al);
 }
 
-ErrorCode safety_problem(Train *tra, Segment *seg, const char *fmt,...) {
-  va_list al;
-  va_start(al,fmt);
-  vlogmsg(EC_Safety, tra, seg?seg->i:0, fmt, al);
-  va_end(al);
-  return EC_Safety;
-}
-
 /*---------- printing nmra data ----------*/
 
 typedef struct {
index 2d6a35a1dba7674b260f34f5dab03a12b56a6c9e..bb38bf3b4fe4f8d9d893fa4c3335403081d38b52 100644 (file)
@@ -186,15 +186,15 @@ Segment *segments;
 #define pred_vacated mark2
 #define will_polarise mark3
 
-typedef void PredictionProblemCallback(void *pu, Train *tra, TrackSegment *seg,
-                                      const char *fmt, va_list al);
+typedef void PredictionProblemCallback(Train *tra, TrackSegment *seg,
+                                      void *pu, const char *message);
 
 typedef struct {
   unsigned
     accelerating:1,
     walk_compute_polarise:1, /* nose_nextseg still needs to worry */
     need_polarise:1, /* when we commit */
-    train_polarity_inverted:1, /* right now */
+    train_polarity_inverted:1, /* right now, or if know_best, the best */
     know_best_polarity; /* longest-lasting into the future */
   TrackLocation nose, fdet, tail;
   TrackAdvanceContext nosec, tailc, fdetc;
@@ -214,7 +214,17 @@ typedef struct {
 
 static ErrorCode predict_vproblem(PredicUserContext *u, TrackSegment *seg,
                                  const char *fmt, va_list al) {
-  u->problem_callback(u->train,seg,fmt,al);
+  int l;
+  char *message;
+
+  l= vasprintf(&message, fmt, al);  if (l <= 0) diem();
+
+  if (!u->problem_callback)
+    safety_panic(u->train, seg, "unexpected problem predicted",
+                " (context: %s): %s", u->problem_callback_u, message);
+  else
+    u->problem_callback(u->train, seg, u->problem_callback_u, message);
+
   return EC_ProblemPredicted;
 }
 static ErrorCode predict_problem(PredicUserContext *u, TrackSegment *seg,
@@ -286,33 +296,6 @@ static int nose_nextseg(TrackLocation *t, TrackAdvanceContext *c,
                             interferer->i->pname);
   }
 
-  /* Check polarity */
-
-  if (u->walk_compute_polarise) {
-    if (!u->need_polarise) {
-      /* this is the very next segment as we only do this once: */
-      u->walk_compute_polarise= u->need_polarise=
-       (t->seg->seg_inverted ^ t->seg->tr_backwards ^
-        u->train_polarity_inverted);
-    }
-    if (t->seg->will_polarise)
-      /* this is our 2nd visit, stop now */
-      u->walk_compute_polarise= 0;
-    
-    if (u->walk_compute_polarise)
-      seg->will_polarise= 1;
-
-    if (!u->know_best_polarity && !t->seg->i->invertible) {
-      u->know_best_polarity= 1;
-      u->
-      
-      
-      if (
-
-    int train_inverted_here= 
-    
-  }
-
   /* What about the route ? */
 
   if (t->seg->i->n_poscombs==1)
@@ -427,15 +410,55 @@ static int fdet_nextseg(TrackLocation *t, TrackAdvanceContext *c,
    * actually use it ourselves and trackloc_advance will call
    * getmovpos. */
 
+  /* Check polarity */
+
   if (!t->seg->invertible) {
     u->noninv_tally[t->backwards]++;
     if (u->noninv_tally[0] && u->noninv_tally[1])
       return predict_problem(u, t->seg, "cannot set track polarity");
   }
 
+  if (u->was_distance == INT_MAX) {
+    t->seg->det_expected= 1;
+
+    u->walk_compute_polarise= u->need_polarise=
+      (t->seg->seg_inverted ^ t->seg->tr_backwards ^
+       u->train_polarity_inverted);
+  }
+
+  if (u->walk_compute_polarise) {
+    if (t->seg->will_polarise)
+      /* this is our 2nd visit, stop now */
+      u->walk_compute_polarise= 0;
+  }
+  if (u->walk_compute_polarise) {
+    if (!u->know_best_polarity) {
+      if (u->noninv_tally[0]) {
+       u->train_polarity_inverted= 0;
+       u->know_best_polarity= 1;
+      } else if (u->noninv_tally[1]) {
+       u->train_polarity_inverted= 1;
+       u->know_best_polarity= 1;
+      }
+    }
+    if (u->know_best_polarity && 
+       !t->seg->i->invertible
+       u->noninv_tally[ t->backwards ^ u->train_polarity_inverted ]) {
+      /* incompatible, stop now */
+      u->walk_compute_polarise= 0;
+    }
+  }
+  if (u->walk_compute_polarise) {
+    seg->will_polarise= 1;
+  }
+
+  /* Advance the tail */
+
   u->tailc.distance= advanced;
   r= trackloc_advance(&u->tail,&u->tailc);  assert(!r);
 
+  /* Final adjustments, prepare for next iteration */
+
   if (u->was_distance == INT_MAX)
     c->distance= speedmanager_stoppingdistance(u->train);
 
@@ -453,6 +476,7 @@ static ErrorCode predict_confirm(Train *tra, int accelerate,
   /* Caller must call this with different situations until it succeeds! */
   PredictUserContext u;
   Segment *foredet;
+  SEG_IV;
 
   FOR_SEG {
     seg->now_preset= seg->pred_present=
@@ -464,7 +488,6 @@ static ErrorCode predict_confirm(Train *tra, int accelerate,
   memset(&u,0,sizeof(u));
   u.accelerating= accelerate;
   u.walk_will_polarise= 1;
-  u.need_polarise= 0;
   u.train_polarity_inverted= foredet->seg_inverted ^ foredet->tr_backwards;
   u.problem_callback= ppc;
   u.problem_callback_u= ppcu;
@@ -496,7 +519,7 @@ static ErrorCode predict_confirm(Train *tra, int accelerate,
   u.count_time= 0;
 
   r= trackloc_advance(&u.nose,&u.nosec);
-  if (r) return r;
+  if (r) goto xproblem;
 
   /* predict the future */
 
@@ -509,7 +532,7 @@ static ErrorCode predict_confirm(Train *tra, int accelerate,
   u.tailc.nextseg= tail_nextseg;
 
   r= trackloc_advance(&fdet,&fdetc);
-  if (r) return r;
+  if (r) goto xproblem;
 
   /*----- commit to the plan -----*/
 
@@ -521,6 +544,9 @@ static ErrorCode predict_confirm(Train *tra, int accelerate,
 
   r= trackloc_advance(&fdet,&fdetc);
 
+  if (u.need_polarise)
+    actual_inversions_start();
+  
   FOR_SEG {
     if (seg->owner == tra) {
       seg->det_ignore= seg->det_expected= 0;
@@ -537,322 +563,75 @@ static ErrorCode predict_confirm(Train *tra, int accelerate,
       ec= movpos_change(seg, target, -1, reservation);
       assert(!ec);
     }
-    
-       movpos_unreserve(seg->motion);
-       seg->motion= 0;
-      } else if (seg->pred_vacated
-
-  }
-}
-
-predict the future
-  fdet.seg= foredet;
-
-  fdet.into= 0;
-
-  tail.seg= foredet;
-  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)
-    safety_panic(0,seg, "unexpected detection");
-
-  Train *tra= seg->owner;
-
-  update_head(tra,seg);
-  predict_and_provide(tra);
-
-
-
-  /* ============ OLD CODE ========== */
-
-static void seg_clear_stale(Segment *seg) {
-  seg->owner= 0;
-  seg->until_here= seg->until_detect= 0;
-}
-
-typedef struct {
-  /* constant inputs */
-  Train *tra;
-  /* modified in place by lay_train_pass: */
-  ErrorCode ec;
-  int invert_count[2]; /* count of (switchable) segments,
-                       * invert_count[0]: inverted from train's pov
-                       *   iff train is backwards (ie, train not inverted)
-                       * invert_count[1]: train is inverted
-                       * set to -1 if any unswitchable is the other way */
-  Segment *invert_forcer; /* the unswitchable which forces */
-} LayTrainState;
-
-static void lay_train_check_clash(LayTrainState *l, Segment *check,
-                                 Segment *report) {
-  const char *exi1="", *exi2="";
-  if (check!=report) { exi1= " at "; exi2= check->i->pname; }
-
-  if (check->tr_updated) {
-    l->ec= safety_problem(l->tra, report, "self-collision%s%s", exi1,exi2);
-    return;
-  }
-  if (check->owner) {
-    if (check->owner != l->tra) {
-      l->ec= safety_problem(l->tra, report, "collision with %s"
-                           "%s%s", check->owner->pname, exi1,exi2);
-      return;
+    if (u.need_polarise) {
+      if (seg->will_polarise)
+       seg->seg_inverted= seg->tr_backwards ^ u.train_polarity_inverted;
+      actual_inversions_segment(seg);
     }
+    seg->now_present= seg->pred_present=
+      seg->pred_vacated= seg->will_polarise= 0;
   }
-}
-
-static void lay_train_pass(LayTrainState *l,
-                          TrackLocation tloc, long advance,
-                          long speed, unsigned backwards,
-                          unsigned check_clash) {
-  Segment *seg, *inter;
-  long overall, remain, dist_until, time_until;
-  int *invert_likehere, train_inverted_here;
-  Train *tra= l->tra;
-  const SegPosCombInfo *pci;
-  const SegmentLinkInfo *link;
-
-  if (l->ec) return;
-
-  seg= tra->foredetect;
-
-  remain= overall= advance + speed * SPEED_CLEAR_MULT;
-
-fprintf(stderr,"lay_train_pass %s @%s+%ld check_clash=%d"
-       " advance=%ld speed=%ld remain=%ld backwards=%u\n",
-       tra->pname, seg->i->pname, tloc.into,
-       check_clash, advance,speed,remain,
-       backwards);
-
-  for (;;) {
-    seg= tloc.seg;
-
-fprintf(stderr,"lay_train_pass  loop @%s remain=%ld\n",
-       seg->i->pname, remain);
-
-    if (check_clash) {
-      lay_train_check_clash(l,seg,seg);
-      inter= interferes(seg);
-      if (inter) lay_train_check_clash(l,inter,seg);
-    }
-
-    seg->owner= l->tra;
-    seg->tr_backwards= tloc.backwards ^ backwards;
-    seg->tr_updated= 1;
-
-    if (backwards)
-      seg->until_detect= 0;
 
-    train_inverted_here= seg->seg_inverted ^ seg->tr_backwards;
-    invert_likehere= &l->invert_count[train_inverted_here];
+  if (u.need_polarise)
+    actual_inversions_done();
 
-    if (seg->i->invertible) {
-      if (*invert_likehere >= 0)
-       (*invert_likehere)++;
-    } else {
-      if (*invert_likehere < 0) {
-       l->ec= safety_problem(l->tra,0, "train requires"
-                             " noninvertible segments with opposite polarity:"
-                             " @%s, @%s", seg->i->pname,
-                             l->invert_forcer->i->pname);
-       return;
-      }
-      assert(!seg->seg_inverted);
-      (*invert_likehere)++;
-      l->invert_count[!train_inverted_here]= -1;
-      l->invert_forcer= seg;
-    }
-
-    dist_until= (overall - remain) - advance;
-    time_until= !speed ? 0 : SPEED_CALC_TIME(speed, dist_until, DOWN);
-    *(check_clash ? &seg->until_here : &seg->until_detect)= time_until;
-
-    if (!remain) break;
-    int r= trackloc_further(&tloc, &remain);
-
-fprintf(stderr,"lay_train_pass   further=%d tloc=@%s+%ld remain=%ld\n",
-       r, tloc.seg->i->pname, tloc.into, remain);
-
-    switch (r) {
-    case -2:
-      l->ec= safety_problem(l->tra, seg, "end of track");
-      return;
-    case -1:
-      l->ec= safety_problem(l->tra, tloc.err, "track route not set");
-      return;
-    case +1:
-      pci= trackloc_segposcomb(&tloc);
-      link= trackloc_segmentlink(&tloc,pci,0);
-      if (link->next+segments != seg) {
-       l->ec= safety_problem(l->tra, link->next+segments,
-                             "track route set against us");
-       return;
-      }
-      break;
-    case 0:
-      return;
-    default:
-      abort();
-    }
-  }
-}
-
-static void lay_train_inversions(LayTrainState *l) {
-  SEG_IV;
-  int train_be_inverted, seg_be_inverted;
-
-  if (l->ec) return;
-
-  train_be_inverted= l->invert_count[1] > l->invert_count[0];
-  assert(l->invert_count[train_be_inverted] >= 0);
-
-  actual_inversions_start();
+  return 0;
 
+ xproblem:
   FOR_SEG {
-    if (!seg->tr_updated) continue;
-    assert(seg->owner == l->tra);
-    seg_be_inverted= train_be_inverted ^ seg->tr_backwards;
-    assert(!(seg_be_inverted && !segi->invertible));
-    if (!segi->invertible)
-      continue;
-    seg->seg_inverted= seg_be_inverted;
-    actual_inversions_segment(seg);
-  }
-  actual_inversions_done();
-}
-
-static void lay_train_done(LayTrainState *l) {
-  SEG_IV;
+    seg->now_present= seg->pred_present=
+      seg->pred_vacated= seg->will_polarise= 0;
 
-  FOR_SEG {
-    if (seg->owner == l->tra) {
-      if (!seg->tr_updated) seg_clear_stale(seg);
-      seg->tr_updated= 0;
+    if (!seg->owner && !seg->moving && seg->motion) {
+      movpos_unreserve(seg->motion);
+      seg->motion= 0;
     }
-    assert(!seg->tr_updated);
-    assert(seg->until_detect >= seg->until_here);
   }
 }
 
-static ErrorCode lay_train(Train *tra, long added_slop) {
-  Segment *seg;
-  TrackLocation tloc;
-  long head, headslop, tail, taildet;
-  LayTrainState l;
-
-  seg= tra->foredetect;
-
-  tloc.seg= seg;
-  tloc.into= tra->maxinto;
-  tloc.backwards= seg->tr_backwards;
-
-fprintf(stderr,"lay_train %s @%s added_slop=%ld maxinto=%ld "
-       "tra->backwards=%d tloc.backwards=%d\n",
-       seg->i->pname, tra->pname, added_slop, (long)tra->maxinto,
-       tra->backwards, tloc.backwards);
-
-  l.tra= tra;
-  l.ec= 0;
-  l.invert_count[0]= l.invert_count[1]= 0;
-
-  head= tra->backwards ? tra->tail : tra->head;
-  headslop= head + added_slop;
-
-  /* 1st pass:
-   * update actual train location (train's head and future locations).
-   *
-   * 2nd pass:
-   * update detection (future locations) only.
-   *
-   * 3rd pass:
-   * train location (current location and tail)
-   *
-   * Clash checking is done in passes 1 and 3, including checking
-   * whether the train clashes with itself (ie, fail if we find
-   * segment with same train and tr_updated set).
-   */
-  lay_train_pass(&l, tloc,  headslop, tra->speed, 0, 1);
-  lay_train_pass(&l, tloc,  0,        tra->speed, 0, 0);
-
-  trackloc_reverse(&tloc);
-  seg->tr_updated= 0; /* we're about to do this one again */
-  tail= tra->backwards ? tra->head : tra->tail;
-  taildet= tra->detectable + tail + tra->maxinto;
-
-  lay_train_pass(&l, tloc, taildet,   0,          1, 1);
+/*========== entrypoints from rest of the program ==========*/
 
-  lay_train_inversions(&l);
-  lay_train_done(&l);
-
-  return l.ec;
+static void detection_report_problem(Train *tra, TrackSegment *seg,
+                                    void *pu, const char *message) {
+  logmsg("SignallingProblemPredicted",tra,seg->i,
+        "re detection @%s: %s", tra->foredetect->i->pname, message);
 }
 
 void safety_notify_detection(Segment *seg) {
-  Train *tra= seg->owner;
-  ErrorCode ec;
-  TrackLocation tloc;
-
-  if (!seg->until_detect)
-    return;
-
-  tloc.seg= seg;
-  tloc.into= 0;
-  tloc.backwards= seg->tr_backwards;
+  Train *tra;
+  
+  if (seg->det_ignore) return;
+  if (!seg->det_expected)
+    safety_panic(0,seg, "unexpected detection");
 
+  tra= seg->owner;
   tra->foredetect= seg;
-  tra->maxinto= trackloc_remaininseg(&tloc);
-
-  if (seg->cm_autostop) {
-    seg->cm_autostop= 0;
-    if (!tra->estopping) {
-      speedmanager_autostop(tra);
-      if (!tra->speed && tra->maxinto > AUTOSTOP_UNCERTAINTY)
-       /* At some point we may need to allow more slop when the
-        * next segment is points than when this is the last segment
-        * (ie, just buffers next). */
-       tra->maxinto= AUTOSTOP_UNCERTAINTY;
-    }
-  }
-  tra->uncertainty= tra->maxinto;
-
-  if (!tra->estopping) {
-    ec= lay_train(tra, 0);
-    if (ec) {
-      logmsg(ec,tra,seg->i, "emergency stop on reaching here");
-      safety_emergencystop(tra);
-    }
-  }
-}
-
-void safety_emergencystop(Train *tra) {
-  ErrorCode ec;
+  if (tra->foredetect->movposcomb < 0)
+    safety_panic(tra,seg, "track route not set and train has arrived");
 
-  if (tra->estopping) return;
+  ec= predict_confirm(tra, 0, detection_report_problem, 0);
+  if (!ec) return;
+  
+  assert(ec == EC_SignallingProblemPredicted);
 
-  ec= lay_train(tra, ESTOP_UNCERTAINTY);
-  if (ec) safety_panic(tra,0, "emergency stop forbidden!");
-  speedmanager_emergencystop(tra);
+  tra->sigstopping= 1;
+  predict_confirm(tra, 0, 0,"detection");
+  assert(!ec);
 }
 
 ErrorCode safety_checkmovposchange(Segment *seg) {
   ErrorCode ec;
   if (seg->owner) {
-    ec= safety_problem(seg->owner, seg, "must not unset route train is using");
-    logmsg(ec,seg->owner,seg->i,"countermanded point change");
-    return ec;
+    oprintf(UPO,"ack SignallingProblemPredicted @%s %s:"
+           " route set for approaching train",
+           seg->i->pname, seg->owner->pname);
+    return EC_BadCmd;
   }
   return 0;
 }
 
+  /* ============ OLD CODE ========== */
+
 ErrorCode safety_requestspeed(Train *tra, long newspeed) {
   long oldspeed;
   ErrorCode ec;
index 777b3561ef269660cf5f73199d96b5cc02d991a1..7947b6496d6bcb80c597c59975639fd9b1bde774 100644 (file)
@@ -83,9 +83,9 @@ struct Segment {
  * handling, arg parsing, etc.
  */
 
-void vlogmsg(ErrorCode ec, Train *tra, const SegmentInfo *segi,
+void vlogmsg(const char *intro, Train *tra, const SegmentInfo *segi,
             const char *fmt, va_list al) __attribute__((format(printf,4,0)));
-void logmsg(ErrorCode ec, Train *tra, const SegmentInfo *segi,
+void logmsg(const char *intro, Train *tra, const SegmentInfo *segi,
            const char *fmt, ...) __attribute__((format(printf,4,5)));
 
 void safety_vpanic(Train *tra, Segment *seg, const char *fmt, va_list al)
@@ -93,10 +93,6 @@ void safety_vpanic(Train *tra, Segment *seg, const char *fmt, va_list al)
 void safety_panic(Train *tra, Segment *seg, const char *fmt,...)
      __attribute__((format(printf,3,4),noreturn));
 
-ErrorCode safety_problem(Train *tra, Segment *seg, const char *fmt, ...)
-     __attribute__((format(printf,3,4)));
-     /* simple wrapper around vlogmsg; implies and returns EC_Safety */
-
 /*========== safety.c ==========*/
 /*
  * safety.c is responsible for ensuring that things don't go