chiark / gitweb /
before remove special moving state which delays after point move
authorian <ian>
Sat, 5 Apr 2008 19:01:44 +0000 (19:01 +0000)
committerian <ian>
Sat, 5 Apr 2008 19:01:44 +0000 (19:01 +0000)
hostside/movpos.c

index 7722f17dcbf6f7ab915faf9d66db3d3112d8635c..b450da0e760e7c036ed8941d641eb605238d6902 100644 (file)
@@ -6,32 +6,61 @@
 
 /*========== 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
+typedef struct KindInfo KindInfo;
+
+/* Kind-independent code is responsible for determining
+ * the method, doing a bit of cleanup, and adjusting the flow
+ * slightly.  Per-kind code does the actual work and is mostly in
+ * charge - it is also responsible for updating seg->moving.
+ */
+/* The following states exist for each MovPosChange
+ * at points when control flow  passes between kind and indep:
+ *   U  Unallocated  no memory allocated (MovPosChange does not exist)
+ *   A  Allocated    memory allocation done
+ *   R  Reserved     reservation was successful
+ *   C  Confirmed    motion queued and will occur
+ *   E  Erroneous    indep must call destroy straight away
+ */
+
+typedef struct MovPosChange {      /* valid in:   filled in by and when:     */
+  const KindInfo *ki;              /*  ARCE        indep after allocate()    */
+  Segment *move;                   /*  ARCE        indep after allocate()    */
+  MovPosCallback *on_done;         /*  C           indep before confirm()    */
+  void *u;                         /*  C           indep before confirm()    */
+  MovPosComb actual;               /*  C           see below                 */
+  /* kind-specific data follows */ /*  varies     kind-specific code, varies */
+} Change;
+  /* `actual' contains the kind's record of the physical state.  It is
+   * initialised by indep (just before confirm) from move->moving->actual
+   * or move->movposcomb as the case may be.  It should be updated
+   * by the kind, since it is used by indep for calculating the number
+   * and identities of the features which may need to change when a
+   * new move request is intended to replace an existing one - ie, the
+   * contents of the motions[] provided to a subsequent confirm().
+   * So while a change is Confirmed, the physical state is recorded
+   * only in the relevant change, and not in the segment's movposcomb.
+   * Once a change goes to Confirmed, the indep code never untangles it
+   * so the kind can manage the proper transition.
    */
-  SomeChange *(*allocate)(int alloc_motions); /* always succeeds */
-  ErrorCode (*reserve)(SomeChange*, Segment *move, int maxdelay_ms);
-    /* indep machinery guarantees  alloc_motions >= move->i->n_motions */
-  ErrorCode (*request)(SomeChange*, Segment *move,
-                      int n_motions, const Motion*, int maxdelay_ms);
-    /* indep machinery guarantees  alloc_motions >= n_motions */
-  void (*destroy)(SomeChange*);
-} MethodInfo;
-
-typedef struct MovPosChangeDetails {
-  const MethodInfo *mi;
-  Segment *move;
-  MovPosCallback *on_moving, *on_done;
-  void *u;
-} ChangeHeader;
+
+struct KindInfo {
+  Change *(*allocate)(int alloc_motions); /* U->A (always succeeds) */
+  ErrorCode (*reserve)(Change*, Segment*, int ms); /* A->R; error: A->E */
+  ErrorCode (*confirm)(Change*, Segment*, int n_motions,
+                      const Motion*, int ms);   /* [AR]->C; error; [AR]->E */
+  void (*destroy)(Change*);                        /* [ARCE]->U */
+  /* indep guarantees that
+   *   alloc_motions >= move->i->n_motions    on reserve
+   *   alloc_motions >= n_motions             on confirm
+   * and that if on entry to reserve move->moving is non-0,
+   *  it is of the same kind
+   */
+};
 
 /*========== points ==========*/
 
