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 * I Installed 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; /* PIDG indep after prepare() */
47 MovPosChange *indep; /* PID indep after prepare() */
48 /* kind-specific data follows */ /* varies kind-specific code, varies */
53 unsigned needcheck, needexec; /* used by indep to track T/Y/E */
55 ErrorCode (*prepare)(Method *m, /* TYE->T */
57 int n_motions, const Motion *motions,
58 int ms, int confirming,
59 Change *chg_r, /* 0->P; err: 0->0; may be 0 */
60 int *cost_r /* may be 0 */);
61 void (*dispose)(Method *m, /* TY->TY */
64 ErrorCode (*install)(Method *m, /* TYE->T; err: TYE->TYY */
65 Change *inst); /* P->I; err: P->P */
66 /* error: ET->T, no change to Changes */
67 void (*remove)(Method *m, /* TYE->TYY */
68 Change *remove); /* I->P */
69 /* error: ET->T, no change to Changes */
71 ErrorCode (*check)(Method *m); /* TYE->Y; err: TYE->TYE */
72 void (*execute)(Method *m); /* EY->E */
73 void (*all_abandon)(Method *m); /* I */
76 /*========== general utility functions ==========*/
78 const char *movpos_pname(Segment *move, MovPosComb poscomb) {
79 return poscomb<0 ? "?" : move->i->poscombs[poscomb].pname;
82 static void ouposn_moving(Change *chg) {
83 Segment *move= chg->move;
84 ouprintf("movpos %s position %s moving\n",
85 move->i->pname, movpos_pname(move, chg->actual));
88 MovPosComb movposcomb_update_feature(MovPosComb startpoint,
89 const MovFeatInfo *mfi,
91 MovPosComb above_weight= mfi->weight * mfi->posns;
92 MovPosComb above= startpoint / above_weight;
93 MovPosComb below= startpoint % mfi->weight;
94 return above*above_weight + featpos*mfi->weight + below;
97 MovPosComb movpos_poscomb_actual(Segment *seg) {
98 return seg->moving ? seg->motion->actual : seg->movposcomb;
101 static void ignore_all_abandon(Method *m) { }
103 /*========== points and other fixed timeslot movfeats ==========*/
106 * We maintain two queues, one for reserved one for actually confirmed
107 * requests where we know what we're doing.
109 * We divide time into discrete slots, numbered with clock arithmetic.
111 * cslot cslot+1 cslot+2
113 * currently next in after
116 * We increment cslot when we consider the movfeat to move;
117 * for points and relays this is when we issue the command to the PIC.
118 * In a request, the deadline represents the latest allowable value
119 * of cslot just before that increment.
122 typedef unsigned FsqSlot;
123 typedef int FsqSlotSigned;
125 /* We think there are three states: Allocated, Reserved and Confirmed.
126 * (plus of course Unallocated where we don't have a request at all).
127 * These correspond to the indep code as follows:
129 * indep state pt state queues checked and plan viable
130 * Unallocated n/a yes
131 * Allocated Allocated yes
132 * Reserved Reserved yes
133 * Confirmed Confirmed yes
136 * Erroneous exists only after a failed reserve() or confirm() so it's
137 * not that confusing to have this slightly malleable terminology.
140 #define FSQDN (~(FsqSlot)0)
142 typedef struct { /* PR QR PC QC */
143 /* in queue? absent reserved absent confirmed */
145 FsqSlot deadline; /* relative relative absolute absolute */
146 int n_motions; /* 1 1 alloc'd num undone */
148 /* [0].i: 0 0 non-0 non-0 */
149 /* .posn: undef undef defined defined */
151 /* We can determine the the state by looking at the two
152 * `statedet' fields, marked <- above.
153 * There are also intermediate states where the req's
154 * statedet fields do not agree with the queue it's on.
155 * We write these as, for example,
156 * AR to mean statedet says Allocated, but queued on fsq_reserved
157 * A? to mean statedet says Allocated, but may be queued
158 * etc. They are only allowed while we are in a fsq_... method function.
161 #define FSQ_MAX_QUEUE 15
165 FsqReq *l[FSQ_MAX_QUEUE];
168 typedef struct FsqMethod FsqMethod;
171 /* set by fsq's client before fsq_init */
173 void (*move)(FsqMethod *m, const MovFeatInfo *mfi, int movfeatposn);
175 int ready; /* >0 means ready; set to 0 by fsq just before move */
176 /* fsq's client must arrange that these start out at all-bits-zero */
178 FsqQueue confirmed, reserved;
184 /* client may put things here */
187 static void fsq_check_action(FsqMethod *m);
188 static ErrorCode fsq_check_plan(FsqMethod *m);
190 static FsqSlotSigned fsq_maxdelay_reldeadline(FsqMethod *m,
191 int maxdelay_ms, int n_motions) {
192 if (maxdelay_ms==-1) return FSQ_MAX_QUEUE*16;
193 return (maxdelay_ms - m->f.lag_ms) / m->f.slot_ms - n_motions;
196 static void fsq_queue_remove_index(FsqQueue *q, int index) {
198 memmove(&q->l[index], &q->l[index+1], sizeof(q->l[0]) * (q->n - index));
201 static int fsq_req_compar_approx(const void *av, const void *bv) {
202 FsqReq *const *a= av;
203 FsqReq *const *b= av;
204 FsqSlotSigned dldiff= (*b)->deadline - (*a)->deadline;
208 static void fsq_queue_remove_item(FsqQueue *q, FsqReq *r) {
211 entry= bsearch(r, q->l, q->n, sizeof(q->l[0]), fsq_req_compar_approx);
214 #define SEARCH_CHECK do{ \
215 if (q->l[i] == r) goto found; \
216 if (q->l[i]->deadline != r->deadline) break; \
218 for(i= entry - q->l; i >= 0; i--) SEARCH_CHECK;
219 for(i= entry - q->l + 1; i < q->n; i++) SEARCH_CHECK;
223 fsq_queue_remove_index(q, i);
226 static FsqQueue *fsq_item_queue(FsqMethod *m, FsqReq *r)
227 { return r->motions[0].i ? &m->f.confirmed : &m->f.reserved; }
231 whichwhen= wh##when, \
234 static ErrorCode fsq_check_plan(FsqMethod *m) {
235 /* Checks whether we can meet the currently queued commitments */
236 /* if this fails, indep machinery calls fsq_prepare to dequeue */
237 int future, conf, resv, whichwhen, DP;
243 DPRINTF1(movpos,fsq, "%s plan", m->m.pname);
245 /* If CDU isn't charged we can't do one right away */
252 FsqReq *confr= conf < m->f.confirmed.n ? m->f.confirmed.l[conf] : 0;
253 FsqReq *resvr= resv < m->f.reserved .n ? m->f.reserved .l[resv] : 0;
254 if (!confr && !resvr) break;
255 DPRINTF2(" %d:",future);
256 int confwhen= confr ? confr->deadline - m->f.cslot : INT_MAX;
257 int resvwhen= resvr ? resvr->deadline : INT_MAX;
258 if (future && resvwhen < confwhen) {
259 WHICH(resv); DPRINTF2("~");
263 future++; DPRINTF2("-");
266 DPRINTF2("%s/%s[%d@t+%d]", whichr->h.move->i->pname,
267 movpos_pname(whichr->h.move, whichr->h.intent),
268 whichr->n_motions, whichwhen);
269 if (future > whichwhen) {
270 DPRINTF2("!...bad\n");
271 return EC_MovFeatTooLate;
273 future += whichr->n_motions;
281 static ErrorCode fsq_queue_insert_item(FsqMethod *m, FsqQueue *q, FsqReq *r) {
284 if (q->n == FSQ_MAX_QUEUE)
285 return EC_BufferFull;
288 insat>0 && (FsqSlotSigned)(r->deadline - q->l[insat-1]->deadline) < 0;
290 q->l[insat]= q->l[insat-1];
295 static void fsq_item_debug(FsqMethod *m, FsqReq *r,
296 const char *pfx, Segment *move) {
297 DPRINTF1(movpos,fsq, "%s%s", pfx, move.pname);
298 if (r->motions[0].i) {
299 for (int i=0, Motion *mo=r->motions; i<r->n_motions; i++, mo++)
300 DPRINTF1(movpos,fsq, "/%s%d", mo->i->pname, (int)mo->posn);
302 DPRINTF1(movpos,fsq, "(%d)", r->n_motions);
306 static ErrorCode fsq_enqueue(FsqMethod *m, FsqReq *r) { /* P->Q; err: P->P */
308 fsq_item_debug(m,r,"enqueue:",r->h.indep.move);
309 return fsq_queue_insert_item(fsq_item_queue(m,r), r);
312 static void fsq_dequeue(FsqMethod *m, FsqReq *r) { /* Q->P */
314 fsq_item_debug(m,r,"dequeue:",r->h.indep.move);
315 fsq_remove_item(fsq_item_queue(m,r), r);
318 /*---------- method entrypoints ----------*/
320 static ErrorCode fsq_prepare(Method *mm, Segment *move,
321 int n_motions, const Motion *motions,
322 int ms, int confirmation,
323 Change *chg_r, int *cost_r) {
324 FsqMethod *m= (void*)mm;
326 assert(n_motions > 0);
328 FsqSlotSigned reldeadline= fsq_maxdelay_reldeadline(m, ms, r->n_motions);
329 if (reldeadline <= 0) return EC_MovFeatTooLate;
332 int alloc_motions= confirmation ? n_motions : 1;
333 /* we need at least one motion in the table so we can tell
334 * the difference between the states by looking at motions[0].i */
335 FsqReq *r= mmalloc(sizeof(*r) + alloc_motions * sizeof(r->motions[0]));
336 r->n_motions= n_motions;
338 r->deadline= reldeadline + m->f.cslot;
339 memcpy(r->motions, motions, sizeof(*r->motions)*motions);
341 r->deadline= reldeadline;
347 *cost_r= n_motions * m->slot_ms;
353 static void fsq_dispose(Method *mm, Change *chg) {
354 FsqMethod *m= (void*)mm;
355 FsqReq *r= (FsqReq*)chg;
359 static void fsq_remove(Method *mm, Change *instchg) {
360 FsqMethod *m= (void*)mm;
361 FsqReq *remv= (FsqReq*)remvchg;
363 fsq_dequeue(m, remv);
366 static ErrorCode fsq_install(Method *mm, Change *instchg) {
367 FsqMethod *m= (void*)mm;
368 FsqReq *inst= (FsqReq*)instchg;
370 return fsq_enqueue(m, inst);
373 static ErrorCode fsq_check(Method *mm) {
374 FsqMethod *m= (void*)mm;
375 ErrorCode ec= fsq_check_plan(m);
376 DPRINTF(movpos,fsq, "%s check=%s\n", m->m.pname, ec2str(ec));
380 static void fsq_execute(Method *mm) {
381 FsqMethod *m= (void*)mm;
382 DPRINTF(movpos,fsq, "%s execute\n", m->m.pname);
386 /*---------- something to do ? ----------*/
388 static void fsq_check_action(FsqMethod *m) {
389 /* client should call this after it sets ready */
392 if (!m->f.confirmed.n) {
393 if (sta_state == Sta_Finalising) resolve_motioncheck();
397 FsqReq *r= m->f.confirmed.l[0];
399 if (r->n_motions && m->f.ready>0) {
400 /* look for something to move */
401 Motion *mo= &r->motions[--r->n_motions];
402 assert(mo->posn < mo->i->posns);
404 m->f.move(m, mo->i, mo->posn);
407 method_update_feature(&m->m, r->h.indep, mo);
411 fsq_queue_remove_index(&m->f.confirmed, 0);
412 indep_change_done(&m->m, &r->h);
413 m->h.dispose(&m->m, &r->h);
415 ec= fsq_check_plan(m); assert(!ec);
420 /*========== points ==========*/
423 * CDU and point queue states:
426 * ____________ conf'd
427 * / points_ \ ready .n
431 * |from INACTIVE -1 0
432 * |any <=Sta_Settling
435 * ___________ |turning
446 * | |fsq_check_action
447 * | | calls point_move which fires a point
452 #define CDU_RECHARGE 350 /*ms*/
453 #define POINT_MOVEMENT 50 /*ms*/
455 static ErrorCode point_prepare(Method *mm, Segment *move,
456 int n_motions, const Motion *motions,
457 int ms, int confirmation,
458 Change *chg_r, int *cost_r) {
459 FsqMethod *m= (void*)mm;
460 assert(m->f.ready>=0);
461 return fsq_prepare(mm,move, n_motions,motions,
462 ms,confirmation, chg_r,cost_r);
465 static void point_move(FsqMethod *m, const MovFeatInfo *mfi, int posn) {
466 /* actually firing points, yay! */
468 enco_pic_point(&piob, mfi->boob[posn]);
469 serial_transmit(&piob);
472 static void points_all_abandon(Method *mm) {
473 FsqMethod *m= (void*)mm;
477 static FsqMethod points_method;
479 void points_turning_on(void) {
480 FsqMethod *m= &points_method;
483 void on_pic_charged(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
484 FsqMethod *m= &points_method;
485 if (m->f.ready<0) return;
490 static FsqMethod points_method= {
491 { "point", mfk_point,
492 point_prepare, fsq_consider, fsq_dispose,
493 fsq_check, fsq_execute, points_all_abandon },
494 { .lag_ms= POINT_MOVEMENT, .slot_ms= CDU_RECHARGE, .move= point_move }
497 /*========== relays ==========*/
502 * ____________ conf'd
503 * / wagglers_ \ ready .n
508 * |any <=Sta_Settling
511 * ___________ |turning
522 * | |fsq_check_action
523 * | | calls waggle_do which switches a relay
528 static FsqMethod waggle;
530 static void waggle_do(FsqMethod *m, const MovFeatInfo *mfi, int posn) {
531 /* actually setting relays */
533 enco_pic_waggle(&piob, mfi->boob[0], posn);
534 serial_transmit(&piob);
537 static SegmentNum waggle_settle_seg;
538 static int waggle_settle_feat;
540 static void waggle_settle_check(void) {
542 if (waggle_settle_seg >= info_nsegments) return;
544 Segment *seg= &segments[waggle_settle_seg];
545 if (waggle_settle_feat >= seg->i->n_movfeats) {
546 waggle_settle_seg++; waggle_settle_feat=0; continue;
549 const MovFeatInfo *feati= &seg->i->movfeats[waggle_settle_feat];
550 if (feati->kind != mfk_relay) {
551 waggle_settle_feat++; continue;
555 waggle_do(&waggle, feati, (seg->movposcomb / feati->weight) & 1);
556 waggle_settle_feat++;
560 void waggle_startup_manual(void) {
564 void waggle_settle(void) {
565 waggle_settle_seg= 0;
566 waggle_settle_feat= 0;
568 waggle_settle_check();
571 void on_pic_waggled(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
572 if (sta_state == Sta_Settling) {
574 waggle_settle_check();
575 } else if (sta_state >= Sta_Resolving || sta_state == Sta_Manual) {
577 fsq_check_action(&waggle);
582 static FsqMethod waggle= {
583 { "relay", mfk_relay,
584 fsq_prepare, fsq_consider, fsq_dispose,
585 fsq_check, fsq_execute, ignore_all_abandon },
586 { .lag_ms= 5, .slot_ms= 50, .move= waggle_do }
589 /*========== dummy `nomove' kind ==========*/
591 typedef struct NomoveChange {
600 unsigned eventqueued:1;
601 NomoveChange *queuehead;
604 static ErrorCode nomove_prepare(Method *meth_in, Segment *move,
605 int n_motions, const Motion *motions,
606 int ms, int confirming,
607 Change *chg_r, int *cost_r) {
610 chg= mmalloc(sizeof(*chg) + sizeof(Motion)*n_motions);
611 chg->n_motions= n_motions;
612 memcpy(chg->motions, motions, sizeof(Motion)*n_motions);
619 static void nomove_dispose(Method *mm, Change *remvchg) {
620 NomoveChange *remv= (void*)remvchg;
624 static ErrorCode nomove_install(Method *mm, Change *instchg) {
625 NomoveMethod *meth= (void*)mm;
626 NomoveChange *inst= (void*)instchg;
627 DLIST1_PREPEND(meth->queuehead, inst, inqueue);
630 static void nomove_remove(Method *mm, Change *remvchg) {
631 NomoveMethod *meth= (void*)mm;
632 NomoveChange *remv= (void*)remvchg;
633 DLIST1_REMOVE(meth->queuehead, remv, inqueue);
636 static ErrorCode nomove_check(Method *mm) { return 0; }
638 static void (*nomove_execute_now)(oop_source *source, struct timeval tv,
640 NomoveMethod *meth= meth_v;
641 meth->eventqueued= 0;
643 while ((done= meth->queuehead)) {
644 for (i=0; i<done->n_motions; i++)
645 method_update_feature(&meth->m, done->indep, &done->motions[i]);
646 method_change_done(&meth->m, &done->h);
647 DLIST1_REMOVE(meth->queuehead, done, inqueue);
648 nomove_dispose(&meth->m, &done->h);
651 static void nomove_execute(Method *mm) {
652 NomoveMethod *meth= (void*)mm;
653 if (!meth->eventqueued) {
654 meth->eventqueued= 1;
655 events->on_time(events, OOP_TIME_NOW, nomove_execute_now, meth);
659 static Method nomove_method= {
661 nomove_prepare, nomove_dispose,
662 nomove_install, nomove_remove,
663 nomove_check, nomove_execute, ignore_all_abandon
666 /*========== method-independent machinery ==========*/
668 struct MovPosChange {
670 MovPosComb actual, target;
671 unsigned installed:1;
676 static Method *methods[]= {
677 [mfk_none] = (Method*)&nomove_method,
678 [mfk_point] = (Method*)&points_method,
679 [mfk_relay] = (Method*)&waggle,
682 /*---------- entrypoints from methods ----------*/
684 static void method_update_feature(Method *m, MovPosChange *indep,
686 /* Called from methods' execution logic when an individual feature
687 * has been moved. This is used by the method-independent code to
688 * compute the correct delta set of movements from the current
689 * actual position, when thinking about new plans. It is also sent
690 * to clients and ultimately used by the UI.
692 ouprintf("movpos %s feat %s %d %s\n", indep->move->i->pname,
693 mo->i->pname, mo->posn, m.pname);
694 if (SOMEP(indep->actual))
696 movposcomb_update_feature(indep->actual, mo->i, mo->posn);
699 static void method_change_done(Method *m, Change *chg) {
700 /* Called from methods' execution logic when a whole change
701 * has been done. The method-independent code will take care of
702 * updating move->movposcomb. etc.
704 * REENTRANCY: must NOT be called from within a call to the method's
705 * execute() (and of course cannot legally be called from within
706 * prepare, consider, check or dispose).
708 MovPosComb *indep= chg->indep;
711 for (search=indep->changes; *search; search++)
712 if ((*search) == chg) goto found;
713 assert(!"change in indep");
717 if (indep->n_changes) {
718 *search= indep[n_changes];
725 move->movposcomb= indep->target;
726 ouprintf("movpos %s position %s stable\n",
727 move->i->pname, movpos_pname(move, move->movposcomb));
731 /*---------- internal core machinery ----------*/
733 static Method *feature_method(MovFeatInfo *feati) {
734 assert(feati->kind >= 0);
735 assert(feati->kind < ARRAY_SIZE(methods));
736 Method *meth= methods[feati->kind];
741 static int change_needed(const MovFeatInfo *feati,
742 MovPosComb startpoint, MovPosComb target) {
744 r= !SOMEP(startpoint) ||
745 (target - startpoint) / feati->weight % feati->posns;
746 DPRINTF(movpos,changeneeded, "%s:%s(%d*%d) %d..%d => %d\n",
747 feature_method(feati)->pname, feati->pname,
748 feati->posns, feati->weight,
749 startpoint, target, r);
753 #define EVAL_MAX_METHODS 2
754 #define EVAL_MAX_MOTIONS 2
756 static ErrorCode indep_prepare(Segment *move, MovPosComb target,
757 MovPosComb startpoint,
758 int ms, int confirming,
759 MovPosChange *indep_r /* 0 ok */,
760 int *cost_r /* 0 ok */) {
762 static Method *meths[EVAL_MAX_METHODS];
763 static int n_motions[EVAL_MAX_METHODS];
764 static Motion meths[EVAL_MAX_METHODS][EVAL_MAX_MOTIONS];
766 const SegmentInfo *movei= move->i;
768 const MovFeatInfo *feati;
770 MovPosChange *indep=0;
772 DPRINTF(movpos,eval, "%s/%s <-%s", move->i->pname,
773 movpos_pname(move,target), movpos_pname(move,startpoint));
775 if (!SOMEP(startpoint)) {
776 startpoint= movpos_poscomb_actual(move);
777 DPRINTF(movpos,eval, " actual <-%s\n",
778 movpos_pname(move,startpoint));
783 for (feat=0, feati=movei->movfeats, tchanges=0, kind= mfk_none;
784 feat<movei->n_movfeats;
786 if (!change_needed(feati,startpoint,target)) continue;
787 MovPosComb posn= target / feati->weight % feati->posns;
788 Method *meth= feature_method(feati);
791 for (methi=0; methi<n_meths; methi++)
792 if (meths[methi] == meth) goto found_method;
793 /* need a new method */
795 if (methi >= EVAL_MAX_METHODS) return EC_MovFeatTooManyMethods;
798 DPRINTF(movpos,eval, " meths[%d]=%s", methi,meth->pname);
801 int motioni= ++n_motions[methi];
802 if (motioni >= EVAL_MAX_MOTIONS) return EC_MovFeatTooManyMotions;
803 DPRINTF(movpos,eval, " motion[%d][%d]=%s%d",
804 methi,motioni,feati->pname,posn);
805 motions[methi][motioni].i= feati;
806 motions[methi][motioni].posn= posn;
810 DPRINTF(movpos,eval, " alloc");
811 indep= mmalloc(sizeof(*indep) + sizeof(Change*) * n_meths);
812 memset(indep->changes, 0, sizeof(Change*) * n_meths);
814 indep->actual= startpoint;
815 indep->target= target;
816 indep->considering= 0;
818 DPRINTF(movpos,eval, "\n");
822 for (int changei=0; changei<n_meths; changei++) {
823 Method *meth= meths[changei];
827 ec= meth->prepare(meth,move,
828 n_motions[changei],motions[changei],
830 indep ? &indep->changes[changei] : 0,
834 Change *chg= indep->changes[changei];
838 totalcost += thiscost;
841 if (indep_r) *indep_r= indep;
842 if (cost_r) *cost_r= totalcost;
843 DPRINTF(movpos,eval, "%s/%s ok cost=%d\n", move->i->pname,
844 movpos_pname(move,target), totalcost);
848 DPRINTF(movpos,eval, "%s/%s abandon %s\n", move->i->pname,
849 movpos_pname(move,target), totalcost, ec2str(ec));
850 indep_dispose(indep);
854 static void indep_remove(MovPosChange *remv) {
857 for (i=0; i<remv->n_changes; i++) {
858 Change *chg= inst->changes[i];
859 if (!chg->installed) continue;
860 Method *meth= chg->meth;
862 meth->remove(meth, chg);
867 indep_install(MovPosChange *inst, int needcheck) {
868 /* if this fails, inst may be left partially installed */
871 for (i=0; i<inst->n_changes; i++) {
872 Change *chg= inst->changes[n_installed];
873 assert(!chg->installed);
874 Method *meth= chg->meth;
876 ec= meth->install(meth, chg);
882 ec= meth->check(meth);
893 static void indep_check_execute(void) {
894 for (Method **methwalk= methods;
897 if (meth->needcheck) {
898 ec= meth->check(meth);
902 if (meth->needexec) {
909 static void indep_dispose(MovPosChange *indep) {
912 for (int changei=0; changei<indep->n_changes; changei++) {
913 Change *chg= indep->changes[changei];
914 Method *meth= chg->meth;
916 meth->dispose(meth, chg);
921 /*---------- entrypoints from rest of program ----------*/
924 movpos_reserve(Segment *move, int maxdelay_ms, MovPosChange **res_r,
925 MovPosComb target, MovPosComb startpoint /*as for findcomb*/) {
927 MovPosChange *indep= 0;
929 DPRINTF(movpos,reserve, "%s/%s maxdelay=%dms startpoint=%s\n",
930 move->i->pname, movpos_pname(move,target),
931 maxdelay_ms, movpos_pname(move,startpoint));
933 ec= indep_prepare(move,target, startpoint,
938 ec= indep_install(indep, 1);
941 indep_check_execute();
946 indep_dispose(indep);
947 indep_check_execute();
951 ErrorCode movpos_findcomb_bysegs(Segment *back, Segment *move, Segment *fwd,
952 MovPosComb startpoint, MovPosComb *chosen_r) {
953 const SegmentInfo *movei= move->i;
954 MovPosComb tcomb, bestcomb=-1;
955 int tcost, bestcost=INT_MAX;
956 const SegPosCombInfo *pci;
958 for (tcomb=0, pci=movei->poscombs;
959 tcomb<movei->n_poscombs;
961 Segment *tback= &segments[pci->link[1].next];
962 Segment *tfwd= &segments[pci->link[0].next];
963 if (back && !(back==tback || back==tfwd)) continue;
964 if (fwd && !(fwd ==tback || fwd ==tfwd)) continue;
966 /* we have to search for the one which is least effort */
967 ec= indep_prepare(move,tcomb,startpoint, -1,0, 0,&tcost);
970 if (tcost >= bestcost) /* prefer low-numbered movposcombs */
976 if (chosen_r) *chosen_r= bestcomb;
978 bestcost==INT_MAX ? EC_MovFeatRouteNotFound :
982 ErrorCode movpos_change(Segment *move, MovPosComb target,
983 int maxdelay_ms, MovPosChange *resv) {
984 const SegmentInfo *movei= move->i;
985 const MovFeatInfo *feati;
991 actual= move->movposcomb;
992 assert(!move->motion);
994 actual= move->motion->actual;
997 DPRINTF(movpos,change, "%s/%s maxdelay=%dms actual=%s\n",
998 move->i->pname, movpos_pname(move,target),
999 maxdelay_ms, movpos_pname(move, actual));
1000 if (resv) DPRINTF(movpos,change, " chg=%s:%s/%s\n",
1001 chg->meth->pname, chg->move->i->pname,
1002 movpos_pname(chg->move, chg->intent));
1004 MovPosChange *inst= 0;
1006 ec= indep_prepare(move,target, actual,
1012 indep_remove(move->motion);;
1014 ec= indep_install(inst, 1);
1017 indep_dispose(resv);
1018 indep_dispose(move->motion);
1022 indep_check_execute();
1027 indep_dispose(inst);
1028 ec= indep_install(move->motion, 0); assert(!ec);
1029 ec= indep_install(resv, 0); assert(!ec);
1030 indep_check_execute();
1034 void movpos_unreserve(MovPosChange *resv) {
1036 DPRINTF(movpos,unreserve, "%s:%s/%s\n",
1037 res->meth->pname, res->move->i->pname,
1038 movpos_pname(res->move, res->intent));
1040 indep_dispose(resv);
1041 indep_check_execute();
1044 MovPosComb movpos_change_intent(MovPosChange *indep) {
1045 return indep->intent;
1048 void motions_all_abandon(void) {
1050 for (meth=methods; *meth; meth++)
1051 (*meth)->all_abandon(*meth);
1060 STUFF BEYOND HERE IS FUNCTIONALITY WHICH NEEDS MOVING TO INDEP
1061 AND/OR CHECKING THAT WE STILL HAVE IT
1064 static ErrorCode fsq_confirm(Method *mm, Change *chg, Segment *move,
1065 int n_motions, const Motion *motions,
1067 FsqMethod *m= (void*)mm;
1068 FsqReq *r= (FsqReq*)chg;
1069 FsqSlotSigned reldeadline;
1070 int allow_failure, DP;
1073 DPRINTF1(movpos,fsq, "%s confirm %s n=%d maxdelay=%dms",
1074 m->m.pname, move->i->pname, n_motions, maxdelay_ms);
1076 assert(!r->motions[0].i); /* no confirming things already confirmed */
1077 if (r->deadline==FSQDN)
1078 DPRINTF2(" (alloc'd: %d)\n", r->n_motions);
1080 DPRINTF2(" (res: %s/%s[%d@t+%d])\n",
1081 r->h.move->i->pname, movpos_pname(r->h.move, r->h.intent),
1082 r->n_motions, r->deadline);
1084 /* If the segment is moving, these motions are already based on the
1085 * actual physical position which is stored in the existing request.
1086 * So we try removing the existing request from the queue and put
1087 * it back if it doesn't work.
1090 if (n_motions > r->n_motions)
1091 return EC_MovFeatReservationInapplicable;
1092 assert(n_motions <= r->n_motions);
1093 if (maxdelay_ms == -1) {
1094 reldeadline= r->deadline;
1095 if (reldeadline==FSQDN)
1096 reldeadline= fsq_maxdelay_reldeadline(m, -1, n_motions);
1098 reldeadline= fsq_maxdelay_reldeadline(m, maxdelay_ms, n_motions);
1100 allow_failure= reldeadline < (FsqSlotSigned)r->deadline;
1101 DPRINTF(movpos,fsq, "%s reldeadline=[%d@t+%d] allow_failure=%d\n",
1102 m->m.pname, n_motions, reldeadline, allow_failure);
1106 /* states of existing: */
1108 move->moving ? (FsqReq*)move->motion : 0; /* U or C */
1111 "%s existing %s n=%d deadline=t+%d\n",
1113 existing->h.move->i->pname,
1114 existing->n_motions,
1115 existing->deadline - m->f.cslot);
1116 fsq_dequeue(m, existing); /* U or CA */
1120 memcpy(r->motions, motions, sizeof(r->motions[0])*n_motions);
1121 if (!n_motions) r->motions[0].i= move->i->movfeats;
1122 assert(r->motions[0].i);
1123 r->n_motions= n_motions;
1124 r->deadline= reldeadline + m->f.cslot;
1126 if (n_motions == move->i->n_movfeats)
1129 r->actual= chg->actual;
1130 assert(r->actual >= 0);
1133 ec= fsq_enqueue(m, &m->f.confirmed, r);
1134 DPRINTF(movpos,fsq, "%s fsq_enqueue=%s\n", m->m.pname, ec2str(ec));
1135 assert(allow_failure || !ec);
1137 if (existing) { /* CA */
1138 if (ec) { /* state C but bad */
1139 fsq_dequeue(m,r); /* state CA */
1140 fsq_mark_as_allocated(r); /* state A */
1141 ErrorCode ec_putback= fsq_enqueue(m,&m->f.confirmed, existing);
1142 assert(!ec_putback); /* C */
1143 } else { /* state C and good */
1144 free(existing); /* U */
1147 /* either ec=0 state C U
1148 * or ec!=0 state A C
1149 * or ec!=0 state C but bad C
1156 move->movposcomb= -1;
1158 fsq_check_action(m);
1164 r->actual= movposcomb_update_feature(r->actual,mo->i,mo->posn);
1165 if (r->h.actual >= 0 || !r->n_motions)
1166 r->h.actual= r->actual;
1167 ouposn_moving(&r->h);
1172 /* look for something to report
1173 * we can get things here other than from the above
1174 * eg if we are asked to move the
1176 Segment *move= r->h.move;
1177 assert(move->moving && move->motion == (Change*)r);
1178 fsq_mark_as_allocated(r); /* now state A aka Done */
1179 motion_done(move,r->h.actual);
1182 /*---------- entrypoints from rest of program ----------*/
1184 static void fsq_all_abandon(Method *mm) {
1185 FsqMethod *m= (void*)mm;
1188 assert(!m->f.reserved.n);
1190 for (i=0; i<m->f.confirmed.n; i++) {
1192 FsqReq *r= m->f.confirmed.l[i];
1193 Segment *move= r->h.move;
1194 assert(move->motion == (Change*)r);
1195 motion_done(move,r->h.actual);
1198 m->f.confirmed.n= 0;
1201 in points_all_abandon
1202 fsq_all_abandon(mm);
1207 * seg->moving and ->motion is in one of the states UC
1209 static Change *mp_allocate(Method *meth, Segment *move,
1210 int alloc_motions, MovPosComb target) {
1211 assert(sta_state >= Sta_Resolving || sta_state == Sta_Manual);
1212 Change *chg= meth->allocate(meth, alloc_motions);
1215 chg->intent= target;