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.
21 /* The following states exist for each MovPosChange
22 * at points when control flow passes between kind and indep:
23 * U Unallocated no memory allocated (MovPosChange does not exist)
24 * A Allocated memory allocation done
25 * R Reserved reservation was successful
26 * C Confirmed motion queued and will occur
27 * D Done motion is complete and callback just needs to be made
28 * E Erroneous indep must call destroy straight away
29 * seg->moving and ->motion is in one of the states UC
32 typedef struct MovPosChange { /* valid in: filled in by and when: */
33 Method *meth; /* ARCDE indep after allocate() */
34 Segment *move; /* ARCDE indep after allocate() */
35 MovPosComb actual; /* CD see below */
36 MovPosComb intent; /* RCD indep after allocate() */
37 /* kind-specific data follows */ /* varies kind-specific code, varies */
39 /* `actual' contains the kind's public opinion about the physical
40 * state. It is initialised by indep (just before confirm) from
41 * move->motion->actual or move->movposcomb as the case may be. It
42 * should be updated by the kind, since it is used by indep for
43 * calculating the number and identities of the features which may
44 * need to change when a new move request is intended to replace an
45 * existing one - ie, the contents of the motions[] provided to a
46 * subsequent confirm(). So while a change is Confirmed, the
47 * physical state is recorded only in the relevant change, and not
48 * in the segment's movposcomb. Once a change goes to Confirmed,
49 * the indep code never untangles it so the kind can manage the
50 * proper transition. */
55 Change *(*allocate)(Method *m, int alloc_motions); /* U->A (never err) */
56 ErrorCode (*reserve)(Method *m, Change*, Segment*, /* A->R */
57 int ms); /* error: A->E */
58 ErrorCode (*confirm)(Method *m, Change*, Segment*, /* [AR]->C */
59 int n_motions, const Motion*, int ms); /* err:[AR]->E */
60 void (*destroy)(Method *m, Change*); /* [ARCE]->U */
61 void (*all_abandon)(Method *m);
62 /* indep guarantees that
63 * alloc_motions >= move->i->n_motions on reserve
64 * alloc_motions >= n_motions on confirm
65 * and that if on entry to reserve move->motion is non-0,
66 * it move->motion is non-0 and of the same kind
70 const char *movpos_pname(Segment *move, MovPosComb poscomb) {
71 return poscomb<0 ? "?" : move->i->poscombs[poscomb].pname;
74 static void ouposn_moving(Change *chg) {
75 Segment *move= chg->move;
76 oprintf(UPO, "movpos %s position %s moving\n",
77 move->i->pname, movpos_pname(move, chg->actual));
80 static void motion_done(Segment *move, MovPosComb actual) {
83 move->movposcomb= actual;
84 oprintf(UPO, "movpos %s position %s stable\n",
85 move->i->pname, movpos_pname(move, move->movposcomb));
88 static void ignore_all_abandon(Method *m) { }
90 /*========== points and other fixed timeslot movfeats ==========*/
93 * We maintain two queues, one for reserved one for actually confirmed
94 * requests where we know what we're doing.
96 * We divide time into discrete slots, numbered with clock arithmetic.
98 * cslot cslot+1 cslot+2
100 * currently next in after
103 * We increment cslot when we consider the movfeat to move;
104 * for points and relays this is when we issue the command to the PIC.
105 * In a request, the deadline represents the latest allowable value
106 * of cslot just before that increment.
109 typedef unsigned FsqSlot;
110 typedef int FsqSlotSigned;
112 /* We think there are three states: Allocated, Reserved and Confirmed.
113 * (plus of course Unallocated where we don't have a request at all).
114 * These correspond to the indep code as follows:
116 * indep state pt state queues checked and plan viable
117 * Unallocated n/a yes
118 * Allocated Allocated yes
119 * Reserved Reserved yes
120 * Confirmed Confirmed yes
123 * Erroneous exists only after a failed reserve() or confirm() so it's
124 * not that confusing to have this slightly malleable terminology.
127 #define FSQDN (~(FsqSlot)0)
129 typedef struct { /* Allocated Reserved Confirmed */
130 /* in queue? absent reserved confirmed */
132 FsqSlot deadline; /* ~0==FSQDN relative absolute <- */
133 MovPosComb actual; /* undef undef see below */
134 int n_motions; /* alloc'd alloc'd undone */
135 Motion motions[]; /* [0].i: 0 0 non-0 <- */
136 /* [..].i: undef undef non-0 */
137 /* .posn: undef undef defined */
139 /* We can determine the the state by looking at the two
140 * `statedet' fields, marked <- above.
141 * There are also intermediate states where the req's
142 * statedet fields do not agree with the queue it's on.
143 * We write these as, for example,
144 * AR to mean statedet says Allocated, but queued on fsq_reserved
145 * A? to mean statedet says Allocated, but may be queued
146 * etc. They are only allowed while we are in a fsq_... method function.
148 /* FsqReq.actual is subtly differnet to MovPosChange.actual,
150 * in MovPosChange in FsqReq
151 * Position unknown -1 0
152 * Position partly known -1 unknown feats are 0
153 * Position completely known exact exact
155 * The partial knowledge positions can only occur in requests that
156 * are confirmed with as many motions as features, so we know that
157 * if we complete a request we know that we can copy actual out
160 * If we abandon a half-done change to a multi-feat segment
161 * we lose the partial knowledge.
164 #define FSQ_MAX_QUEUE 15
168 FsqReq *l[FSQ_MAX_QUEUE];
171 typedef struct FsqMethod FsqMethod;
174 /* set by fsq's client before fsq_init */
176 void (*move)(FsqMethod *m, const MovFeatInfo *mfi, int movfeatposn);
178 int ready; /* >0 means ready; set to 0 by fsq just before move */
179 /* fsq's client must arrange that these start out at all-bits-zero */
181 FsqQueue confirmed, reserved;
187 /* client may put things here */
190 static void fsq_check_action(FsqMethod *m);
191 static ErrorCode fsq_check_plan(FsqMethod *m);
193 static FsqSlotSigned fsq_maxdelay_reldeadline(FsqMethod *m,
194 int maxdelay_ms, int n_motions) {
195 if (maxdelay_ms==-1) return FSQ_MAX_QUEUE*16;
196 return (maxdelay_ms - m->f.lag_ms) / m->f.slot_ms - n_motions;
199 static void fsq_queue_remove_index(FsqQueue *q, int index) {
201 memmove(&q->l[index], &q->l[index+1], sizeof(q->l[0]) * (q->n - index));
204 static int fsq_req_compar_approx(const void *av, const void *bv) {
205 FsqReq *const *a= av;
206 FsqReq *const *b= av;
207 FsqSlotSigned dldiff= (*b)->deadline - (*a)->deadline;
211 static void fsq_queue_remove_item(FsqQueue *q, FsqReq *r) {
214 entry= bsearch(r, q->l, q->n, sizeof(q->l[0]), fsq_req_compar_approx);
217 #define SEARCH_CHECK do{ \
218 if (q->l[i] == r) goto found; \
219 if (q->l[i]->deadline != r->deadline) break; \
221 for(i= entry - q->l; i >= 0; i--) SEARCH_CHECK;
222 for(i= entry - q->l + 1; i < q->n; i++) SEARCH_CHECK;
226 fsq_queue_remove_index(q, i);
229 static void fsq_dequeue(FsqMethod *m, FsqReq *r) { /* X->XA */
230 if (r->motions[0].i) {
231 fsq_queue_remove_item(&m->f.confirmed, r);
232 } else if (r->deadline!=FSQDN) {
233 fsq_queue_remove_item(&m->f.reserved, r);
240 static void fsq_mark_as_allocated(FsqReq *r) { /* AX->X */
241 /* Sets statedet fields for Allocated */
248 whichwhen= wh##when, \
251 static ErrorCode fsq_check_plan(FsqMethod *m) {
252 /* Checks whether we can meet the currently queued commitments */
253 int future, conf, resv, whichwhen;
259 oprintf(DUPO("movpos/fsq") "%s plan", m->m.pname);
261 /* If CDU is charged we can't do one right away */
268 FsqReq *confr= conf < m->f.confirmed.n ? m->f.confirmed.l[conf] : 0;
269 FsqReq *resvr= resv < m->f.reserved .n ? m->f.reserved .l[resv] : 0;
270 if (!confr && !resvr) break;
271 oprintf(UPO," %d:",future);
272 int confwhen= confr ? confr->deadline - m->f.cslot : INT_MAX;
273 int resvwhen= resvr ? resvr->deadline : INT_MAX;
274 if (future && resvwhen < confwhen) {
284 oprintf(UPO, "%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 oprintf(UPO,"!...bad\n");
289 return EC_MovFeatTooLate;
291 future += whichr->n_motions;
293 oprintf(UPO," ok\n");
299 static ErrorCode fsq_enqueue(FsqMethod *m, FsqQueue *q, /* XA -> X */
300 FsqReq *r) { /* or on error, XA -> A */
301 int insat; /* ... where X is R or C and corresponds to q */
303 if (q->n == FSQ_MAX_QUEUE)
304 return EC_BufferFull;
307 insat>0 && (FsqSlotSigned)(r->deadline - q->l[insat-1]->deadline) < 0;
309 q->l[insat]= q->l[insat-1];
313 return fsq_check_plan(m);
314 /* if this fails, indep machinery calls fsq_destroy which dequeues */
317 /*---------- method entrypoints ----------*/
319 static Change *fsq_allocate(Method *mm, int alloc_motions) {
323 /* we need at least one motion in the table so we can tell
324 * the difference between the states by looking at motions[0].i */
327 r= mmalloc(sizeof(*r) + alloc_motions * sizeof(r->motions[0]));
329 r->n_motions= alloc_motions;
334 static ErrorCode fsq_reserve(Method *mm, Change *chg,
335 Segment *move, int maxdelay_ms) {
336 FsqMethod *m= (void*)mm;
337 FsqReq *r= (FsqReq*)chg;
338 FsqSlotSigned reldeadline;
340 reldeadline= fsq_maxdelay_reldeadline(m, maxdelay_ms, r->n_motions);
341 if (reldeadline <= 0) { fsq_mark_as_allocated(r); return EC_MovFeatTooLate; }
342 r->deadline= reldeadline;
343 return fsq_enqueue(m, &m->f.reserved, r);
346 static ErrorCode fsq_confirm(Method *mm, Change *chg, Segment *move,
347 int n_motions, const Motion *motions,
349 FsqMethod *m= (void*)mm;
350 FsqReq *r= (FsqReq*)chg;
351 FsqSlotSigned reldeadline;
355 oprintf(DUPO("movpos/fsq") "%s confirm %s n=%d maxdelay=%dms",
356 m->m.pname, move->i->pname, n_motions, maxdelay_ms);
358 assert(!r->motions[0].i); /* no confirming things already confirmed */
359 if (r->deadline==FSQDN)
360 oprintf(UPO, " (alloc'd: %d)\n", r->n_motions);
362 oprintf(UPO, " (res: %s/%s[%d@t+%d])\n",
363 r->h.move->i->pname, movpos_pname(r->h.move, r->h.intent),
364 r->n_motions, r->deadline);
366 /* If the segment is moving, these motions are already based on the
367 * actual physical position which is stored in the existing request.
368 * So we try removing the existing request from the queue and put
369 * it back if it doesn't work.
372 if (n_motions > r->n_motions)
373 return EC_MovFeatReservationInapplicable;
374 assert(n_motions <= r->n_motions);
375 if (maxdelay_ms == -1) {
376 reldeadline= r->deadline;
377 if (reldeadline==FSQDN)
378 reldeadline= fsq_maxdelay_reldeadline(m, -1, n_motions);
380 reldeadline= fsq_maxdelay_reldeadline(m, maxdelay_ms, n_motions);
382 allow_failure= reldeadline < (FsqSlotSigned)r->deadline;
383 oprintf(DUPO("movpos/fsq") "%s reldeadline=[%d@t+%d] allow_failure=%d\n",
384 m->m.pname, n_motions, reldeadline, allow_failure);
388 /* states of existing: */
390 move->moving ? (FsqReq*)move->motion : 0; /* U or C */
392 oprintf(DUPO("movpos/fsq")
393 "%s existing %s n=%d deadline=t+%d\n",
395 existing->h.move->i->pname,
397 existing->deadline - m->f.cslot);
398 fsq_dequeue(m, existing); /* U or CA */
402 memcpy(r->motions, motions, sizeof(r->motions[0])*n_motions);
403 if (!n_motions) r->motions[0].i= move->i->movfeats;
404 assert(r->motions[0].i);
405 r->n_motions= n_motions;
406 r->deadline= reldeadline + m->f.cslot;
408 if (n_motions == move->i->n_movfeats)
411 r->actual= chg->actual;
412 assert(r->actual >= 0);
415 ec= fsq_enqueue(m, &m->f.confirmed, r);
416 oprintf(DUPO("movpos/fsq") "%s fsq_enqueue=%s\n", m->m.pname, ec2str(ec));
417 assert(allow_failure || !ec);
419 if (existing) { /* CA */
420 if (ec) { /* state C but bad */
421 fsq_dequeue(m,r); /* state CA */
422 fsq_mark_as_allocated(r); /* state A */
423 ErrorCode ec_putback= fsq_enqueue(m,&m->f.confirmed, existing);
424 assert(!ec_putback); /* C */
425 } else { /* state C and good */
426 free(existing); /* U */
429 /* either ec=0 state C U
431 * or ec!=0 state C but bad C
438 move->movposcomb= -1;
444 static void fsq_destroy(Method *mm, Change *chg) { /* X->XA and then freed */
445 FsqMethod *m= (void*)mm;
446 FsqReq *r= (FsqReq*)chg;
451 /*---------- something to do ? ----------*/
453 static void fsq_check_action(FsqMethod *m) {
454 /* client should call this after it sets ready */
457 if (!m->f.confirmed.n) {
458 if (sta_state == Sta_Finalising) resolve_motioncheck();
462 FsqReq *r= m->f.confirmed.l[0];
464 if (r->n_motions && m->f.ready>0) {
465 /* look for something to move */
466 Motion *mo= &r->motions[--r->n_motions];
467 assert(mo->posn < mo->i->posns);
469 m->f.move(m, mo->i, mo->posn);
470 oprintf(UPO, "movpos %s feat %s %d %s\n", r->h.move->i->pname,
471 mo->i->pname, mo->posn, m->m.pname);
474 MovPosComb above_weight= mo->i->weight * mo->i->posns;
475 MovPosComb above= r->actual / above_weight;
476 MovPosComb below= r->actual % mo->i->weight;
477 r->actual= above*above_weight + mo->posn*mo->i->weight + below;
478 if (r->h.actual >= 0 || !r->n_motions)
479 r->h.actual= r->actual;
480 ouposn_moving(&r->h);
484 /* look for something to report
485 * we can get things here other than from the above
486 * eg if we are asked to move the
488 Segment *move= r->h.move;
489 assert(move->moving && move->motion == (Change*)r);
490 fsq_queue_remove_index(&m->f.confirmed,0);
491 fsq_mark_as_allocated(r); /* now state A aka Done */
492 motion_done(move,r->h.actual);
494 ec= fsq_check_plan(m); assert(!ec);
499 /*---------- entrypoints from rest of program ----------*/
501 static void fsq_all_abandon(Method *mm) {
502 FsqMethod *m= (void*)mm;
505 assert(!m->f.reserved.n);
507 for (i=0; i<m->f.confirmed.n; i++) {
508 FsqReq *r= m->f.confirmed.l[i];
509 Segment *move= r->h.move;
510 assert(move->motion == (Change*)r);
511 motion_done(move,r->h.actual);
517 /*========== points ==========*/
520 * CDU and point queue states:
523 * ____________ conf'd
524 * / points_ \ ready .n
528 * |from INACTIVE -1 0
529 * |any <=Sta_Settling
532 * ___________ |turning
543 * | |fsq_check_action
544 * | | calls point_move which fires a point
549 #define CDU_RECHARGE 250 /*ms*/
550 #define POINT_MOVEMENT 50 /*ms*/
552 static Change *point_allocate(Method *mm, int alloc_motions) {
553 FsqMethod *m= (void*)mm;
554 assert(m->f.ready>=0);
555 return fsq_allocate(mm, alloc_motions);
558 static void point_move(FsqMethod *m, const MovFeatInfo *mfi, int posn) {
559 /* actually firing points, yay! */
561 enco_pic_point(&piob, mfi->boob[posn]);
562 serial_transmit(&piob);
565 static void points_all_abandon(Method *mm) {
566 FsqMethod *m= (void*)mm;
571 static FsqMethod points_method;
573 void points_turning_on(void) {
574 FsqMethod *m= &points_method;
577 void on_pic_charged(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
578 FsqMethod *m= &points_method;
579 if (m->f.ready<0) return;
584 static FsqMethod points_method= {
585 { "point", mfk_point,
586 point_allocate, fsq_reserve, fsq_confirm,
587 fsq_destroy, points_all_abandon },
588 { .lag_ms= POINT_MOVEMENT, .slot_ms= CDU_RECHARGE, .move= point_move }
591 /*========== relays ==========*/
596 * ____________ conf'd
597 * / wagglers_ \ ready .n
602 * |any <=Sta_Settling
605 * ___________ |turning
616 * | |fsq_check_action
617 * | | calls point_move which fires a point
622 static FsqMethod waggle;
624 static Change *waggle_allocate(Method *mm, int alloc_motions) {
625 FsqMethod *m= (void*)mm;
626 assert(m->f.ready>=0);
627 return fsq_allocate(mm, alloc_motions);
630 static void waggle_do(FsqMethod *m, const MovFeatInfo *mfi, int posn) {
631 /* actually firing points, yay! */
633 enco_pic_waggle(&piob, mfi->boob[0], posn);
634 serial_transmit(&piob);
637 static SegmentNum waggle_settle_seg;
638 static int waggle_settle_feat;
640 static void waggle_settle_check(void) {
642 if (waggle_settle_seg >= info_nsegments) return;
644 Segment *seg= &segments[waggle_settle_seg];
645 if (waggle_settle_feat >= seg->i->n_movfeats) {
646 waggle_settle_seg++; waggle_settle_feat=0; continue;
649 const MovFeatInfo *feati= &seg->i->movfeats[waggle_settle_feat];
650 if (feati->kind != mfk_relay) {
651 waggle_settle_feat++; continue;
655 waggle_do(&waggle, feati, (seg->movposcomb / feati->weight) & 1);
656 waggle_settle_feat++;
660 void waggle_startup_manual(void) {
664 void waggle_settle(void) {
665 waggle_settle_seg= 0;
666 waggle_settle_feat= 0;
668 waggle_settle_check();
671 void on_pic_waggled(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
672 if (sta_state == Sta_Settling) {
674 waggle_settle_check();
675 } else if (sta_state >= Sta_Resolving || sta_state == Sta_Manual) {
677 fsq_check_action(&waggle);
682 static FsqMethod waggle= {
683 { "relay", mfk_relay,
684 waggle_allocate, fsq_reserve, fsq_confirm,
685 fsq_destroy, fsq_all_abandon },
686 { .lag_ms= 5, .slot_ms= 50, .move= waggle_do }
689 /*========== dummy `nomove' kind ==========*/
691 static Change *nomove_allocate(Method *m, int alloc_motions) {
692 oprintf(DUPO("movfeatkind-momove") "allocate %d\n",alloc_motions);
693 return mmalloc(sizeof(Change));
695 static ErrorCode nomove_reserve(Method *m, Change *c, Segment *move, int ms) {
696 oprintf(DUPO("movfeatkind-nomove") "reserve\n");
699 static void nomove_destroy(Method *m, Change *c) { free(c); }
700 static ErrorCode nomove_confirm(Method *m, Change *c, Segment *move, int n,
701 const Motion *motions, int ms) {
702 oprintf(DUPO("movfeatkind-nomove") "confirm\n");
707 static Method nomove_method= {
708 "nomove", mfk_none, nomove_allocate, nomove_reserve, nomove_confirm,
709 nomove_destroy, ignore_all_abandon
712 /*========== method-independent machinery ==========*/
714 static Method *methods[]= {
716 (Method*)&points_method,
721 static Change *mp_allocate(Method *meth, Segment *move,
722 int alloc_motions, MovPosComb target) {
723 assert(sta_state >= Sta_Resolving || sta_state == Sta_Manual);
724 Change *chg= meth->allocate(meth, alloc_motions);
731 static int change_needed(const MovFeatInfo *feati,
732 MovPosComb startpoint, MovPosComb target) {
735 (target - startpoint) / feati->weight % feati->posns;
736 oprintf(DUPO("movpos/change-needed") "%s:%s(%d*%d) %d..%d => %d\n",
737 methods[feati->kind]->pname, feati->pname,
738 feati->posns, feati->weight,
739 startpoint, target, r);
743 static int evaluate_target(Segment *move, MovPosComb target,
744 MovPosComb startpoint, MovFeatKind *kind_r) {
745 /* returns number of features which have to change to reach target,
746 * or -1 for mixed kinds. kind_r may be 0. */
747 const SegmentInfo *movei= move->i;
749 const MovFeatInfo *feati;
752 oprintf(DUPO("movpos/eval") "%s/%s <-%s\n", move->i->pname,
753 movpos_pname(move,target), movpos_pname(move,startpoint));
756 startpoint= movpos_poscomb_actual(move);
757 oprintf(DUPO("movpos/eval") " actual <-%s\n",
758 movpos_pname(move,startpoint));
761 for (feat=0, feati=movei->movfeats, tchanges=0, kind= mfk_none;
762 feat<movei->n_movfeats;
764 if (!change_needed(feati,startpoint,target)) continue;
766 if (kind && feati->kind != kind) return -1;
770 if (kind_r) *kind_r= kind;
771 oprintf(DUPO("movpos/eval") "changes=%d kind=%s\n",
772 tchanges, methods[kind]->pname);
776 ErrorCode movpos_findcomb_bysegs(Segment *back, Segment *move, Segment *fwd,
777 MovPosComb startpoint, MovPosComb *chosen_r) {
778 const SegmentInfo *movei= move->i;
779 MovPosComb tcomb, bestcomb=-1;
780 int tchanges, bestchanges=INT_MAX;
781 const SegPosCombInfo *pci;
783 for (tcomb=0, pci=movei->poscombs;
784 tcomb<movei->n_poscombs;
786 Segment *tback= &segments[pci->link[1].next];
787 Segment *tfwd= &segments[pci->link[0].next];
788 if (back && !(back==tback || back==tfwd)) continue;
789 if (fwd && !(fwd ==tback || fwd ==tfwd)) continue;
791 /* we have to search for the one which is least effort */
792 tchanges= evaluate_target(move,tcomb,startpoint,0);
798 if (tchanges >= bestchanges) /* prefer low-numbered movposcombs */
802 bestchanges= tchanges;
804 if (chosen_r) *chosen_r= bestcomb;
806 bestchanges==INT_MAX ? EC_MovFeatRouteNotFound :
807 bestchanges==INT_MAX-1 ? EC_MovFeatKindsCombination :
811 ErrorCode movpos_change(Segment *move, MovPosComb target,
812 int maxdelay_ms, MovPosChange *chg) {
813 const SegmentInfo *movei= move->i;
814 const MovFeatInfo *feati;
818 MovFeatKind kind= mfk_none;
821 actual= move->movposcomb;
822 assert(!move->motion);
824 kind= move->motion->meth->kind;
825 actual= move->motion->actual;
828 oprintf(DUPO("movpos/change") "%s/%s maxdelay=%dms actual=%s\n",
829 move->i->pname, movpos_pname(move,target),
830 maxdelay_ms, movpos_pname(move, actual));
831 if (chg) oprintf(DUPO("movpos/change") " chg=%s:%s/%s\n",
832 chg->meth->pname, chg->move->i->pname,
833 movpos_pname(chg->move, chg->intent));
835 { /* provide horizon for visibility of motions[] */
837 Motion motions[movei->n_movfeats];
839 for (feat=0, feati=movei->movfeats;
840 feat<movei->n_movfeats;
842 if (!change_needed(feati,actual,target))
844 MovPosComb posn= target / feati->weight % feati->posns;
846 if (feati->kind != kind) { ec= EC_MovFeatKindsCombination; goto x; }
850 motions[n_motions].i= feati;
851 motions[n_motions].posn= posn;
855 Method *meth= methods[kind];
858 if (chg->meth != meth ||
860 chg->intent != target)
861 return EC_MovFeatReservationInapplicable;
863 chg= mp_allocate(meth,move,n_motions,target);
867 oprintf(DUPO("movpos/change") "confirm %s:%d...\n",
868 meth->pname, n_motions);
869 ec= meth->confirm(meth, chg, move, n_motions, motions, maxdelay_ms);
870 oprintf(DUPO("movpos/change") "confirm => %s\n",errorcodelist[ec]);
876 movpos_unreserve(chg);
881 movpos_reserve(Segment *move, int maxdelay_ms, MovPosChange **res_r,
882 MovPosComb target, MovPosComb startpoint /*as for findcomb*/) {
883 MovFeatKind kind= mfk_none;
887 oprintf(DUPO("movpos/reserve") "%s/%s maxdelay=%dms startpoint=%s\n",
888 move->i->pname, movpos_pname(move,target),
889 maxdelay_ms, movpos_pname(move,startpoint));
891 nchanges= evaluate_target(move,target,startpoint,&kind);
892 if (nchanges==-1) return EC_MovFeatKindsCombination;
894 Method *meth= methods[kind];
895 oprintf(DUPO("movpos/reserve") "allocate %s:%d...\n",
896 meth->pname, nchanges);
897 Change *chg= mp_allocate(meth, move, nchanges, target);
898 ec= meth->reserve(meth, chg, move, maxdelay_ms);
899 oprintf(DUPO("movpos/reserve") "reserve => %s\n",errorcodelist[ec]);
906 movpos_unreserve(chg);
910 void movpos_unreserve(MovPosChange *res) {
912 oprintf(DUPO("movpos/unreserve") "%s:%s/%s\n",
913 res->meth->pname, res->move->i->pname,
914 movpos_pname(res->move, res->intent));
915 res->meth->destroy(res->meth, res);
918 MovPosComb movpos_poscomb_actual(Segment *seg) {
919 return seg->moving ? seg->motion->actual : seg->movposcomb;
922 MovPosComb movpos_change_intent(MovPosChange *chg) {
926 void motions_all_abandon(void) {
928 for (meth=methods; *meth; meth++)
929 (*meth)->all_abandon(*meth);