chiark / gitweb /
WIP movpos.c
authorian <ian>
Sat, 29 Mar 2008 12:29:26 +0000 (12:29 +0000)
committerian <ian>
Sat, 29 Mar 2008 12:29:26 +0000 (12:29 +0000)
hostside/errorcodes.h.gen
hostside/movpos.c [new file with mode: 0644]
hostside/safety.h

index 7608367ef39f933659c80159b1d8e23b56413466..630e7ec6757aa4a0a2fb4249bdd34975ee3b9bcf 100755 (executable)
@@ -4,6 +4,8 @@
        OK
        Invalid
        Safety
+       Points
+       MovFeatKindsCombination
        );
 
 
diff --git a/hostside/movpos.c b/hostside/movpos.c
new file mode 100644 (file)
index 0000000..61ba390
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Handling of points and other moveable features.
+ */
+
+#include "realtime.h"
+
+/*---------- declarations ----------*/
+
+typedef struct SomeChange SomeChange;
+
+typedef struct {
+  MoveFeatInfo *i;
+  Small posn;
+} Motion;
+
+typedef struct {
+  /* call flow is:  allocate [[reserve] request] cancel
+   * error from reserve or request causes call to destroy
+   */
+  SomeChange *(*allocate)(int n_motions); /* always succeeds */
+  ErrorCode (*reserve)(SomeChange*, Segment *move, int maxdelay_ms);
+  ErrorCode (*request)(SomeChange*, Segment *move,
+                      int n_motions, const Motion*, int maxdelay_ms);
+  void (*destroy)(SomeChange*);
+} MethodInfo;
+
+typedef struct MovPosChangeDetails {
+  const MethodInfo *mi;
+  Segment *move;
+  MovPosCallback *on_moving, *on_done;
+  void *u;
+} ChangeHeader;
+
+
+/*---------- method-independent machinery ----------*/
+
+static const MethodInfo methodinfos[]= {
+  { nomove_allocate, nomove_reserve, nomove_request, nomove_cancel }
+  { point_allocate,  point_reserve,  point_request,  point_cancel  }
+};
+
+ErrorCode
+movpos_requestchange(Segment *back, Segment *move, *Segment *fwd,
+                    int maxdelay_ms, MovPosChangeRequest *req_io,
+                    MovPosCallback *on_moving, MovPosCallback *on_done, *u) {
+  const SegmentInfo *movei= move->i;
+  SegPosCombInfo *pci;
+  MovPosComb tcomb, bestcomb=0;
+  int tchanges, bestchanges=INT_MAX;
+  ErrorCode ec;
+
+  for (tcomb=0, pci=movei->poscombs;
+       tcomb<movei->n_poscombs;
+       tcomb++, pci++) {
+    Segment *tback= &segments[pci->backwards.next];
+    Segment *tfwd=  &segments[pci->forwards .next];
+    if (back && !(back==tback || back=tfwd)) continue;
+    if (fwd  && !(fwd ==tback || fwd =tfwd)) continue;
+
+    if (movei->n_movfeats>1) {
+      /* we have to search for the one which is least effort, then */
+      for (feat=0, feati=movei->movfeats, tchanges=0;
+          feat<movei->n_movfeats;
+          feat++)
+       if ((tcomb - move->movposcomb) / feati->weight % feati->posns)
+         tchanges++;
+      if (tchanges > bestchanges)
+       continue;
+    }
+    tcomb= bestcomb;
+    tchanges= bestchanges;
+  }
+
+  if (bestchanges==INT_MAX) { ec= EC_Invalid; goto x; }
+
+  int n_motions=0;
+  Motion motions[movei->n_movfeats];
+  MovFeatKind kind= mfk_none;
+
+  for (feat=0, feati=movei->movfeats;
+       feat<movei->n_movfeats;
+       feat++, feati++) {
+    if ((bestcomb - move->movposcomb) / feati->weight % feati->posns)
+      continue;
+    if (kind) {
+      if (feati->kind != kind) { ec= EC_MovFeatKindsCombination; goto x; }
+      kind= feati->kind;
+    }
+    motions[n_motions].i= feati;
+    motions[n_motions].posn= bestcomb / feati->weight % feati->posns;
+    n_motions++;
+  }
+
+  const MethodInfo *mi= methodinfos[kind];
+
+  if (!*req_io) {
+    (*req_io)= (ChangeHeader*)mi->allocate(n_motions);
+    (*req_io)->mi=        mi;
+    (*req_io)->move=      move;
+    (*req_io)->on_moving= on_moving;
+    (*req_io)->on_done=   on_done;
+    (*req_io)->u=         u;
+  }
+
+  ec= mi->request((SomeChange*)*req_io, move, n_motions, motions, maxdelay_ms);
+  if (ec) goto x;
+
+  return 0;
+
+ x:
+  movpos_cancelchange(*req_io);
+  return ec;
+}
+
+void movpos_cancelchange(MovPosChangeRequest *req) {
+  if (!req) return;
+  req->mi->cancel((SomeChange*)req);
+}
+
+ErrorCode
+movpos_reservechange(Segment *move, int maxdelay_ms,
+                    MovPosChangeRequest *res_r) {
+  MovFeatKind kind= mfk_none;
+
+  for (feat=0; feati=movei->movfeats;
+       feat<movei->n_movfeats;
+       feat++, feati++)
+    if (kind) {
+      if (feati->kind != kind) return EC_MovFeatKindsCombination;
+      kind= feati->kind;
+    }
+
+  const MethodInfo *mi= methodinfos[kind];
+  SomeChange *chg= mi->allocate(movei->n_movfeats);
+  ec= mi->reserve(chg, move, maxdelay_ms);
+  if (ec) goto x;
+
+  *res_r= (ChangeHeader*)chg;
+  return 0;
+
+ x:
+  movpos_cancelchange((ChangeHeader*)chg);
+  return ec;
+}
+
+
+  
+  }
+
+    
+  }
+  
+
+    (*req_io)->move= move;
+    (*req_io)->move= move;
+
+  ChangeHeader *change= method(move, n_motions, motions, *req_io);
+  if (!change)
+    return EC_Point;
+
+  change
+  change.on_moving= on_moving;
+  change.on_done=   on_done;
+  change.u=         u;
+
+  *req_io= 
+  
+    
+
+  MovFeatKind tkind
+    if (tchanges
+
+      unsigned diff= (
+      
+
+ / feati->weight
+
+      unsigned posold= (move->movposcomb / feati->weight) % feati->posns;
+    
+  }
+
+  for (feat=0, feati=movei->movfeats, result=0;
+       feat<movei->n_movfeats;
+       feat++) {
+    unsigned posold= (move->movposcomb / feati->weight) % feati->posns;
+    for (poschange=0; poschange<feati->posns; poschange++) {
+      unsigned posnew= poschange % feati->posns;
+      
+
+/*
+ * Currently there is only one queue for the one CDU.
+ *
+ * We maintain a queue of change requests.  The queue can also contain
+ * reservations.  We divide time into discrete slots, numbered with
+ * clock arithmetic.
+ *
+ *     cslot         cslot+1      cslot+2
+ *
+ *     currently     next in      after
+ *     changing      line         that
+ */
+
+typedef unsigned Slot;
+
+typedef struct PointChangeQueueEntry {
+  struct PointChangeQueueEntry *next, *back;
+
+  Slot latest, needs;
+  Segment *move;
+  Motion motions[];
+} QE;
+
+static Slot cslot;
+static struct { QE *head, *tail; } queue;
+
+convert incoming latest's into queue lengths as simple counts
+maintain latest count number for each 
index 9d96fb0d393381797fdcb0e69be30cef92982ee0..65faf2d23b7caed4e65eb07efd10c326ae4870c6 100644 (file)
@@ -73,7 +73,7 @@ struct Segment {
   unsigned
     tr_backwards:1, /* train's motion is (would be) backwards wrt track */
     ho_backwards:1, /* home train has its front and rear backwards wrt track */
-    movfeat_moving:1, /* feature(s) have been told to change to movposcomb */
+    points_moving:1, /* feature(s) have been told to change to movposcomb */
     cm_autostop:1, /* train should stop on detection */
     seg_inverted:1, /* polarity is inverted */
     tr_updated:1, /* for use by safety.c:lay_train etc.; otherwise 0 */
@@ -129,6 +129,43 @@ void safety_setdirection(Train* tra, int sense_fixme_define_this_properly);
 void safety_notify_detection(Segment *seg);
   /* Called by startup.c when new train detection occurs in state Run. */
 
+/*========== movpos.c ==========*/
+/*
+ * movpos.c manages the CDU and points and other moveable features.
+ * Only safety.c should request changes.
+ */
+
+typedef struct MovPosChangeDetails *MovPosChangeRequest;
+typedef void MovPosCallback(Segment*, MovPosChangeRequest, void *u);
+
+ErrorCode
+movpos_requestchange(Segment *back, Segment *move, Segment *fwd,
+                    int maxdelay_ms, MovPosChangeRequest *req_io,
+                    MovPosCallback *on_moving, MovPosCallback *on_done,
+                    void *u);
+  /* back and fwd may be 0 if we don't care (and must be if there is
+   * no track in that direction.  It is immaterial which is back and
+   * which fwd.  *req_io should be 0 on entry, or the results of
+   * movpos_reservechange; on successful exit it is non-0.  req_io may
+   * be 0.  Updates seg->movposcomb and seg->points_moving.  Returns
+   * EC_Invalid if there is no movposcomb of move matching back/fwd,
+   * or EC_MovPos if the maxdelay_ms could not be met; on error any
+   * reservation is destroyed and *req_io is undefined. */
+
+void movpos_cancelchange(MovPosChangeRequest /* 0 OK */);
+  /* Cancels any movements not yet done; may leave movposcomb in an
+   * unknown or invalid physical state.  For a reservation, just
+   * discards it without doing anything. */
+
+ErrorCode
+movpos_reservechange(Segment *move, int maxdelay_ms,
+                    MovPosChangeRequest *res_r);
+  /* Returns EC_Points if the maxdelay_ms could not be met.  The resulting
+   * MovPosChangeRequest is a reservation which is guaranteed to be
+   * useable successfully later for any movpos_requestchange for the
+   * same move and a greater or equal maxdelay_ms.  On successful
+   * exit *res_r is set to non-0. */
+
 /*========== speedmgr.c ==========*/
 
 void speedmanager_speedchange_request(Train *tra, long speed);