@@ -54,16 +83,32 @@ typedef struct MovPosChangeDetails {
 typedef unsigned PtSlot;
 typedef int PtSlotSigned;
 
-typedef struct {             /* Allocated Reserved  Confirmed               */
-                   /* in queue?  absent    reserved  confirmed              */
-  ChangeHeader h;                                                these two  */
-  Slot deadline;   /*            ~0        relative  absolute  <- `statedet' */
-  int n_motions;   /*            alloc'd   alloc'd   undone       fields    */
-  Motion motions[];/*   [0].i:   0         0         non-0     <- indicate  */
-                   /*  [..].i:   undef     undef     non-0        state     */
-                   /*   .posn:   undef     undef     defined                */
+/* We think there are three states: Allocated, Reserved and Confirmed.
+ * (plus of course Unallocated where we don't have a request at all).
+ * These correspond to the indep code as follows:
+ *
+ *  indep state   pt state    queues checked and plan viable
+ *   Unallocated   n/a         yes
+ *   Allocated     Allocated   yes
+ *   Reserved      Reserved    yes
+ *   Confirmed     Confirmed   yes
+ *   Erroneous     A/R/C       no
+ *
+ * Erroneous exists only after a failed reserve() or confirm() so it's
+ * not that confusing to have this slightly malleable terminology.
+ */
+
+typedef struct {                 /* Allocated  Reserved   Confirmed       */
+                     /* in queue?    absent     reserved   confirmed      */
+  ChangeHeader h;
+  Slot deadline;     /*              ~0         relative   absolute    <- */
+  int n_motions;     /*              alloc'd    alloc'd    undone         */
+  Motion motions[];  /*   [0].i:     0          0          non-0       <- */
+                     /*  [..].i:     undef      undef      non-0          */
+                     /*   .posn:     undef      undef      defined        */
 } PointReq;
-  /* We abbreviate these states as   A R C
+  /* We can determine the the state by looking at the two
+   * `statedet' fields, marked <- above.
    * There are also intermediate states where the req's
    *  statedet fields do not agree with the queue it's on.
    *  We write these as, for example,
@@ -75,67 +120,98 @@ typedef struct {             /* Allocated Reserved  Confirmed               */
 #define CDU_RECHARGE   250 /*ms*/
 #define POINT_MOVEMENT  50 /*ms*/
 
-#define PT_MAX_QUEUE  15
-
-static PtSlot pt_cslot;
-static int pt_cdu_charged;
+typedef struct {
+  int n;
+  PointReq *l[PT_MAX_QUEUE];
+} PointQueue;
 
 todo
  actually fire points: use item, and remove it, etc.
  write check routine
 
-typedef struct {
-  int n;
-  PointReq *l[PT_MAX_QUEUE];
-} PointQueue;
+#define PT_MAX_QUEUE  15
 
-static PointQueue pt_confirmed, pt_reserved;
+/*
+ * CDU and point queue states:
+ *
+ *
+ *    ____________                 pt_cdu_     conf'd  conf'd          pt_
+ *   /   points_  \                charged       .n    .l[0]->         motion
+ *   |   all_      |                                   n_motions       timeout
+ *   |   abaondon  |
+ *   |             V
+ *   |from       INACTIVE              -1      0       n/a             Idle
+ *   |any       <=Sta_Settling
+ *  ^^^^^^^^     (start)
+ *                 |
+ *    ____________ |turning
+ *   /            \| _on
+ *   |             V
+ *   |           CHARGING              0       any     any or n/a      Idle
+ *   |          >=Sta_Resolving
+ *   |   _________ |
+ *   |  /         \|
+ *   |  |          |on_pic
+ *   |  |          |_charged
+ *   |  |          V
+ *   ^  ^        READY                 1       any     any or n/a      Idle
+ *   |  |          |
+ *   |  |          |pt_check_action
+ *   |  ^          |fires a point
+ *   |\___________/|
+ *   |        more |last motion
+ *   |  ^  motions |
+ *   |  |          |
+ *   |  |          V
+ *   |  |        MOVING                        0       >0      0               Running
+ *   |  \_________/|
+ *   |             |
+ *    \____________/
+ *      motion_done
+ */
 
-#define PT_DEL ((const MovFeatInfo*)info_segments) /* some random struct */
+static PtSlot pt_cslot;
+static int pt_cdu_charged;
+static PointQueue pt_confirmed, pt_reserved;
+static TimeoutEvent pt_motion_timeout;
 
-static pt__maxdelay_reldeadline(int maxdelay_ms) {
+static pt_maxdelay_reldeadline(int maxdelay_ms) {
   return (maxdelay_ms - POINT_MOVEMENT + CDU_RECHARGE) / CDU_RECHARGE;
 }
 
-static void pt__queue_remove_index(PointQueue *q, int index) {
+static void pt_queue_remove_index(PointQueue *q, int index) {
   q->n--;
   memmove(&q->l[index], &q->l[index+1], sizeof(q->l[0]) * (q->n - index));
 }
 
-static void pt__req_compar(const void *av, const void *bv) {
+static void pt_req_compar(const void *av, const void *bv) {
   PointQueue *const *a= av;
   PointQueue *const *b= av;
   return (PtSlotSigned)((*b)->deadline - (*a)->deadline);
 }
 
-static void pt__queue_remove_item(PointQueue *q, PointReq *r) {
+static void pt_queue_remove_item(PointQueue *q, PointReq *r) {
   PointQueue **entry;
-  entry= bsearch(r, q->l, q->n, sizeof(q->l[0]), pt__req_compar);
+  entry= bsearch(r, q->l, q->n, sizeof(q->l[0]), pt_req_compar);
   assert(entry);
-  pt__queue_remove_index(q, entry - q->l);
+  pt_queue_remove_index(q, entry - q->l);
 }
 
-static void pt__dequeue(PointReq *r) { /* X->XA */
+static void pt_dequeue(PointReq *r) { /* X->XA */
   if (r->motions[0].i) {
-    pt__queue_remove_item(&pt_confirmed, r);
+    pt_queue_remove_item(&pt_confirmed, r);
   } else if (~r->deadline) {
-    pt__queue_remove_item(&pt_reserved, r);
+    pt_queue_remove_item(&pt_reserved, r);
   }
 }
 
-static void pt_destroy(SomeChange *chg) { /* X->XA and then free it */
-  PointReq *r= (PointReq*)chg;
-  pt__dequeue(r);
-  free(r);
-}
-
-static void pt__mark_as_allocated(PointReq *r) { /* AX->X */
+static void pt_mark_as_allocated(PointReq *r) { /* AX->X */
   /* Sets statedet fields for Allocated */
   r->deadline= ~(PtSlot)0;
   r->motions[0].i=0;
 }
 
-static ErrorCode pt__check(void) {
+static ErrorCode pt_check_plan(void) {
   /* Checks whether we can meet the currently queued commitments */
   int future, conf, resv;
 
@@ -167,23 +243,12 @@ static ErrorCode pt__check(void) {
     future++;
   }
   return 0;
-}
-  
-       ;
-       
-    
-
-
-  for (conf=0;
-       conf < 
-
-    
 }
 
-static ErrorCode pt__enqueue(PointQueue *q, PointReq *r) { /* XA -> X */
+static ErrorCode pt_enqueue(PointQueue *q, PointReq *r) { /* XA -> X */
   ErrorCode ec;              /* ... where X is R or C and corresponds to q */
                              /* or on error,   XA -> A */
-  
+
   if (q->n == PT_MAX_QUEUE) {
     return EC_BufferFull;
   }
@@ -195,13 +260,21 @@ static ErrorCode pt__enqueue(PointQueue *q, PointReq *r) { /* XA -> X */
   q->l[insat]= r;
   q->n++;
 
-  return pt__check();
+  return pt_check();
   /* if this fails, indep machinery calls pt_destroy which dequeues */
 }
 
+/*---------- kind method entrypoints ----------*/
+
 static SomeChange pt_allocate(int alloc_motions) {
   PointReq= *r;
 
+  assert(pt_cdu_charged>=0);
+  if (!alloc_motions)
+    /* we need at least one motion in the table so we can tell
+     *  the difference between the states by looking at motions[0].i */
+    alloc_motions= 1;
+
   r= mmalloc(sizeof(*r) + alloc_motions * sizeof(r->motions[0]));
   r->deadline= ~(PtSlot)0;
   r->n_motions= alloc_motions;
@@ -209,69 +282,194 @@ static SomeChange pt_allocate(int alloc_motions) {
   return (SomeChange*)r;
 }
 
-static ErrorCode pt_reserve(SomeChange *chg, Segment *move, int maxdelay_ms) {
+static ErrorCode point_reserve(SomeChange *chg, Segment *move,
+                              int maxdelay_ms) {
   PointReq *r= (PointReq*)chg;
   r->deadline= pt_reldeadline(maxdelay_ms);
-  if (!r->deadline) { pt__mark_as_allocated(r); return EC_Points; }
+  if (!r->deadline) { pt_mark_as_allocated(r); return EC_Points; }
   return pt_queue_add(&pt_reserved, r);
 }
 
-static ErrorCode pt_request(SomeChange *chg, Segment *move,
-                           int n_motions, const Motion *motions,
-                           int maxdelay_ms) {
-                                           /* [AR]->C; on error: [AR]->X */
+static ErrorCode point_confirm(SomeChange *chg, Segment *move,
+                              int n_motions, const Motion *motions,
+                              int maxdelay_ms) {
   PointReq *r= (PointReq*)chg;
   PtSlot newdeadline;
   int allow_failure;
 
+  /* If the segment is moving, these motions are already based on the
+   * actual physical position which is stored in the existing request.
+   * So we try removing the existing request from the queue and put
+   * it back if it doesn't work.
+   */
+   
   assert(n_motions <= r->n_motions);
   newdeadline= pt_reldeadline(maxdelay_ms) + cslot;
   allow_failure= newdeadline < r->deadline;
 
-  /* state [AR] */
-  pt__dequeue(r);
-  /* state [AR]A */
-  assert(n_motions>0 && motions[0].i);
+  /* state A or R */
+  pt_dequeue(r);
+                                       /* states of existing: */
+  PointReq *existing= move->moving;        /* U or C */
+  if (existing) pt_dequeue(existing);      /* U or CA */
+
+  /* state A or RA */
   memcpy(r->motions, motions, sizeof(r->motions[0])*n_motions);
+  if (!n_motions) motions[0].i= move->i->movfeats;
+  assert(motions[0].i);
   r->n_motions= n_motions;
   r->deadline= newdeadline + pt_cslot;
+
   /* state CA */
-  ec= pt__enqueue(&pt_confirmed, r);
+  ec= pt_enqueue(&pt_confirmed, r);
   assert(allow_failure || !ec);
+
+  if (existing) {                          /* CA */
+    if (ec) { /* state C but bad */
+      pt_dequeue(r); /* state CA */
+      pt_mark_as_allocated(r); /* state A */
+      ErrorCode ec_putback= pt_enqueue(&pt_confirmed, existing);
+      assert(!ec_putback);                 /* C */
+    } else { /* state C and good */
+      free(existing);                      /* U */
+    }
+  }
+  /* either  ec=0   state C                    U
+   *     or  ec!=0  state A                    C
+   *     or  ec!=0  state C but bad            C
+   */
+  
+  if (!ec) pt_check_action();
+
   return ec;
 }
 
+static void pt_destroy(Change *chg) { /* X->XA and then free it */
+  PointReq *r= (PointReq*)chg;
+  pt_dequeue(r);
+  free(r);
+}
+
+/*---------- actually firing points, yay! ----------*/
+
+static void pt_check_action(void) {
+  PicInsn piob;
+  
+  if (!pt_confirmed.n) {
+    toev_stop(&pt_motion_timeout);
+    return;
+  }
+
+  PointReq *r= pt_confirmed.l[0];
+
+  if (r->n_motions) {
+    if (!pt_cdu_charged) {
+      
+
+    Motion *m= &r->motions[--r->n_motions];
+    assert(m->posn < m->i->posns);
+    enco_pic_point(&piob, m->i->boob[m->posn]);
+    serial_transmit(&piob);
+    pt_cdu_charged= 0;
+
+    MovPosComb above_weight= m->i->weight * m->i->posns;
+    MovPosComb above= r->actual / above_weight;
+    MovPosComb below= r->actual % m->i->weight;
+    r->actual= above*above_weight + m->posn*m->i->weight + below;
+  }
+
+  if (!r->n_motions)
+    toev_start(&pt_motion_timeout);
+}
+
+static void pt_motion_done(TimeoutEvent *toev) {
+  assert(pt_confirmed.n);
+  PointReq *r= pt_confirmed.l[0];
+  assert(!r->n_motions);
+  Segment *move= r->h.move;
+  assert(move->moving == r);
+  move->movposcomb= r->actual;
+  move->moving= 0;
+  pt_queue_remove_index(&pt_confirmed,0);
+  r->h.on_done(move, r->h.u);
+  free(r);
+
+  pt_check_action();
+}
+
 /*---------- entrypoints from rest of program ----------*/
 
+static void points_all_abandon(void) {
+  int i;
+
+  assert(!pt_reserved.n);
+
+  for (i=0; i<pt_confirmed.n; i++) {
+    PointReq *r= pt_confirmed.l[i];
+    Segment *move= r->h.move;
+    assert(move->moving == (PointReq*)r);
+    move->moving= 0;
+    move->movposcomb= r->h.actual;
+    free(r);
+  }
+  pt_confirmed.n= 0;
+  pt_cdu_charged= -1;
+  toev_stop(&pt_motion_timeout);
+}
+
 static void points_turning_on(void) {
   pt_cdu_charged= 0;
+  pt_motion_timeout.duration= POINT_MOVEMENT;
+  pt_motion_timeout.callback= pt_motion_done;
+  assert(!pt_motion_timeout.running);
 }
 
 void on_pic_charged(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
+  if (pt_cdu_charged<0) return;
   pt_cdu_charged= 1;
-  if (sta_state <= Sta_Settling) return;
-  fixme check fault arrangements wrt cdu and points etc.
-  fixme do something here
+  if (pt_motion_timeout.running) {
+    toev_stop(&pt_motion_timeout);
+    pt_motion_done(0);
+  }
+  pt_check_action();
 }
 
-
 /*========== method-independent machinery ==========*/
 
-static const MethodInfo methodinfos[]= {
-  { nomove_allocate, nomove_reserve, nomove_request, nomove_cancel }
-  { point_allocate,  point_reserve,  point_request,  point_cancel  }
+static const KindInfo methodinfos[]= {
+  { nomove_allocate, nomove_reserve, nomove_request, nomove_cancel },
+  { point_allocate,  point_reserve,  point_request,  point_cancel  },
+  0
 };
 
+ChangeHeader *mp_allocate(const KindInfo *ki, Segment *move,
+                         int alloc_motions) {
+  assert(sta_state >= Sta_Resolving);
+  chg= (ChangeHeader*)ki->allocate(alloc_motions);
+  chg->ki=        ki;
+  chg->move=      move;
+  return chg;
+}
+
 ErrorCode
-movpos_requestchange(Segment *back, Segment *move, *Segment *fwd,
-                    int maxdelay_ms, MovPosChangeRequest *req_io,
-                    MovPosCallback *on_moving, MovPosCallback *on_done, *u) {
+movpos_change(Segment *back, Segment *move, *Segment *fwd,
+             int maxdelay_ms, MovPosChange chg,
+             MovPosCallback *on_done, *u) {
   const SegmentInfo *movei= move->i;
   SegPosCombInfo *pci;
-  MovPosComb tcomb, bestcomb=0;
+  MovPosComb actual, tcomb, bestcomb=0;
   int tchanges, bestchanges=INT_MAX;
   ErrorCode ec;
 
+  MovFeatKind kind= mfk_none;
+
+  if (move->moving) {
+    kind= move->moving->ki - methodinfos;
+    actual= move->moving->actual;
+  } else {
+    actual= move->movposcomb;
+  }
+
   for (tcomb=0, pci=movei->poscombs;
        tcomb<movei->n_poscombs;
        tcomb++, pci++) {
@@ -285,7 +483,7 @@ movpos_requestchange(Segment *back, Segment *move, *Segment *fwd,
       for (feat=0, feati=movei->movfeats, tchanges=0;
           feat<movei->n_movfeats;
           feat++)
-       if ((tcomb - move->movposcomb) / feati->weight % feati->posns)
+       if ((tcomb - actual) / feati->weight % feati->posns)
          tchanges++;
       if (tchanges > bestchanges)
        continue;
@@ -298,12 +496,11 @@ movpos_requestchange(Segment *back, Segment *move, *Segment *fwd,
 
   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)
+    if ((bestcomb - actual) / feati->weight % feati->posns)
       continue;
     if (kind) {
       if (feati->kind != kind) { ec= EC_MovFeatKindsCombination; goto x; }
@@ -314,37 +511,28 @@ movpos_requestchange(Segment *back, Segment *move, *Segment *fwd,
     n_motions++;
   }
 
-  const MethodInfo *mi= methodinfos[kind];
+  const KindInfo *ki= 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;
+  if (chg) {
+    assert(move == chg->move);
   } else {
-    if (move != (*req_io)->move) { ec= EC_Invalid; return; }
+    chg= mp_allocate(ki,move,n_motions);
   }
+  chg->actual=    actual;
+  chg->on_done=   on_done;
+  chg->u=         u;
 
-  ec= mi->request((SomeChange*)*req_io, move, n_motions, motions, maxdelay_ms);
+  ec= ki->request(chg, move, n_motions, motions, maxdelay_ms);
   if (ec) goto x;
-
   return 0;
 
  x:
-  movpos_cancelchange(*req_io);
+  movpos_unreserve(chg);
   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) {
+movpos_reservechange(Segment *move, int maxdelay_ms, MovPosChange *res_r) {
   MovFeatKind kind= mfk_none;
 
   for (feat=0; feati=movei->movfeats;
@@ -355,15 +543,20 @@ movpos_reservechange(Segment *move, int maxdelay_ms,
       kind= feati->kind;
     }
 
-  const MethodInfo *mi= methodinfos[kind];
-  SomeChange *chg= mi->allocate(movei->n_movfeats);
-  ec= mi->reserve(chg, move, maxdelay_ms);
+  const KindInfo *ki= methodinfos[kind];
+  ChangeHeader *chg= mp_allocate(ki, move, movei->n_movfeats);
+  ec= ki->reserve(chg, move, maxdelay_ms);
   if (ec) goto x;
 
-  *res_r= (ChangeHeader*)chg;
+  *res_r= chg;
   return 0;
 
  x:
-  movpos_cancelchange((ChangeHeader*)chg);
+  movpos_unreserve(chg);
   return ec;
 }
+
+void movpos_unreserve(MovPosChange *res) {
+  if (!res) return;
+  req->ki->destroy(req);
+}