2 * Handling of points and other moveable features.
7 /*========== declarations ==========*/
14 typedef struct Method Method;
15 typedef struct Change Change;
18 typedef uint32_t UnkMap;
20 typedef struct MovPosChange {
22 /* everything beyond here is private for indep */
23 MovPosComb actualpos, target;
24 UnkMap actualunk; /* bit per movfeat, set iff actualpos contains dummy 0 */
30 static void method_update_feature(Method*, MovPosChange*, const Motion *mo);
31 /* Called from methods' execution logic when an individual feature
32 * has been moved. This is used by the method-independent code to
33 * compute the correct delta set of movements from the current
34 * actual position, when thinking about new plans. It is also sent
35 * to clients and ultimately used by the UI.
38 static void method_change_done(Method *m, Change *chg);
39 /* Called from methods' execution logic when a whole change
40 * has been done. The method-independent code will take care of
41 * updating move->movposcomb. etc.
43 * REENTRANCY: May be called from within a call to the method's
44 * execute(). Of course cannot legally be called from within
45 * prepare, consider, check or dispose.
49 /* Kind-independent code is responsible for determining
50 * the method, doing a bit of cleanup, and adjusting the flow
51 * slightly. Per-kind code does the actual work and is mostly in
52 * charge - it is also responsible for updating seg->moving and ->motion.
55 * The following states exist for each Method
56 * S Starting corresponds to global states other than Sta_Run
57 * T Tentative changes have been made but may yet be undone
58 * Y Yes proposed changes have been checked and are OK
59 * E Executing the method is executing
61 * The following states exist for each Change
62 * at points when control flow passes between kind and indep:
63 * U Unallocated no memory allocated (Change does not exist)
64 * P Prepared memory allocation done, basics filled in
65 * I Installed reservation or confirmation successful
66 * D Done motion is complete and callback is being entered
67 * G Garbage motion is complete and callback is being exited
73 * No Changes remain Prepared while the Method is Executing.
76 struct Change { /* valid in: filled in by and when: */
77 Method *meth; /* PIDG indep after prepare() */
78 MovPosChange *indep; /* PID indep after prepare() */
79 unsigned installed:1; /* private for indep */
80 /* kind-specific data follows */ /* varies kind-specific code, varies */
86 ErrorCode (*prepare)(Method *m, /* TYE->T */
88 int n_motions, const Motion *motions,
89 int ms, int confirmation,
90 Change **chg_r, /* 0->P; err: 0->0; may be 0 */
91 int *cost_r /* may be 0 */);
92 void (*dispose)(Method *m, /* TY->TY */
95 ErrorCode (*install)(Method *m, /* TYE->T; err: TYE->TYY */
96 Change *inst); /* P->I; err: P->P */
97 /* error: ET->T, no change to Changes */
98 void (*remove)(Method *m, /* TYE->TYY */
99 Change *remove); /* I->P */
100 /* error: ET->T, no change to Changes */
102 ErrorCode (*check)(Method *m); /* TYE->Y; err: TYE->TYE */
103 void (*execute)(Method *m); /* EY->E */
104 void (*all_abandon)(Method *m); /* TYE->S */
106 unsigned needcheck, needexec; /* used by indep to track T/Y/E */
109 /*========== general utility functions ==========*/
111 static UnkMap unkfeatbit(int featix) { return (UnkMap)1 << featix; }
112 static UnkMap unkallfeatbits(int nfeats) { return ~(~(UnkMap)0 << nfeats); }
114 const char *movpos_pname(const Segment *move, MovPosComb poscomb) {
115 return !SOMEP(poscomb) ? "?" : move->i->poscombs[poscomb].pname;
118 static void ouposn_moving(const MovPosChange *indep) {
119 Segment *move= indep->move;
120 ouprintf("movpos %s position %s moving\n",
122 indep->actualunk ? "?" : movpos_pname(move, indep->actualpos));
124 static void ouposn_stable(const Segment *move) {
125 ouprintf("movpos %s position %s stable\n",
126 move->i->pname, movpos_pname(move, move->movposcomb));
128 static void ouposn_feat(const Segment *move, const MovFeatInfo *feati,
129 MovPosComb posn, const Method *m) {
130 ouprintf("movpos %s feat %s %d %s\n", move->i->pname,
131 feati->pname, posn, m->pname);
134 int movposcomb_feature_posn(const MovFeatInfo *feati, MovPosComb comb) {
135 /* Returns position of individual feature. */
136 return (comb / feati->weight) % feati->posns;
139 MovPosComb movposcomb_feature_update(const MovFeatInfo *mfi,
140 MovPosComb startpoint, int featpos) {
141 MovPosComb above_weight= mfi->weight * mfi->posns;
142 MovPosComb above= startpoint / above_weight;
143 MovPosComb below= startpoint % mfi->weight;
144 return above*above_weight + featpos*mfi->weight + below;
147 static void ignore_all_abandon(Method *m) { }
149 /*========== points and other fixed timeslot movfeats ==========*/
152 * We maintain two queues, one for reserved one for actually confirmed
153 * requests where we know what we're doing.
155 * We divide time into discrete slots, numbered with clock arithmetic.
157 * cslot cslot+1 cslot+2
159 * currently next in after
162 * We increment cslot when we consider the movfeat to move;
163 * for points and relays this is when we issue the command to the PIC.
164 * In a request, the deadline represents the latest allowable value
165 * of cslot just before that increment.
168 typedef unsigned FsqSlot;
169 typedef int FsqSlotSigned;
171 #define FSQDN (~(FsqSlot)0)
173 typedef struct { /* state Prep Resv Inst Resv Prep Conf Inst Conf */
174 Change h; /* in queue? absent reserved absent confirmed */
175 FsqSlot deadline; /* relative relative absolute absolute */
176 int n_motions; /* 1 1 num undone num undone */
177 Motion motions[]; /* [0].i: 0 0 non-0 non-0 */
178 /* .posn: undef undef defined defined */
181 #define FSQ_MAX_QUEUE 15
185 FsqReq *l[FSQ_MAX_QUEUE];
188 typedef struct FsqMethod FsqMethod;
191 /* set by fsq's client before fsq_init */
193 void (*move)(FsqMethod *m, const MovFeatInfo *mfi, int movfeatposn);
195 int ready; /* >0 means ready; set to 0 by fsq just before move */
196 /* fsq's client must arrange that these start out at all-bits-zero */
198 FsqQueue confirmed, reserved;
204 /* client may put things here */
207 static void fsq_check_action(FsqMethod *m);
208 static ErrorCode fsq_check_plan(FsqMethod *m);
210 static FsqSlotSigned fsq_maxdelay_reldeadline(FsqMethod *m,
211 int maxdelay_ms, int n_motions) {
212 if (maxdelay_ms==-1) return FSQ_MAX_QUEUE*16;
213 return (maxdelay_ms - m->f.lag_ms) / m->f.slot_ms - n_motions;
216 static void fsq_queue_remove_index(FsqQueue *q, int index) {
218 memmove(&q->l[index], &q->l[index+1], sizeof(q->l[0]) * (q->n - index));
221 static int fsq_req_compar_approx(const void *av, const void *bv) {
222 FsqReq *const *a= av;
223 FsqReq *const *b= av;
224 FsqSlotSigned dldiff= (*b)->deadline - (*a)->deadline;
228 static void fsq_queue_remove_item(FsqQueue *q, FsqReq *r) {
231 entry= bsearch(r, q->l, q->n, sizeof(q->l[0]), fsq_req_compar_approx);
234 #define SEARCH_CHECK do{ \
235 if (q->l[i] == r) goto found; \
236 if (q->l[i]->deadline != r->deadline) break; \
238 for(i= entry - q->l; i >= 0; i--) SEARCH_CHECK;
239 for(i= entry - q->l + 1; i < q->n; i++) SEARCH_CHECK;
243 fsq_queue_remove_index(q, i);
246 static FsqQueue *fsq_item_queue(FsqMethod *m, FsqReq *r)
247 { return r->motions[0].i ? &m->f.confirmed : &m->f.reserved; }
251 whichwhen= wh##when, \
254 static ErrorCode fsq_check_plan(FsqMethod *m) {
255 /* Checks whether we can meet the currently queued commitments */
256 /* if this fails, indep machinery calls fsq_prepare to dequeue */
257 int future, conf, resv, whichwhen, DP;
263 DPRINTF1(movpos,fsq, "%s plan", m->m.pname);
265 /* If CDU isn't charged we can't do one right away */
272 FsqReq *confr= conf < m->f.confirmed.n ? m->f.confirmed.l[conf] : 0;
273 FsqReq *resvr= resv < m->f.reserved .n ? m->f.reserved .l[resv] : 0;
274 if (!confr && !resvr) break;
275 DPRINTF2(" %d:",future);
276 int confwhen= confr ? confr->deadline - m->f.cslot : INT_MAX;
277 int resvwhen= resvr ? resvr->deadline : INT_MAX;
278 if (future && resvwhen < confwhen) {
279 WHICH(resv); DPRINTF2("~");
283 future++; DPRINTF2("-");
286 DPRINTF2("%s/%s[%d@t+%d]", whichr->h.indep->move->i->pname,
287 movpos_pname(whichr->h.indep->move, whichr->h.indep->target),
288 whichr->n_motions, whichwhen);
289 if (future > whichwhen) {
290 DPRINTF2("!...bad\n");
291 return EC_MovFeatTooLate;
293 future += whichr->n_motions;
301 static ErrorCode fsq_queue_insert_item(FsqMethod *m, FsqQueue *q, FsqReq *r) {
304 if (q->n == FSQ_MAX_QUEUE)
305 return EC_BufferFull;
308 insat>0 && (FsqSlotSigned)(r->deadline - q->l[insat-1]->deadline) < 0;
310 q->l[insat]= q->l[insat-1];
317 static void fsq_item_debug(FsqMethod *m, FsqReq *r, const char *opwhat) {
319 Segment *move= r->h.indep->move;
320 DPRINTF1(movpos,fsq, "%s %s %s", m->m.pname, opwhat, move->i->pname);
321 if (r->motions[0].i) {
324 for (i=0, mo=r->motions; i<r->n_motions; i++, mo++)
325 DPRINTF2("/%s%d", mo->i->pname, (int)mo->posn);
328 DPRINTF2("(%d)\n", r->n_motions);
332 static ErrorCode fsq_enqueue(FsqMethod *m, FsqReq *r) { /* P->I; err: P->P */
334 fsq_item_debug(m,r,"enqueue");
335 return fsq_queue_insert_item(m, fsq_item_queue(m,r), r);
338 static void fsq_dequeue(FsqMethod *m, FsqReq *r) { /* I->P */
340 fsq_item_debug(m,r,"dequeue");
341 fsq_queue_remove_item(fsq_item_queue(m,r), r);
344 /*---------- method entrypoints ----------*/
346 static ErrorCode fsq_prepare(Method *mm, const Segment *move,
347 int n_motions, const Motion *motions,
348 int ms, int confirmation,
349 Change **chg_r, int *cost_r) {
350 FsqMethod *m= (void*)mm;
352 assert(n_motions > 0);
354 FsqSlotSigned reldeadline= fsq_maxdelay_reldeadline(m, ms, n_motions);
355 if (reldeadline <= 0) return EC_MovFeatTooLate;
358 int alloc_motions= confirmation ? n_motions : 1;
359 /* we need at least one motion in the table so we can tell
360 * the difference between the states by looking at motions[0].i */
361 FsqReq *r= mmalloc(sizeof(*r) + alloc_motions * sizeof(r->motions[0]));
362 r->n_motions= n_motions;
364 r->deadline= reldeadline + m->f.cslot;
365 memcpy(r->motions, motions, sizeof(*r->motions)*n_motions);
367 r->deadline= reldeadline;
373 *cost_r= n_motions * m->f.slot_ms;
379 static void fsq_dispose(Method *mm, Change *chg) {
380 FsqReq *r= (FsqReq*)chg;
384 static void fsq_remove(Method *mm, Change *remvchg) {
385 FsqMethod *m= (void*)mm;
386 FsqReq *remv= (FsqReq*)remvchg;
388 fsq_dequeue(m, remv);
391 static ErrorCode fsq_install(Method *mm, Change *instchg) {
392 FsqMethod *m= (void*)mm;
393 FsqReq *inst= (FsqReq*)instchg;
395 return fsq_enqueue(m, inst);
398 static ErrorCode fsq_check(Method *mm) {
399 FsqMethod *m= (void*)mm;
400 ErrorCode ec= fsq_check_plan(m);
404 static void fsq_execute(Method *mm) {
405 FsqMethod *m= (void*)mm;
409 /*---------- something to do ? ----------*/
411 static void fsq_check_action(FsqMethod *m) {
412 /* client should call this after it sets ready */
415 if (!m->f.confirmed.n) {
416 if (sta_state == Sta_Finalising) resolve_motioncheck();
420 FsqReq *r= m->f.confirmed.l[0];
422 if (r->n_motions && m->f.ready>0) {
423 /* look for something to move */
424 Motion *mo= &r->motions[--r->n_motions];
425 assert(mo->posn < mo->i->posns);
427 m->f.move(m, mo->i, mo->posn);
430 method_update_feature(&m->m, r->h.indep, mo);
434 fsq_queue_remove_index(&m->f.confirmed, 0);
435 method_change_done(&m->m, &r->h);
436 m->m.dispose(&m->m, &r->h);
438 ec= fsq_check_plan(m); assert(!ec);
443 /*========== points ==========*/
446 * CDU and point queue states:
449 * ____________ conf'd
450 * / points_ \ ready .n
454 * |from INACTIVE -1 0
455 * |any <=Sta_Settling
458 * ___________ |turning
469 * | |fsq_check_action
470 * | | calls point_move which fires a point
475 #define CDU_RECHARGE 350 /*ms*/
476 #define POINT_MOVEMENT 50 /*ms*/
478 static ErrorCode point_prepare(Method *mm, const Segment *move,
479 int n_motions, const Motion *motions,
480 int ms, int confirmation,
481 Change **chg_r, int *cost_r) {
482 FsqMethod *m= (void*)mm;
483 assert(m->f.ready>=0);
484 return fsq_prepare(mm,move, n_motions,motions,
485 ms,confirmation, chg_r,cost_r);
488 static void point_move(FsqMethod *m, const MovFeatInfo *mfi, int posn) {
489 /* actually firing points, yay! */
491 enco_pic_point(&piob, mfi->boob[posn]);
492 serial_transmit(&piob);
495 static void points_all_abandon(Method *mm) {
496 FsqMethod *m= (void*)mm;
500 static FsqMethod points_method;
502 void points_turning_on(void) {
503 FsqMethod *m= &points_method;
506 void on_pic_charged(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
507 FsqMethod *m= &points_method;
508 if (m->f.ready<0) return;
513 static FsqMethod points_method= {
515 point_prepare, fsq_dispose,
516 fsq_install, fsq_remove,
517 fsq_check, fsq_execute, points_all_abandon },
518 { .lag_ms= POINT_MOVEMENT, .slot_ms= CDU_RECHARGE, .move= point_move }
521 /*========== relays ==========*/
526 * ____________ conf'd
527 * / wagglers_ \ ready .n
532 * |any <=Sta_Settling
535 * ___________ |turning
546 * | |fsq_check_action
547 * | | calls waggle_do which switches a relay
552 static FsqMethod waggle;
554 static void waggle_do(FsqMethod *m, const MovFeatInfo *mfi, int posn) {
555 /* actually setting relays */
557 enco_pic_waggle(&piob, mfi->boob[0], posn);
558 serial_transmit(&piob);
561 static SegmentNum waggle_settle_seg;
562 static int waggle_settle_feat;
564 static void waggle_settle_check(void) {
566 if (waggle_settle_seg >= info_nsegments) return;
568 Segment *seg= &segments[waggle_settle_seg];
569 if (waggle_settle_feat >= seg->i->n_movfeats) {
570 waggle_settle_seg++; waggle_settle_feat=0; continue;
573 const MovFeatInfo *feati= &seg->i->movfeats[waggle_settle_feat];
574 if (feati->kind != mfk_relay) {
575 waggle_settle_feat++; continue;
579 waggle_do(&waggle, feati, (seg->movposcomb / feati->weight) & 1);
580 waggle_settle_feat++;
584 void waggle_startup_manual(void) {
588 void waggle_settle(void) {
589 waggle_settle_seg= 0;
590 waggle_settle_feat= 0;
592 waggle_settle_check();
595 void on_pic_waggled(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
596 if (sta_state == Sta_Settling) {
598 waggle_settle_check();
599 } else if (sta_state >= Sta_Resolving || sta_state == Sta_Manual) {
601 fsq_check_action(&waggle);
606 static FsqMethod waggle= {
608 fsq_prepare, fsq_dispose,
609 fsq_install, fsq_remove,
610 fsq_check, fsq_execute, ignore_all_abandon },
611 { .lag_ms= 5, .slot_ms= 50, .move= waggle_do }
614 /*========== dummy `nomove' kind ==========*/
616 typedef struct NomoveChange {
618 DLIST_NODE(struct NomoveChange) inqueue;
619 int n_motions; /* 0 for reservations */
625 NomoveChange *queuehead; /* contains confirmations only */
628 static ErrorCode nomove_prepare(Method *meth_in, const Segment *move,
629 int n_motions, const Motion *motions,
630 int ms, int confirming,
631 Change **chg_r, int *cost_r) {
635 if (!confirming) n_motions= 0;
636 chg= mmalloc(sizeof(*chg) + sizeof(Motion)*n_motions);
637 chg->n_motions= n_motions;
638 memcpy(chg->motions, motions, sizeof(Motion)*n_motions);
645 static void nomove_dispose(Method *mm, Change *remvchg) {
646 NomoveChange *remv= (void*)remvchg;
650 static ErrorCode nomove_install(Method *mm, Change *instchg) {
651 NomoveMethod *meth= (void*)mm;
652 NomoveChange *inst= (void*)instchg;
654 DLIST1_PREPEND(meth->queuehead, inst, inqueue);
657 static void nomove_remove(Method *mm, Change *remvchg) {
658 NomoveMethod *meth= (void*)mm;
659 NomoveChange *remv= (void*)remvchg;
661 DLIST1_REMOVE(meth->queuehead, remv, inqueue);
664 static ErrorCode nomove_check(Method *mm) { return 0; }
666 static void nomove_execute(Method *mm) {
667 NomoveMethod *meth= (void*)mm;
670 while ((done= meth->queuehead)) {
671 assert(done->n_motions);
673 for (i=0; i<done->n_motions; i++)
674 method_update_feature(&meth->m, done->h.indep, &done->motions[i]);
675 method_change_done(&meth->m, &done->h);
676 DLIST1_REMOVE(meth->queuehead, done, inqueue);
677 nomove_dispose(&meth->m, &done->h);
681 static Method nomove_method= {
683 nomove_prepare, nomove_dispose,
684 nomove_install, nomove_remove,
685 nomove_check, nomove_execute, ignore_all_abandon
688 /*========== method-independent machinery ==========*/
690 #define INDEP_DBG_FMT "<%p:%s/%s[%d]>"
691 #define INDEP_DBG_ARGS(in) (in), \
692 ((in)->move->i->pname), (movpos_pname((in)->move, (in)->target)), \
695 #define INDEP_DPFX_FMT "movpos " INDEP_DBG_FMT " "
696 #define INDEP_DPFX_ARGS(in) INDEP_DBG_ARGS((in))
698 #define METH_DPFX_FMT "%s " INDEP_DBG_FMT " "
699 #define METH_DPFX_ARGS(indep, meth) ((meth).pname), INDEP_DBG_ARGS((indep))
701 static void indep_indep_done(Indep *indep);
703 static Method *methods[]= {
704 [mfk_none] = (Method*)&nomove_method,
705 [mfk_point] = (Method*)&points_method,
706 [mfk_relay] = (Method*)&waggle,
710 /*---------- entrypoints from methods ----------*/
712 static void method_update_feature(Method *m, MovPosChange *indep,
714 int featix= mo->i - indep->move->i->movfeats;
715 assert(featix >= 0 && featix < indep->move->i->n_movfeats);
716 ouposn_feat(indep->move, mo->i, mo->posn, m);
718 movposcomb_feature_update(mo->i, indep->actualpos, mo->posn);
719 indep->actualunk &= ~unkfeatbit(featix);
720 ouposn_moving(indep);
723 static void method_change_done(Method *m, Change *chg) {
724 Indep *indep= chg->indep;
727 DPRINTF(movpos,meth, METH_DPFX_FMT "method_change_done...\n",
728 METH_DPFX_ARGS(indep,*m));
730 for (search=indep->changes; *search; search++)
731 if ((*search) == chg) goto found;
732 assert(!"change in indep");
736 if (indep->n_changes) {
737 *search= indep->changes[indep->n_changes];
741 if (!indep->refcount)
742 indep_indep_done(indep);
745 static void indep_indep_done(Indep *indep) {
747 Segment *move= indep->move;
750 move->movposcomb= indep->target;
755 /*---------- internal core machinery ----------*/
757 static Method *feature_method(const MovFeatInfo *feati) {
758 assert(feati->kind >= 0);
759 assert(feati->kind < ARRAY_SIZE(methods));
760 Method *meth= methods[feati->kind];
765 static int change_needed(int featix, const MovFeatInfo *feati,
766 MovPosComb startpointpos, UnkMap startpointunk,
770 r= (startpointunk & unkfeatbit(featix)) ||
771 (target / feati->weight) % feati->posns -
772 (startpointpos / feati->weight) % feati->posns;
774 if (DEBUGP(movpos,eval))
775 DPRINTFA(" { %s:%s(%d*%d) %d..%d => %d }",
776 feature_method(feati)->pname, feati->pname,
777 feati->posns, feati->weight,
778 startpointpos, target, r);
782 static void indep_dispose(MovPosChange *indep) {
785 DPRINTF(movpos,intern, INDEP_DPFX_FMT "dispose...\n",
786 INDEP_DPFX_ARGS(indep));
789 for (changei=0; changei<indep->n_changes; changei++) {
790 Change *chg= indep->changes[changei];
793 Method *meth= chg->meth;
794 DPRINTF(movpos,meth, METH_DPFX_FMT "dispose...\n",
795 METH_DPFX_ARGS(indep,*meth));
796 meth->dispose(meth, chg);
801 #define EVAL_MAX_METHODS 2
802 #define EVAL_MAX_MOTIONS 2
804 static ErrorCode indep_prepare(Segment *move, MovPosComb target,
805 MovPosComb startpointpos,
806 int ms, int confirming,
807 MovPosChange **indep_r /* 0 ok */,
808 int *cost_r /* 0 ok */) {
810 static Method *meths[EVAL_MAX_METHODS];
811 static int n_motions[EVAL_MAX_METHODS];
812 static Motion motions[EVAL_MAX_METHODS][EVAL_MAX_MOTIONS];
814 const SegmentInfo *movei= move->i;
816 UnkMap startpointunk;
818 MovPosChange *indep=0;
820 DPRINTF1(movpos,eval, "movpos prepare %s/%s <-%s", move->i->pname,
821 movpos_pname(move,target), movpos_pname(move,startpointpos));
823 if (SOMEP(startpointpos)) {
827 startpointpos= move->motion->actualpos;
828 startpointunk= move->motion->actualunk;
829 } else if (SOMEP(move->movposcomb)) {
830 startpointpos= move->movposcomb;
834 startpointunk= unkallfeatbits(move->i->n_movfeats);
837 DPRINTF2(" actual <-%s/", move->i->pname);
838 for (feat=0; feat<movei->n_movfeats; feat++) {
839 const MovFeatInfo *feati= &movei->movfeats[feat];
840 if (startpointunk & unkfeatbit(feat))
841 DPRINTF2("%s?", feati->pname);
843 DPRINTF2("%s%d", feati->pname,
844 startpointpos / feati->weight % feati->posns);
851 for (feat=0; feat<movei->n_movfeats; feat++) {
852 const MovFeatInfo *feati= &movei->movfeats[feat];
853 if (!change_needed(feat,feati,
854 startpointpos,startpointunk,
857 MovPosComb posn= target / feati->weight % feati->posns;
858 Method *meth= feature_method(feati);
861 for (methi=0; methi<n_meths; methi++)
862 if (meths[methi] == meth) goto found_method;
863 /* need a new method */
865 if (methi >= EVAL_MAX_METHODS) {
866 DPRINTF2(" MovFeatTooManyMethods methi=%d\n",methi);
867 return EC_MovFeatTooManyMethods;
871 DPRINTF2(" meths[%d]=%s", methi,meth->pname);
874 int motioni= n_motions[methi]++;
875 if (motioni >= EVAL_MAX_MOTIONS) {
876 DPRINTF2(" MovFeatTooManyMotions motioni=%d\n",motioni);
877 return EC_MovFeatTooManyMotions;
879 DPRINTF2(" motion[%d][%d]=%s%d", methi, motioni, feati->pname,posn);
880 motions[methi][motioni].i= feati;
881 motions[methi][motioni].posn= posn;
886 indep= mmalloc(sizeof(*indep) + sizeof(Change*) * n_meths);
888 indep->actualpos= startpointpos;
889 indep->actualunk= startpointunk;
890 indep->target= target;
891 indep->n_changes= n_meths;
893 memset(indep->changes, 0, sizeof(Change*) * n_meths);
901 for (changei=0; changei<n_meths; changei++) {
902 Method *meth= meths[changei];
908 DPRINTF(movpos,meth, METH_DPFX_FMT "prepare n_motions=%d...\n",
909 METH_DPFX_ARGS(indep,*meth), n_motions[changei]);
911 DPRINTF(movpos,meth, "%s prepare (costing) n_motions=%d...\n",
912 meth->pname, n_motions[changei]);
914 ec= meth->prepare(meth,move,
915 n_motions[changei],motions[changei],
917 indep ? &indep->changes[changei] : 0,
921 Change *chg= indep->changes[changei];
926 totalcost += thiscost;
929 if (indep_r) *indep_r= indep;
930 if (cost_r) *cost_r= totalcost;
933 DPRINTF(movpos,eval, INDEP_DPFX_FMT "prepare cost=%d ok\n",
934 INDEP_DPFX_ARGS(indep), totalcost);
936 DPRINTF(movpos,eval, "movpos prepare %s/%s cost=%d ok\n",
937 move->i->pname, movpos_pname(move,target), totalcost);
941 indep_dispose(indep);
942 DPRINTF(movpos,entry, "movpos prepare %s/%s err=%s\n", move->i->pname,
943 movpos_pname(move,target), ec2str(ec));
947 static void indep_remove(MovPosChange *remv) {
950 DPRINTF(movpos,intern, INDEP_DPFX_FMT "remove...\n",
951 INDEP_DPFX_ARGS(remv));
954 for (i=0; i<remv->n_changes; i++) {
955 Change *chg= remv->changes[i];
956 if (!chg->installed) continue;
957 Method *meth= chg->meth;
960 DPRINTF(movpos,meth, METH_DPFX_FMT "remove...\n",
961 METH_DPFX_ARGS(remv,*meth));
962 meth->remove(meth, chg);
968 indep_install(MovPosChange *inst, int checknow) {
969 /* if this fails, inst may be left partially installed */
972 DPRINTF(movpos,intern, INDEP_DPFX_FMT "install checknow=%d...\n",
973 INDEP_DPFX_ARGS(inst), checknow);
977 for (i=0; i<inst->n_changes; i++) {
978 Change *chg= inst->changes[i];
979 assert(!chg->installed);
980 Method *meth= chg->meth;
983 ec= meth->install(meth, chg);
984 DPRINTF(movpos,meth, METH_DPFX_FMT "install=%s\n",
985 METH_DPFX_ARGS(inst,*meth), ec2str(ec));
991 ec= meth->check(meth);
992 DPRINTF(movpos,meth, METH_DPFX_FMT "check=%s\n",
993 METH_DPFX_ARGS(inst,*meth), ec2str(ec));
1004 static void indep_check_execute(void) {
1005 DPRINTF(movpos,intern, "movpos indep_check_execute\n");
1007 Method **methwalk, *meth;
1008 for (methwalk= methods; (meth= *methwalk); methwalk++) {
1009 if (meth->needcheck) {
1010 ErrorCode ec= meth->check(meth);
1011 DPRINTF(movpos,meth, "%s check=%s\n", meth->pname, ec2str(ec));
1015 if (meth->needexec) {
1017 DPRINTF(movpos,meth, "%s execute...\n", meth->pname);
1018 meth->execute(meth);
1023 /*---------- entrypoints from rest of program ----------*/
1026 movpos_reserve(Segment *move, int maxdelay_ms, MovPosChange **res_r,
1027 MovPosComb target, MovPosComb startpoint /*as for findcomb*/) {
1029 MovPosChange *indep= 0;
1031 DPRINTF(movpos,entry, "movpos reserve %s/%s maxdelay=%dms startpoint=%s\n",
1032 move->i->pname, movpos_pname(move,target),
1033 maxdelay_ms, movpos_pname(move,startpoint));
1035 ec= indep_prepare(move,target, startpoint,
1040 ec= indep_install(indep, 1);
1043 indep_check_execute();
1045 DPRINTF(movpos,entry, "movpos reserve %s/%s ok\n",
1046 move->i->pname, movpos_pname(move,target));
1051 indep_remove(indep);
1052 indep_dispose(indep);
1053 indep_check_execute();
1055 DPRINTF(movpos,entry, "movpos reserve %s/%s err=%s\n",
1056 move->i->pname, movpos_pname(move,target), ec2str(ec));
1060 ErrorCode movpos_findcomb_bysegs(Segment *back, Segment *move, Segment *fwd,
1061 MovPosComb startpoint, MovPosComb *chosen_r) {
1062 const SegmentInfo *movei= move->i;
1063 MovPosComb tcomb, bestcomb=-1;
1064 int tcost, bestcost=INT_MAX;
1065 const SegPosCombInfo *pci;
1067 DPRINTF(movpos,eval, "movpos_findcomb_bysegs %s-%s-%s <-%s\n",
1068 back ? back->i->pname : "*", move->i->pname,
1069 fwd ? fwd ->i->pname : "*", movpos_pname(move, startpoint));
1071 for (tcomb=0, pci=movei->poscombs;
1072 tcomb<movei->n_poscombs;
1074 /* these next assignments may generate segments[-1] but we don't
1075 * care because that won't compare equal to back or fwd */
1076 Segment *tback= &segments[pci->link[1].next];
1077 Segment *tfwd= &segments[pci->link[0].next];
1079 DPRINTF(movpos,intern, "movpos_findcomb_bysegs ... %s : %s-%s-%s\n",
1080 movpos_pname(move, tcomb),
1081 SOMEP(pci->link[1].next) ? tback->i->pname : "#",
1083 SOMEP(pci->link[0].next) ? tfwd->i->pname : "#");
1085 if (back && !(back==tback || back==tfwd)) continue;
1086 if (fwd && !(fwd ==tback || fwd ==tfwd)) continue;
1088 /* we have to search for the one which is least effort */
1089 ErrorCode ec= indep_prepare(move,tcomb,startpoint, -1,0, 0,&tcost);
1092 if (tcost >= bestcost) /* prefer low-numbered movposcombs */
1098 DPRINTF(movpos,entry, "movpos_findcomb_bysegs %s..%s..%s <-%s => %s/%s\n",
1099 back ? back->i->pname : "-", move->i->pname,
1100 fwd ? fwd ->i->pname : "-", movpos_pname(move, startpoint),
1101 move->i->pname, movpos_pname(move,bestcomb));
1103 if (chosen_r) *chosen_r= bestcomb;
1105 bestcost==INT_MAX ? EC_MovFeatRouteNotFound :
1109 ErrorCode movpos_change(Segment *move, MovPosComb target,
1110 int maxdelay_ms, MovPosChange *resv) {
1114 DPRINTF1(movpos,entry, "movpos change %s/%s maxdelay=%dms",
1115 move->i->pname, movpos_pname(move, target), maxdelay_ms);
1116 if (resv) DPRINTF2(" resv=%s/%s",
1117 resv->move->i->pname,
1118 movpos_pname(resv->move, resv->target));
1119 if (move->motion) DPRINTF2(" oldmotion=/%s",
1120 movpos_pname(move, move->motion->target));
1123 MovPosChange *inst= 0;
1125 ec= indep_prepare(move,target, NOTA(MovPosComb),
1131 indep_remove(move->motion);;
1133 ec= indep_install(inst, 1);
1136 indep_dispose(resv);
1137 indep_dispose(move->motion);
1142 inst->refcount++; /* prevents method_change_done from destroying it */
1144 ouposn_moving(inst);
1145 indep_check_execute();
1148 if (!inst->n_changes)
1150 indep_indep_done(inst);
1152 DPRINTF(movpos,entry, "movpos change %s/%s ok\n",
1153 move->i->pname, movpos_pname(move, target));
1158 indep_dispose(inst);
1159 ec= indep_install(move->motion, 0); assert(!ec);
1160 ec= indep_install(resv, 0); assert(!ec);
1161 indep_check_execute();
1163 DPRINTF(movpos,entry, "movpos change %s/%s err=%s\n",
1164 move->i->pname, movpos_pname(move, target), ec2str(ec));
1168 void movpos_unreserve(MovPosChange *resv) {
1170 DPRINTF(movpos,entry, "movpos unreserve %s/%s...\n",
1171 resv->move->i->pname, movpos_pname(resv->move, resv->target));
1173 indep_dispose(resv);
1174 indep_check_execute();
1177 MovPosComb movpos_change_intent(MovPosChange *indep) {
1178 return indep->target;
1181 void motions_all_abandon(void) {
1184 DPRINTF(movpos,entry, "movpos motions_all_abandon...\n");
1186 if (!seg->moving) continue;
1188 MovPosChange *abandon= seg->motion;
1189 indep_remove(abandon);
1190 seg->movposcomb= abandon->actualunk ? NOTA(MovPosComb) : abandon->actualpos;
1193 indep_dispose(abandon);
1195 for (meth=methods; *meth; meth++)
1196 (*meth)->all_abandon(*meth);
1199 void movpos_reportall(void) {
1204 assert(!seg->moving);
1205 if (seg->i->n_poscombs <= 1) continue;
1207 if (SOMEP(seg->movposcomb)) {
1208 for (feat=0; feat<seg->i->n_movfeats; feat++) {
1209 const MovFeatInfo *feati= &seg->i->movfeats[feat];
1210 MovPosComb posn= (seg->movposcomb / feati->weight) % feati->posns;
1211 ouposn_feat(seg, feati, posn, feature_method(feati));