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 prepare() */
47 MovPosChange *indep; /* PQ indep after prepare() */
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, /* 0->P; err: 0->0; 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); /* I */
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 #define EVAL_MAX_METHODS 2
693 #define EVAL_MAX_MOTIONS 2
695 static ErrorCode evaluate_target(Segment *move, MovPosComb target,
696 MovPosComb startpoint,
697 int ms, int confirming,
698 MovPosChange *indep_r /* 0 ok */,
699 int *cost_r /* 0 ok */) {
701 static Method *meths[EVAL_MAX_METHODS];
702 static int n_motions[EVAL_MAX_METHODS];
703 static Motion meths[EVAL_MAX_METHODS][EVAL_MAX_MOTIONS];
705 const SegmentInfo *movei= move->i;
707 const MovFeatInfo *feati;
709 MovPosChange *indep=0;
711 DPRINTF(movpos,eval, "%s/%s <-%s", move->i->pname,
712 movpos_pname(move,target), movpos_pname(move,startpoint));
714 if (!SOMEP(startpoint)) {
715 startpoint= movpos_poscomb_actual(move);
716 fixme actual plumbing etc;
717 DPRINTF(movpos,eval, " actual <-%s\n",
718 movpos_pname(move,startpoint));
723 for (feat=0, feati=movei->movfeats, tchanges=0, kind= mfk_none;
724 feat<movei->n_movfeats;
726 if (!change_needed(feati,startpoint,target)) continue;
727 MovPosComb posn= target / feati->weight % feati->posns;
728 Method *meth= methods[kind];
731 for (methi=0; methi<n_meths; methi++)
732 if (meths[methi] == meth) goto found_method;
733 /* need a new method */
735 if (methi >= EVAL_MAX_METHODS) return EC_MovFeatTooManyMethods;
738 DPRINTF(movpos,eval, " meths[%d]=%s", methi,meth->pname);
741 int motioni= ++n_motions[methi];
742 if (motioni >= EVAL_MAX_MOTIONS) return EC_MovFeatTooManyMotions;
743 DPRINTF(movpos,eval, " motion[%d][%d]=%s%d",
744 methi,motioni,feati->pname,posn);
745 motions[methi][motioni].i= feati;
746 motions[methi][motioni].posn= posn;
750 DPRINTF(movpos,eval, " alloc");
751 indep= mmalloc(sizeof(*indep) + sizeof(Change*) * n_meths);
752 memset(indep->changes, 0, sizeof(Change*) * n_meths);
754 indep->start= fixme startpoint;
755 indep->actual= fixme startbfixpoint;
757 DPRINTF(movpos,eval, "\n");
761 for (int changei=0; changei<n_meths; changei++) {
762 Method *meth= meths[changei];
764 ec= meth->prepare(meth,move,
765 n_motions[changei],motions[changei],
767 indep ? &indep->changes[changei] : 0,
771 Change *chg= indep->changes[changei];
775 totalcost += thiscost;
778 if (indep_r) *indep_r= indep;
779 if (cost_r) *cost_r= totalcost;
780 DPRINTF(movpos,eval, "%s/%s ok cost=%d\n", move->i->pname,
781 movpos_pname(move,target), totalcost);
785 DPRINTF(movpos,eval, "%s/%s abandon %s\n", move->i->pname,
786 movpos_pname(move,target), totalcost, ec2str(ec));
787 indep_dispose(indep);
792 indep_swap(MovPosChange *remv, MovPosChange *inst) {
793 /* does consider and check */
794 assert(inst->n_changes <= 32);
795 assert(remv->n_changes <= 32);
796 uint32_t inst_done, remv_done;
797 int inst2remv[inst->n_changes]; /* valid only if inst_done; -ve => none */
801 for (ii=0; ii<inst->n_changes; ii++) {
802 Method *meth= inst->changes[ii].meth;
803 for (jj=remv->n_changes-1; jj>=0; jj++)
804 if (remv->changes[jj].meth == meth) break;
805 ec= meth->consider(meth,
806 jj>=0 ? remv->changes[jj] : 0,
810 inst_done |= (1UL << ii);
812 if (jj>=0) remv_done |= (1UL << jj);
814 ec= meth->check(meth);
817 for (jj=0; jj<remv->n_changes; jj++) {
818 if (remv_done & (1UL << jj)) continue;
819 ec= meth->consider(meth, remv->changes[jj], 0);
821 ec= meth->check(meth);
823 /* remv_done |= (1UL << jj);
824 not needed because we never roll back from here */
829 for (ii=0; ii<inst->n_changes; ii++) {
830 if (!(inst_done & (1UL << ii))) continue;
831 Method *meth= inst->changes[ii].meth;
833 ec= meth->consider(meth,
835 jj>=0 ? remv->changes[jj] : 0);
837 ec= meth->check(meth);
840 /* we do not need to unwind methods for which we are only removing
841 * since we never roll back after starting those */
845 static void indep_execute(void) {
846 for (Method **methwalk= methods;
853 static void indep_dispose(MovPosChange *indep) {
856 for (int changei=0; changei<indep->n_changes; changei++) {
857 Change *chg= indep->changes[changei];
858 Method *meth= chg->meth;
860 meth->dispose(meth, chg);
866 movpos_reserve(Segment *move, int maxdelay_ms, MovPosChange **res_r,
867 MovPosComb target, MovPosComb startpoint /*as for findcomb*/) {
869 MovPosChange *indep= 0;
871 DPRINTF(movpos,reserve, "%s/%s maxdelay=%dms startpoint=%s\n",
872 move->i->pname, movpos_pname(move,target),
873 maxdelay_ms, movpos_pname(move,startpoint));
875 ec= evaluate_target(move,target, startpoint,
880 ec= indep_consider(0, indep);
887 indep_dispose(indep);
892 static int change_needed(const MovFeatInfo *feati,
893 MovPosComb startpoint, MovPosComb target) {
896 (target - startpoint) / feati->weight % feati->posns;
897 DPRINTF(movpos,changeneeded, "%s:%s(%d*%d) %d..%d => %d\n",
898 methods[feati->kind]->pname, feati->pname,
899 feati->posns, feati->weight,
900 startpoint, target, r);
904 ErrorCode movpos_findcomb_bysegs(Segment *back, Segment *move, Segment *fwd,
905 MovPosComb startpoint, MovPosComb *chosen_r) {
906 const SegmentInfo *movei= move->i;
907 MovPosComb tcomb, bestcomb=-1;
908 int tcost, bestcost=INT_MAX;
909 const SegPosCombInfo *pci;
911 for (tcomb=0, pci=movei->poscombs;
912 tcomb<movei->n_poscombs;
914 Segment *tback= &segments[pci->link[1].next];
915 Segment *tfwd= &segments[pci->link[0].next];
916 if (back && !(back==tback || back==tfwd)) continue;
917 if (fwd && !(fwd ==tback || fwd ==tfwd)) continue;
919 /* we have to search for the one which is least effort */
920 ec= evaluate_target(move,tcomb,startpoint, -1,0, 0,&tcost);
923 if (tcost >= bestcost) /* prefer low-numbered movposcombs */
929 if (chosen_r) *chosen_r= bestcomb;
931 bestcost==INT_MAX ? EC_MovFeatRouteNotFound :
938 ErrorCode movpos_change(Segment *move, MovPosComb target,
939 int maxdelay_ms, MovPosChange *chg) {
940 const SegmentInfo *movei= move->i;
941 const MovFeatInfo *feati;
945 MovFeatKind kind= mfk_none;
948 actual= move->movposcomb;
949 assert(!move->motion);
951 kind= move->motion->meth->kind;
952 actual= move->motion->actual;
955 DPRINTF(movpos,change, "%s/%s maxdelay=%dms actual=%s\n",
956 move->i->pname, movpos_pname(move,target),
957 maxdelay_ms, movpos_pname(move, actual));
958 if (chg) DPRINTF(movpos,change, " chg=%s:%s/%s\n",
959 chg->meth->pname, chg->move->i->pname,
960 movpos_pname(chg->move, chg->intent));
962 { /* provide horizon for visibility of motions[] */
964 Motion motions[movei->n_movfeats];
966 there was code here to fill in motions
968 Method *meth= methods[kind];
971 if (chg->meth != meth ||
973 chg->intent != target)
974 return EC_MovFeatReservationInapplicable;
976 chg= mp_allocate(meth,move,n_motions,target);
980 DPRINTF(movpos,change, "confirm %s:%d...\n",
981 meth->pname, n_motions);
982 ec= meth->confirm(meth, chg, move, n_motions, motions, maxdelay_ms);
983 DPRINTF(movpos,change, "confirm => %s\n",errorcodelist[ec]);
989 movpos_unreserve(chg);
993 void movpos_unreserve(MovPosChange *res) {
995 DPRINTF(movpos,unreserve, "%s:%s/%s\n",
996 res->meth->pname, res->move->i->pname,
997 movpos_pname(res->move, res->intent));
998 res->meth->destroy(res->meth, res);
1001 MovPosComb movpos_poscomb_actual(Segment *seg) {
1002 return seg->moving ? seg->motion->actual : seg->movposcomb;
1005 MovPosComb movpos_change_intent(MovPosChange *chg) {
1009 void motions_all_abandon(void) {
1011 for (meth=methods; *meth; meth++)
1012 (*meth)->all_abandon(*meth);
1021 STUFF BEYOND HERE IS FUNCTIONALITY WHICH NEEDS MOVING TO INDEP
1022 AND/OR CHECKING THAT WE STILL HAVE IT
1025 static ErrorCode fsq_confirm(Method *mm, Change *chg, Segment *move,
1026 int n_motions, const Motion *motions,
1028 FsqMethod *m= (void*)mm;
1029 FsqReq *r= (FsqReq*)chg;
1030 FsqSlotSigned reldeadline;
1031 int allow_failure, DP;
1034 DPRINTF1(movpos,fsq, "%s confirm %s n=%d maxdelay=%dms",
1035 m->m.pname, move->i->pname, n_motions, maxdelay_ms);
1037 assert(!r->motions[0].i); /* no confirming things already confirmed */
1038 if (r->deadline==FSQDN)
1039 DPRINTF2(" (alloc'd: %d)\n", r->n_motions);
1041 DPRINTF2(" (res: %s/%s[%d@t+%d])\n",
1042 r->h.move->i->pname, movpos_pname(r->h.move, r->h.intent),
1043 r->n_motions, r->deadline);
1045 /* If the segment is moving, these motions are already based on the
1046 * actual physical position which is stored in the existing request.
1047 * So we try removing the existing request from the queue and put
1048 * it back if it doesn't work.
1051 if (n_motions > r->n_motions)
1052 return EC_MovFeatReservationInapplicable;
1053 assert(n_motions <= r->n_motions);
1054 if (maxdelay_ms == -1) {
1055 reldeadline= r->deadline;
1056 if (reldeadline==FSQDN)
1057 reldeadline= fsq_maxdelay_reldeadline(m, -1, n_motions);
1059 reldeadline= fsq_maxdelay_reldeadline(m, maxdelay_ms, n_motions);
1061 allow_failure= reldeadline < (FsqSlotSigned)r->deadline;
1062 DPRINTF(movpos,fsq, "%s reldeadline=[%d@t+%d] allow_failure=%d\n",
1063 m->m.pname, n_motions, reldeadline, allow_failure);
1067 /* states of existing: */
1069 move->moving ? (FsqReq*)move->motion : 0; /* U or C */
1072 "%s existing %s n=%d deadline=t+%d\n",
1074 existing->h.move->i->pname,
1075 existing->n_motions,
1076 existing->deadline - m->f.cslot);
1077 fsq_dequeue(m, existing); /* U or CA */
1081 memcpy(r->motions, motions, sizeof(r->motions[0])*n_motions);
1082 if (!n_motions) r->motions[0].i= move->i->movfeats;
1083 assert(r->motions[0].i);
1084 r->n_motions= n_motions;
1085 r->deadline= reldeadline + m->f.cslot;
1087 if (n_motions == move->i->n_movfeats)
1090 r->actual= chg->actual;
1091 assert(r->actual >= 0);
1094 ec= fsq_enqueue(m, &m->f.confirmed, r);
1095 DPRINTF(movpos,fsq, "%s fsq_enqueue=%s\n", m->m.pname, ec2str(ec));
1096 assert(allow_failure || !ec);
1098 if (existing) { /* CA */
1099 if (ec) { /* state C but bad */
1100 fsq_dequeue(m,r); /* state CA */
1101 fsq_mark_as_allocated(r); /* state A */
1102 ErrorCode ec_putback= fsq_enqueue(m,&m->f.confirmed, existing);
1103 assert(!ec_putback); /* C */
1104 } else { /* state C and good */
1105 free(existing); /* U */
1108 /* either ec=0 state C U
1109 * or ec!=0 state A C
1110 * or ec!=0 state C but bad C
1117 move->movposcomb= -1;
1119 fsq_check_action(m);
1125 r->actual= movposcomb_update_feature(r->actual,mo->i,mo->posn);
1126 if (r->h.actual >= 0 || !r->n_motions)
1127 r->h.actual= r->actual;
1128 ouposn_moving(&r->h);
1133 /* look for something to report
1134 * we can get things here other than from the above
1135 * eg if we are asked to move the
1137 Segment *move= r->h.move;
1138 assert(move->moving && move->motion == (Change*)r);
1139 fsq_mark_as_allocated(r); /* now state A aka Done */
1140 motion_done(move,r->h.actual);
1143 /*---------- entrypoints from rest of program ----------*/
1145 static void fsq_all_abandon(Method *mm) {
1146 FsqMethod *m= (void*)mm;
1149 assert(!m->f.reserved.n);
1151 for (i=0; i<m->f.confirmed.n; i++) {
1153 FsqReq *r= m->f.confirmed.l[i];
1154 Segment *move= r->h.move;
1155 assert(move->motion == (Change*)r);
1156 motion_done(move,r->h.actual);
1159 m->f.confirmed.n= 0;
1162 in points_all_abandon
1163 fsq_all_abandon(mm);
1168 * seg->moving and ->motion is in one of the states UC
1170 static Change *mp_allocate(Method *meth, Segment *move,
1171 int alloc_motions, MovPosComb target) {
1172 assert(sta_state >= Sta_Resolving || sta_state == Sta_Manual);
1173 Change *chg= meth->allocate(meth, alloc_motions);
1176 chg->intent= target;