2 * Handling of points and other moveable features.
7 /*========== declarations ==========*/
14 typedef struct Method Method;
16 /* Kind-independent code is responsible for determining
17 * the method, doing a bit of cleanup, and adjusting the flow
18 * slightly. Per-kind code does the actual work and is mostly in
19 * charge - it is also responsible for updating seg->moving and ->motion.
22 * The following states exist for each Method
23 * I Initialising corresponds to global states other than Sta_Run
24 * T Tentative changes have been made but may yet be undone
25 * Y Yes proposed changes have been checked and are OK
26 * E Executing the method is executing
28 * The following states exist for each Change
29 * at points when control flow passes between kind and indep:
30 * U Unallocated no memory allocated (Change does not exist)
31 * P Prepared memory allocation done, basics filled in
32 * Q Queued reservation or confirmation successful
33 * D Done motion is complete and callback is being entered
34 * G Garbage motion is complete and callback is being exited
40 * No Changes remain Prepared while the Method is Executing.
43 typedef struct Change Change;
45 struct Change { /* valid in: filled in by and when: */
46 Method *meth; /* PQ indep after allocate() */
47 MovPosChange *indep; /* PQ indep after allocate() */
48 /* kind-specific data follows */ /* varies kind-specific code, varies */
50 /* `actual' contains the kind's public opinion about the physical
51 * state. It is initialised by indep (just before confirm) from
52 * move->motion->actual or move->movposcomb as the case may be. It
53 * should be updated by the kind, since it is used by indep for
54 * calculating the number and identities of the features which may
55 * need to change when a new move request is intended to replace an
56 * existing one - ie, the contents of the motions[] provided to a
57 * subsequent confirm(). So while a change is Confirmed, the
58 * physical state is recorded only in the relevant MovPosChange, and not
59 * in the segment's movposcomb. Once a change goes to Confirmed,
60 * the indep code never untangles it so the kind can manage the
61 * proper transition. */
66 ErrorCode (*prepare)(Method *m, /* TYE->T */
68 int n_motions, const Motion *motions,
69 int ms, int confirming,
70 Change *chg_r, /* U->P; err: U->U; may be 0 */
71 int *cost_r /* may be 0 */);
72 ErrorCode (*consider)(Method *m, /* TYE->T */
73 Change *remove, /* Q->P; err: Q->Q */
74 Change *install); /* P->Q; err: P->P */
75 /* error: ET->T, no change to Changes */
76 void (*dispose)(Method *m, /* TY->TY */
79 ErrorCode (*check)(Method *m); /* TYE->Y; err: TYE->TYE */
80 void (*execute)(Method *m); /* EY->E */
81 void (*all_abandon)(Method *m);
84 const char *movpos_pname(Segment *move, MovPosComb poscomb) {
85 return poscomb<0 ? "?" : move->i->poscombs[poscomb].pname;
88 static void ouposn_moving(Change *chg) {
89 Segment *move= chg->move;
90 ouprintf("movpos %s position %s moving\n",
91 move->i->pname, movpos_pname(move, chg->actual));
94 MovPosComb movposcomb_update_feature(MovPosComb startpoint,
95 const MovFeatInfo *mfi,
97 MovPosComb above_weight= mfi->weight * mfi->posns;
98 MovPosComb above= startpoint / above_weight;
99 MovPosComb below= startpoint % mfi->weight;
100 return above*above_weight + featpos*mfi->weight + below;
103 static void ignore_all_abandon(Method *m) { }
105 /*========== points and other fixed timeslot movfeats ==========*/
108 * We maintain two queues, one for reserved one for actually confirmed
109 * requests where we know what we're doing.
111 * We divide time into discrete slots, numbered with clock arithmetic.
113 * cslot cslot+1 cslot+2
115 * currently next in after
118 * We increment cslot when we consider the movfeat to move;
119 * for points and relays this is when we issue the command to the PIC.
120 * In a request, the deadline represents the latest allowable value
121 * of cslot just before that increment.
124 typedef unsigned FsqSlot;
125 typedef int FsqSlotSigned;
127 /* We think there are three states: Allocated, Reserved and Confirmed.
128 * (plus of course Unallocated where we don't have a request at all).
129 * These correspond to the indep code as follows:
131 * indep state pt state queues checked and plan viable
132 * Unallocated n/a yes
133 * Allocated Allocated yes
134 * Reserved Reserved yes
135 * Confirmed Confirmed yes
138 * Erroneous exists only after a failed reserve() or confirm() so it's
139 * not that confusing to have this slightly malleable terminology.
142 #define FSQDN (~(FsqSlot)0)
144 typedef struct { /* PR QR PC QC */
145 /* in queue? absent reserved absent confirmed */
147 FsqSlot deadline; /* relative relative absolute absolute */
148 MovPosComb actual; /* undef undef see below */
149 int n_motions; /* 1 1 alloc'd num undone */
151 /* [0].i: 0 0 non-0 non-0 */
152 /* .posn: undef undef defined defined */
154 /* We can determine the the state by looking at the two
155 * `statedet' fields, marked <- above.
156 * There are also intermediate states where the req's
157 * statedet fields do not agree with the queue it's on.
158 * We write these as, for example,
159 * AR to mean statedet says Allocated, but queued on fsq_reserved
160 * A? to mean statedet says Allocated, but may be queued
161 * etc. They are only allowed while we are in a fsq_... method function.
163 /* FsqReq.actual is subtly differnet to MovPosChange.actual,
165 * in MovPosChange in FsqReq
166 * Position unknown -1 0
167 * Position partly known -1 unknown feats are 0
168 * Position completely known exact exact
170 * The partial knowledge positions can only occur in requests that
171 * are confirmed with as many motions as features, so we know that
172 * if we complete a request we know that we can copy actual out
175 * If we abandon a half-done change to a multi-feat segment
176 * we lose the partial knowledge.
179 #define FSQ_MAX_QUEUE 15
183 FsqReq *l[FSQ_MAX_QUEUE];
186 typedef struct FsqMethod FsqMethod;
189 /* set by fsq's client before fsq_init */
191 void (*move)(FsqMethod *m, const MovFeatInfo *mfi, int movfeatposn);
193 int ready; /* >0 means ready; set to 0 by fsq just before move */
194 /* fsq's client must arrange that these start out at all-bits-zero */
196 FsqQueue confirmed, reserved;
202 /* client may put things here */
205 static void fsq_check_action(FsqMethod *m);
206 static ErrorCode fsq_check_plan(FsqMethod *m);
208 static FsqSlotSigned fsq_maxdelay_reldeadline(FsqMethod *m,
209 int maxdelay_ms, int n_motions) {
210 if (maxdelay_ms==-1) return FSQ_MAX_QUEUE*16;
211 return (maxdelay_ms - m->f.lag_ms) / m->f.slot_ms - n_motions;
214 static void fsq_queue_remove_index(FsqQueue *q, int index) {
216 memmove(&q->l[index], &q->l[index+1], sizeof(q->l[0]) * (q->n - index));
219 static int fsq_req_compar_approx(const void *av, const void *bv) {
220 FsqReq *const *a= av;
221 FsqReq *const *b= av;
222 FsqSlotSigned dldiff= (*b)->deadline - (*a)->deadline;
226 static void fsq_queue_remove_item(FsqQueue *q, FsqReq *r) {
229 entry= bsearch(r, q->l, q->n, sizeof(q->l[0]), fsq_req_compar_approx);
232 #define SEARCH_CHECK do{ \
233 if (q->l[i] == r) goto found; \
234 if (q->l[i]->deadline != r->deadline) break; \
236 for(i= entry - q->l; i >= 0; i--) SEARCH_CHECK;
237 for(i= entry - q->l + 1; i < q->n; i++) SEARCH_CHECK;
241 fsq_queue_remove_index(q, i);
244 static FsqQueue *fsq_item_queue(FsqMethod *m, FsqReq *r) {
245 return r->motions[0].i ? &m->f.confirmed : &m->f.reserved;
249 whichwhen= wh##when, \
252 static ErrorCode fsq_check_plan(FsqMethod *m) {
253 /* Checks whether we can meet the currently queued commitments */
254 /* if this fails, indep machinery calls fsq_prepare to dequeue */
255 int future, conf, resv, whichwhen, DP;
261 DPRINTF1(movpos,fsq, "%s plan", m->m.pname);
263 /* If CDU isn't charged we can't do one right away */
270 FsqReq *confr= conf < m->f.confirmed.n ? m->f.confirmed.l[conf] : 0;
271 FsqReq *resvr= resv < m->f.reserved .n ? m->f.reserved .l[resv] : 0;
272 if (!confr && !resvr) break;
273 DPRINTF2(" %d:",future);
274 int confwhen= confr ? confr->deadline - m->f.cslot : INT_MAX;
275 int resvwhen= resvr ? resvr->deadline : INT_MAX;
276 if (future && resvwhen < confwhen) {
277 WHICH(resv); DPRINTF2("~");
281 future++; DPRINTF2("-");
284 DPRINTF2("%s/%s[%d@t+%d]", whichr->h.move->i->pname,
285 movpos_pname(whichr->h.move, whichr->h.intent),
286 whichr->n_motions, whichwhen);
287 if (future > whichwhen) {
288 DPRINTF2("!...bad\n");
289 return EC_MovFeatTooLate;
291 future += whichr->n_motions;
299 static ErrorCode fsq_queue_insert_item(FsqMethod *m, FsqQueue *q, FsqReq *r) {
302 if (q->n == FSQ_MAX_QUEUE)
303 return EC_BufferFull;
306 insat>0 && (FsqSlotSigned)(r->deadline - q->l[insat-1]->deadline) < 0;
308 q->l[insat]= q->l[insat-1];
313 static void fsq_item_debug(FsqMethod *m, FsqReq *r,
314 const char *pfx, Segment *move) {
315 DPRINTF1(movpos,fsq, "%s%s", pfx, move.pname);
316 if (r->motions[0].i) {
317 for (int i=0, Motion *mo=r->motions; i<r->n_motions; i++, mo++)
318 DPRINTF1(movpos,fsq, "/%s%d", mo->i->pname, (int)mo->posn);
320 DPRINTF1(movpos,fsq, "(%d)", r->n_motions);
324 static ErrorCode fsq_enqueue(FsqMethod *m, FsqReq *r) { /* P->Q; err: P->P */
326 fsq_item_debug(m,r,"enqueue:",r->h.indep.move);
327 return fsq_queue_insert_item(fsq_item_queue(m,r), r);
330 static void fsq_dequeue(FsqMethod *m, FsqReq *r) { /* Q->P */
332 fsq_item_debug(m,r,"dequeue:",r->h.indep.move);
333 fsq_remove_item(fsq_item_queue(m,r), r);
336 /*---------- method entrypoints ----------*/
338 static ErrorCode fsq_prepare(Method *mm, Segment *move,
339 int n_motions, const Motion *motions,
340 int ms, int confirmation,
341 Change *chg_r, int *cost_r) {
342 FsqMethod *m= (void*)mm;
344 assert(n_motions > 0);
346 FsqSlotSigned reldeadline= fsq_maxdelay_reldeadline(m, ms, r->n_motions);
347 if (reldeadline <= 0) return EC_MovFeatTooLate;
350 int alloc_motions= confirmation ? n_motions : 1;
351 /* we need at least one motion in the table so we can tell
352 * the difference between the states by looking at motions[0].i */
353 FsqReq *r= mmalloc(sizeof(*r) + alloc_motions * sizeof(r->motions[0]));
354 r->n_motions= n_motions;
356 r->deadline= reldeadline + m->f.cslot;
357 memcpy(r->motions, motions, sizeof(*r->motions)*motions);
359 r->deadline= reldeadline;
365 *cost_r= n_motions * m->slot_ms;
371 static ErrorCode fsq_consider(Method *mm, Change *remove, Change *install) {
372 FsqMethod *m= (void*)mm;
373 FsqReq *remv= (FsqReq*)remove;
374 FsqReq *inst= (FsqReq*)install;
376 DPRINTF1(movpos,fsq, "%s consider ", m->m.pname);
378 fsq_dequeue(m, remv);
379 ErrorCode ec= fsq_enqueue(m, inst);
381 ErrorCode ec2= fsq_enqueue(m, remv);
384 DPRINTF1(movpos,fsq, " %s\n", ec2str(ec));
388 static ErrorCode fsq_check(Method *mm) {
389 FsqMethod *m= (void*)mm;
390 ErrorCode ec= fsq_check_plan(m);
391 DPRINTF(movpos,fsq, "%s check=%s\n", m->m.pname, ec2str(ec));
395 static void fsq_execute(Method *mm) {
396 FsqMethod *m= (void*)mm;
397 DPRINTF(movpos,fsq, "%s execute\n", m->m.pname);
401 static void fsq_dispose(Method *mm, Change *chg) {
402 FsqMethod *m= (void*)mm;
403 FsqReq *r= (FsqReq*)chg;
407 /*---------- something to do ? ----------*/
409 static void fsq_check_action(FsqMethod *m) {
410 /* client should call this after it sets ready */
413 if (!m->f.confirmed.n) {
414 if (sta_state == Sta_Finalising) resolve_motioncheck();
418 FsqReq *r= m->f.confirmed.l[0];
420 if (r->n_motions && m->f.ready>0) {
421 /* look for something to move */
422 Motion *mo= &r->motions[--r->n_motions];
423 assert(mo->posn < mo->i->posns);
425 m->f.move(m, mo->i, mo->posn);
428 indep_update_feature(&m->m, r->h.indep, mo);
432 fsq_queue_remove_index(&m->f.confirmed, 0);
433 indep_change_done(&m->m, &r->h);
434 m->h.dispose(&m->m, &r->h);
436 ec= fsq_check_plan(m); assert(!ec);
441 /*========== points ==========*/
444 * CDU and point queue states:
447 * ____________ conf'd
448 * / points_ \ ready .n
452 * |from INACTIVE -1 0
453 * |any <=Sta_Settling
456 * ___________ |turning
467 * | |fsq_check_action
468 * | | calls point_move which fires a point
473 #define CDU_RECHARGE 350 /*ms*/
474 #define POINT_MOVEMENT 50 /*ms*/
476 static ErrorCode point_prepare(Method *mm, Segment *move,
477 int n_motions, const Motion *motions,
478 int ms, int confirmation,
479 Change *chg_r, int *cost_r) {
480 FsqMethod *m= (void*)mm;
481 assert(m->f.ready>=0);
482 return fsq_prepare(mm,move, n_motions,motions,
483 ms,confirmation, chg_r,cost_r);
486 static void point_move(FsqMethod *m, const MovFeatInfo *mfi, int posn) {
487 /* actually firing points, yay! */
489 enco_pic_point(&piob, mfi->boob[posn]);
490 serial_transmit(&piob);
493 static void points_all_abandon(Method *mm) {
494 FsqMethod *m= (void*)mm;
498 static FsqMethod points_method;
500 void points_turning_on(void) {
501 FsqMethod *m= &points_method;
504 void on_pic_charged(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
505 FsqMethod *m= &points_method;
506 if (m->f.ready<0) return;
511 static FsqMethod points_method= {
512 { "point", mfk_point,
513 point_prepare, fsq_consider, fsq_dispose,
514 fsq_check, fsq_execute, points_all_abandon },
515 { .lag_ms= POINT_MOVEMENT, .slot_ms= CDU_RECHARGE, .move= point_move }
518 /*========== relays ==========*/
523 * ____________ conf'd
524 * / wagglers_ \ ready .n
529 * |any <=Sta_Settling
532 * ___________ |turning
543 * | |fsq_check_action
544 * | | calls waggle_do which switches a relay
549 static FsqMethod waggle;
551 static void waggle_do(FsqMethod *m, const MovFeatInfo *mfi, int posn) {
552 /* actually setting relays */
554 enco_pic_waggle(&piob, mfi->boob[0], posn);
555 serial_transmit(&piob);
558 static SegmentNum waggle_settle_seg;
559 static int waggle_settle_feat;
561 static void waggle_settle_check(void) {
563 if (waggle_settle_seg >= info_nsegments) return;
565 Segment *seg= &segments[waggle_settle_seg];
566 if (waggle_settle_feat >= seg->i->n_movfeats) {
567 waggle_settle_seg++; waggle_settle_feat=0; continue;
570 const MovFeatInfo *feati= &seg->i->movfeats[waggle_settle_feat];
571 if (feati->kind != mfk_relay) {
572 waggle_settle_feat++; continue;
576 waggle_do(&waggle, feati, (seg->movposcomb / feati->weight) & 1);
577 waggle_settle_feat++;
581 void waggle_startup_manual(void) {
585 void waggle_settle(void) {
586 waggle_settle_seg= 0;
587 waggle_settle_feat= 0;
589 waggle_settle_check();
592 void on_pic_waggled(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
593 if (sta_state == Sta_Settling) {
595 waggle_settle_check();
596 } else if (sta_state >= Sta_Resolving || sta_state == Sta_Manual) {
598 fsq_check_action(&waggle);
603 static FsqMethod waggle= {
604 { "relay", mfk_relay,
605 fsq_prepare, fsq_consider, fsq_dispose,
606 fsq_check, fsq_execute, ignore_all_abandon },
607 { .lag_ms= 5, .slot_ms= 50, .move= waggle_do }
610 /*========== dummy `nomove' kind ==========*/
612 static ErrorCode nomove_prepare(Method *m, Segment *move,
613 int n_motions, const Motion *motions,
614 int ms, int confirming,
615 Change *chg_r, int *cost_r) {
617 *chg= mmalloc(sizeof(Change));
626 static ErrorCode nomove_consider(Method *m, Change *remove, Change *install)
629 static void nomove_dispose(Method *m, Change *chg) { }
630 static ErrorCode nomove_check(Method *m) { return 0; }
631 static ErrorCode nomove_execute(Method *m) {
635 static Method nomove_method= {
637 nomove_prepare, nomove_consider, nomove_dispose,
638 nomove_check, nomove_execute, ignore_all_abandon
641 /*========== method-independent machinery ==========*/
643 struct MovPosChange {
652 static Method *methods[]= {
654 (Method*)&points_method,
659 static void indep_update_feature(Method *m, MovPosChange *indep,
661 if (SOMEP(indep->start))
662 ouprintf("movpos %s feat %s %d %s\n", indep->move->i->pname,
663 mo->i->pname, mo->posn, m.pname);
665 movposcomb_update_feature(indep->actual, mo->i, mo->posn);
668 static void indep_change_done(Method *m, Change *chg) {
669 MovPosComb *indep= chg->indep;
672 for (search=indep->changes; *search; search++)
673 if ((*search) == chg) goto found;
674 assert(!"change in indep");
678 if (indep->n_changes) {
679 *search= indep[n_changes];
686 move->movposcomb= indep->actual;
687 ouprintf("movpos %s position %s stable\n",
688 move->i->pname, movpos_pname(move, move->movposcomb));
692 static ErrorCode evaluate_target(Segment *move, MovPosComb target,
693 MovPosComb startpoint,
695 Change *changes_r[N_METHODS],
697 const SegmentInfo *movei= move->i;
699 const MovFeatInfo *feati;
702 Method *change_methods[N_METHODS];
703 Motion *change_motions[N_METHODS];
706 DPRINTF(movpos,eval, "%s/%s <-%s\n", move->i->pname,
707 movpos_pname(move,target), movpos_pname(move,startpoint));
709 if (!SOMEP(startpoint)) {
710 startpoint= movpos_poscomb_actual(move);
711 DPRINTF(movpos,eval, " actual <-%s\n",
712 movpos_pname(move,startpoint));
717 for (feat=0, feati=movei->movfeats, tchanges=0, kind= mfk_none;
718 feat<movei->n_movfeats;
720 if (!change_needed(feati,startpoint,target)) continue;
721 for (i=0; i<n_changes; i++)
725 if (kind && feati->kind != kind) return -1;
729 if (kind_r) *kind_r= kind;
730 DPRINTF(movpos,eval, "changes=%d kind=%s\n",
731 tchanges, methods[kind]->pname);
738 movpos_reserve(Segment *move, int maxdelay_ms, MovPosChange **res_r,
739 MovPosComb target, MovPosComb startpoint /*as for findcomb*/) {
740 MovFeatKind kind= mfk_none;
745 Change *changes[N_METHODS];
747 DPRINTF(movpos,reserve, "%s/%s maxdelay=%dms startpoint=%s\n",
748 move->i->pname, movpos_pname(move,target),
749 maxdelay_ms, movpos_pname(move,startpoint));
751 evaluate_target(move,target,startpoint, &n_changes,&changes);
754 if (nchanges==-1) return EC_MovFeatKindsCombination;
756 Method *meth= methods[kind];
757 DPRINTF(movpos,reserve, "allocate %s:%d...\n",
758 meth->pname, nchanges);
759 Change *chg= mp_allocate(meth, move, nchanges, target);
760 ec= meth->reserve(meth, chg, move, maxdelay_ms);
761 DPRINTF(movpos,reserve, "reserve => %s\n",errorcodelist[ec]);
768 movpos_unreserve(chg);
778 static Change *mp_allocate(Method *meth, Segment *move,
779 int alloc_motions, MovPosComb target) {
780 assert(sta_state >= Sta_Resolving || sta_state == Sta_Manual);
781 Change *chg= meth->allocate(meth, alloc_motions);
788 static int change_needed(const MovFeatInfo *feati,
789 MovPosComb startpoint, MovPosComb target) {
792 (target - startpoint) / feati->weight % feati->posns;
793 DPRINTF(movpos,changeneeded, "%s:%s(%d*%d) %d..%d => %d\n",
794 methods[feati->kind]->pname, feati->pname,
795 feati->posns, feati->weight,
796 startpoint, target, r);
800 ErrorCode movpos_findcomb_bysegs(Segment *back, Segment *move, Segment *fwd,
801 MovPosComb startpoint, MovPosComb *chosen_r) {
802 const SegmentInfo *movei= move->i;
803 MovPosComb tcomb, bestcomb=-1;
804 int tchanges, bestchanges=INT_MAX;
805 const SegPosCombInfo *pci;
807 for (tcomb=0, pci=movei->poscombs;
808 tcomb<movei->n_poscombs;
810 Segment *tback= &segments[pci->link[1].next];
811 Segment *tfwd= &segments[pci->link[0].next];
812 if (back && !(back==tback || back==tfwd)) continue;
813 if (fwd && !(fwd ==tback || fwd ==tfwd)) continue;
815 /* we have to search for the one which is least effort */
816 tchanges= evaluate_target(move,tcomb,startpoint,0);
822 if (tchanges >= bestchanges) /* prefer low-numbered movposcombs */
826 bestchanges= tchanges;
828 if (chosen_r) *chosen_r= bestcomb;
830 bestchanges==INT_MAX ? EC_MovFeatRouteNotFound :
831 bestchanges==INT_MAX-1 ? EC_MovFeatKindsCombination :
835 ErrorCode movpos_change(Segment *move, MovPosComb target,
836 int maxdelay_ms, MovPosChange *chg) {
837 const SegmentInfo *movei= move->i;
838 const MovFeatInfo *feati;
842 MovFeatKind kind= mfk_none;
845 actual= move->movposcomb;
846 assert(!move->motion);
848 kind= move->motion->meth->kind;
849 actual= move->motion->actual;
852 DPRINTF(movpos,change, "%s/%s maxdelay=%dms actual=%s\n",
853 move->i->pname, movpos_pname(move,target),
854 maxdelay_ms, movpos_pname(move, actual));
855 if (chg) DPRINTF(movpos,change, " chg=%s:%s/%s\n",
856 chg->meth->pname, chg->move->i->pname,
857 movpos_pname(chg->move, chg->intent));
859 { /* provide horizon for visibility of motions[] */
861 Motion motions[movei->n_movfeats];
863 for (feat=0, feati=movei->movfeats;
864 feat<movei->n_movfeats;
866 if (!change_needed(feati,actual,target))
868 MovPosComb posn= target / feati->weight % feati->posns;
870 if (feati->kind != kind) { ec= EC_MovFeatKindsCombination; goto x; }
874 motions[n_motions].i= feati;
875 motions[n_motions].posn= posn;
879 Method *meth= methods[kind];
882 if (chg->meth != meth ||
884 chg->intent != target)
885 return EC_MovFeatReservationInapplicable;
887 chg= mp_allocate(meth,move,n_motions,target);
891 DPRINTF(movpos,change, "confirm %s:%d...\n",
892 meth->pname, n_motions);
893 ec= meth->confirm(meth, chg, move, n_motions, motions, maxdelay_ms);
894 DPRINTF(movpos,change, "confirm => %s\n",errorcodelist[ec]);
900 movpos_unreserve(chg);
904 void movpos_unreserve(MovPosChange *res) {
906 DPRINTF(movpos,unreserve, "%s:%s/%s\n",
907 res->meth->pname, res->move->i->pname,
908 movpos_pname(res->move, res->intent));
909 res->meth->destroy(res->meth, res);
912 MovPosComb movpos_poscomb_actual(Segment *seg) {
913 return seg->moving ? seg->motion->actual : seg->movposcomb;
916 MovPosComb movpos_change_intent(MovPosChange *chg) {
920 void motions_all_abandon(void) {
922 for (meth=methods; *meth; meth++)
923 (*meth)->all_abandon(*meth);
932 STUFF BEYOND HERE IS FUNCTIONALITY WHICH NEEDS MOVING TO INDEP
933 AND/OR CHECKING THAT WE STILL HAVE IT
936 static ErrorCode fsq_confirm(Method *mm, Change *chg, Segment *move,
937 int n_motions, const Motion *motions,
939 FsqMethod *m= (void*)mm;
940 FsqReq *r= (FsqReq*)chg;
941 FsqSlotSigned reldeadline;
942 int allow_failure, DP;
945 DPRINTF1(movpos,fsq, "%s confirm %s n=%d maxdelay=%dms",
946 m->m.pname, move->i->pname, n_motions, maxdelay_ms);
948 assert(!r->motions[0].i); /* no confirming things already confirmed */
949 if (r->deadline==FSQDN)
950 DPRINTF2(" (alloc'd: %d)\n", r->n_motions);
952 DPRINTF2(" (res: %s/%s[%d@t+%d])\n",
953 r->h.move->i->pname, movpos_pname(r->h.move, r->h.intent),
954 r->n_motions, r->deadline);
956 /* If the segment is moving, these motions are already based on the
957 * actual physical position which is stored in the existing request.
958 * So we try removing the existing request from the queue and put
959 * it back if it doesn't work.
962 if (n_motions > r->n_motions)
963 return EC_MovFeatReservationInapplicable;
964 assert(n_motions <= r->n_motions);
965 if (maxdelay_ms == -1) {
966 reldeadline= r->deadline;
967 if (reldeadline==FSQDN)
968 reldeadline= fsq_maxdelay_reldeadline(m, -1, n_motions);
970 reldeadline= fsq_maxdelay_reldeadline(m, maxdelay_ms, n_motions);
972 allow_failure= reldeadline < (FsqSlotSigned)r->deadline;
973 DPRINTF(movpos,fsq, "%s reldeadline=[%d@t+%d] allow_failure=%d\n",
974 m->m.pname, n_motions, reldeadline, allow_failure);
978 /* states of existing: */
980 move->moving ? (FsqReq*)move->motion : 0; /* U or C */
983 "%s existing %s n=%d deadline=t+%d\n",
985 existing->h.move->i->pname,
987 existing->deadline - m->f.cslot);
988 fsq_dequeue(m, existing); /* U or CA */
992 memcpy(r->motions, motions, sizeof(r->motions[0])*n_motions);
993 if (!n_motions) r->motions[0].i= move->i->movfeats;
994 assert(r->motions[0].i);
995 r->n_motions= n_motions;
996 r->deadline= reldeadline + m->f.cslot;
998 if (n_motions == move->i->n_movfeats)
1001 r->actual= chg->actual;
1002 assert(r->actual >= 0);
1005 ec= fsq_enqueue(m, &m->f.confirmed, r);
1006 DPRINTF(movpos,fsq, "%s fsq_enqueue=%s\n", m->m.pname, ec2str(ec));
1007 assert(allow_failure || !ec);
1009 if (existing) { /* CA */
1010 if (ec) { /* state C but bad */
1011 fsq_dequeue(m,r); /* state CA */
1012 fsq_mark_as_allocated(r); /* state A */
1013 ErrorCode ec_putback= fsq_enqueue(m,&m->f.confirmed, existing);
1014 assert(!ec_putback); /* C */
1015 } else { /* state C and good */
1016 free(existing); /* U */
1019 /* either ec=0 state C U
1020 * or ec!=0 state A C
1021 * or ec!=0 state C but bad C
1028 move->movposcomb= -1;
1030 fsq_check_action(m);
1036 r->actual= movposcomb_update_feature(r->actual,mo->i,mo->posn);
1037 if (r->h.actual >= 0 || !r->n_motions)
1038 r->h.actual= r->actual;
1039 ouposn_moving(&r->h);
1044 /* look for something to report
1045 * we can get things here other than from the above
1046 * eg if we are asked to move the
1048 Segment *move= r->h.move;
1049 assert(move->moving && move->motion == (Change*)r);
1050 fsq_mark_as_allocated(r); /* now state A aka Done */
1051 motion_done(move,r->h.actual);
1054 /*---------- entrypoints from rest of program ----------*/
1056 static void fsq_all_abandon(Method *mm) {
1057 FsqMethod *m= (void*)mm;
1060 assert(!m->f.reserved.n);
1062 for (i=0; i<m->f.confirmed.n; i++) {
1064 FsqReq *r= m->f.confirmed.l[i];
1065 Segment *move= r->h.move;
1066 assert(move->motion == (Change*)r);
1067 motion_done(move,r->h.actual);
1070 m->f.confirmed.n= 0;
1073 in points_all_abandon
1074 fsq_all_abandon(mm);
1079 * seg->moving and ->motion is in one of the states UC