From: ian Date: Sun, 20 Apr 2008 14:35:26 +0000 (+0000) Subject: wip new safety - before change way trackloc movpos is done X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ijackson/git?a=commitdiff_plain;h=bea4fa5fb72d05060df7c22db37f5a7ecc871156;p=trains.git wip new safety - before change way trackloc movpos is done --- diff --git a/hostside/errorcodes.h.gen b/hostside/errorcodes.h.gen index 49d8025..d8570b5 100755 --- a/hostside/errorcodes.h.gen +++ b/hostside/errorcodes.h.gen @@ -2,13 +2,14 @@ @f= qw( OK - Invalid - Safety MovFeatTooLate MovFeatKindsCombination + MovFeatReservationInapplicable BufferFull BadCmd NotFound + ProblemPredicted + SignalStopHorizonReached ); diff --git a/hostside/movpos.c b/hostside/movpos.c index e883968..973d583 100644 --- a/hostside/movpos.c +++ b/hostside/movpos.c @@ -33,6 +33,7 @@ typedef struct MovPosChange { /* valid in: filled in by and when: */ const KindInfo *ki; /* ARCDE indep after allocate() */ Segment *move; /* ARCDE indep after allocate() */ MovPosComb actual; /* CD see below */ + MovPosComb intent; /* RCD indep after allocate() */ /* kind-specific data follows */ /* varies kind-specific code, varies */ } Change; /* `actual' contains the kind's public opinion about the physical @@ -311,6 +312,8 @@ fprintf(stderr," point confirm\n"); * it back if it doesn't work. */ + if (n_motions >= r->n_motions) + return EC_MovFeatReservationInapplicable; assert(n_motions <= r->n_motions); newdeadline= pt_maxdelay_reldeadline(maxdelay_ms) + pt_cslot; allow_failure= newdeadline < r->deadline; @@ -471,71 +474,82 @@ static const KindInfo methodinfos[]= { }; static Change *mp_allocate(const KindInfo *ki, Segment *move, - int alloc_motions) { + int alloc_motions, MovPosComb target) { assert(sta_state >= Sta_Resolving); Change *chg= ki->allocate(alloc_motions); chg->ki= ki; chg->move= move; + chg->intent= target; return chg; } -static int movpos__evaluate_target(Segment *move, MovPosComb target) { - /* returns number of features which have to change to reach target */ +static int change_needed(const MovFeatInfo *feati, MovPosComb target, + MovPosComb startpoint) { + return + startpoint<0 || + (target - startpoint) / feati->weight % feati->posns; +} + +static int evaluate_target(Segment *move, MovPosComb target, + MovPosComb startpoint, MovFeatKind *kind_r) { + /* returns number of features which have to change to reach target, + * or -1 for mixed kinds. kind_r may be 0. */ const SegmentInfo *movei= move->i; int feat, tchanges; - MovPosComb actual; const MovFeatInfo *feati; + MovFeatKind kind; - actual= movpos_poscomb_actual(move); + if (startpoint<0) startpoint= movpos_poscomb_actual(move); - for (feat=0, feati=movei->movfeats, tchanges=0; + for (feat=0, feati=movei->movfeats, tchanges=0, kind= mfk_none;; featn_movfeats; - feat++) - if (actual<0 || (target - actual) / feati->weight % feati->posns) - tchanges++; + feat++, feati++) { + if (!change_needed(feati,target,startpoint)) continue; + tchanges++; + if (kind && feati->kind != kind) return -1; + kind= feati->kind; + } + + if (kind_r) *kind_r= kind; return tchanges; } -ErrorCode -movpos_change_bysegs(Segment *back, Segment *move, Segment *fwd, - int maxdelay_ms, MovPosChange *chg) { +ErrorCode movpos_findcomb_bysegs(Segment *back, Segment *move, Segment *fwd, + MovPosComb startpoint, MovPosComb *chosen_r) { const SegmentInfo *movei= move->i; - MovPosComb tcomb, bestcomb=0; + MovPosComb tcomb, bestcomb=-1; int tchanges, bestchanges=INT_MAX; const SegPosCombInfo *pci; - //fprintf(stderr,"moving %s\n",move->i->pname); for (tcomb=0, pci=movei->poscombs; tcombn_poscombs; tcomb++, pci++) { - //fprintf(stderr," tcomb %lu\n",tcomb); Segment *tback= &segments[pci->backwards.next]; Segment *tfwd= &segments[pci->forwards .next]; - //fprintf(stderr," tback %s tfwd %s\n", - // tback?tback->i->pname:"-", - // tfwd?tfwd->i->pname:"-" - // ); if (back && !(back==tback || back==tfwd)) continue; if (fwd && !(fwd ==tback || fwd ==tfwd)) continue; if (movei->n_movfeats>1) { //fprintf(stderr," several feats\n"); /* we have to search for the one which is least effort, then */ - tchanges= movpos__evaluate_target(move, tcomb); + tchanges= evaluate_target(move,tcomb,startpoint,0); if (tchanges >= bestchanges) /* prefer low-numbered movposcombs */ continue; + if (tchanges==-1) { + tchanges= INT_MAX-1; + /* fall through and update */ + } } else { tchanges= 1; } - //fprintf(stderr," best %lu changes %d\n",tcomb,tchanges); bestcomb= tcomb; bestchanges= tchanges; } - - //fprintf(stderr," best %lu changes %d\n",bestcomb,bestchanges); - if (bestchanges==INT_MAX) { movpos_unreserve(chg); return EC_Invalid; } - - return movpos_change(move, tcomb, maxdelay_ms, chg); + if (*chosen_r) *chosen_r= bestcomb; + return + tchanges==INT_MAX ? EC_Invalid : + tchanges==INT_MAX-1 ? EC_MovFeatKindsCombination : + 0; } ErrorCode movpos_change(Segment *move, MovPosComb target, @@ -547,11 +561,12 @@ ErrorCode movpos_change(Segment *move, MovPosComb target, ErrorCode ec; MovFeatKind kind= mfk_none; - if (move->moving) { - kind= move->moving->ki - methodinfos; - actual= move->moving->actual; - } else { + if (!move->moving) { actual= move->movposcomb; + assert(!move->motion); + } else { + kind= move->motion->ki - methodinfos; + actual= move->motion->actual; } { @@ -564,7 +579,7 @@ fprintf(stderr," motions... best=%lu actual=%ld\n",target,actual); feat++, feati++) { fprintf(stderr," checking %s w=%lu posns=%d\n", feati->pname,feati->weight,(int)feati->posns); - if (actual>=0 && !((target - actual) / feati->weight % feati->posns)) + if (!change_needed(feati,actual,target)) continue; MovPosComb posn= target / feati->weight % feati->posns; fprintf(stderr," motion %s %lu kind=%d\n",feati->pname,posn,kind); @@ -581,9 +596,12 @@ fprintf(stderr," motion %s %lu kind=%d\n",feati->pname,posn,kind); const KindInfo *ki= &methodinfos[kind]; if (chg) { - assert(move == chg->move); + if (chg->ki != ki || + chg->move != move || + chg->intent != intent) + return EC_MovFeatReservationInapplicable; } else { - chg= mp_allocate(ki,move,n_motions); + chg= mp_allocate(ki,move,n_motions,target); } chg->actual= actual; @@ -600,22 +618,18 @@ fprintf(stderr," confirming gave %s\n",errorcodelist[ec]); } ErrorCode -movpos_reserve(Segment *move, int maxdelay_ms, MovPosChange **res_r) { +movpos_reserve(Segment *move, int maxdelay_ms, MovPosChange **res_r, + MovPosComb target, MovPosComb startpoint /*as for findcomb*/) { MovFeatKind kind= mfk_none; const MovFeatInfo *feati; ErrorCode ec; - int feat; + int feat, nchanges; - for (feat=0, feati=move->i->movfeats; - feati->n_movfeats; - feat++, feati++) - if (kind) { - if (feati->kind != kind) return EC_MovFeatKindsCombination; - kind= feati->kind; - } + nchanges= evaluate_target(move,target,startpoint,&kind); + if (nchanges=-1) return EC_MovFeatKindsCombination; const KindInfo *ki= &methodinfos[kind]; - Change *chg= mp_allocate(ki, move, move->i->n_movfeats); + Change *chg= mp_allocate(ki, move, move->i->n_movfeats, target); ec= ki->reserve(chg, move, maxdelay_ms); if (ec) goto x; @@ -635,3 +649,7 @@ void movpos_unreserve(MovPosChange *res) { MovPosComb movpos_poscomb_actual(Segment *seg) { return seg->moving ? seg->moving->actual : seg->movposcomb; } + +MovPosComb movpos_change_intent(MovPosChange *chg) { + return chg->intent; +} diff --git a/hostside/safety.c b/hostside/safety.c index 64c54a2..a2d9969 100644 --- a/hostside/safety.c +++ b/hostside/safety.c @@ -60,18 +60,21 @@ Segment *segments; * If we _have_ claimed it then it had better be predicted to be * vacant by the time we get there (pred_present clear, see below). * - * If it is currently moving then that must be OK because we checked - * it before (except that if we're trying to increase our speed that - * may not be OK and we must reject the speed increase because we - * can't easily check whether the movement would happen in time). + * Regarding moveable features, we continuously develop our plan, + * as represented in route_plan and route_reservation. * - * If it is not currently moving and is set against us, then we need - * to arrange that we set it appropriately: if we've just claimed the - * segment then we can ask movfeat to set it for us (using any - * reservation which we may have stashed away) (and fail if it - * declines); otherwise we ask movfeat to give us a reservation valid - * for the time interval between the predicted vacation and present - * times. + * If the feature is currently moving and owned by us then that must + * be OK because we checked it before (except that if we're trying to + * increase our speed that may not be OK and we must replan the speed + * increase to check whether the movement will happen in time). + * + * If it is not currently moving and is set against us, then we plan + * to set it. If there is already a plan (ie, a reservation) and + * we're not accelerating then that's fine. Otherwise we make one: we + * determine the desired movposcomb make a reservation to move it in + * time. (If the segment is already owned by us that means a + * reservation to move it between when the tail leaves and the nose + * enters.) * * When predicted foredetect enters a new segment we add the new * segment to the tally of segments of the particular kind and @@ -82,14 +85,16 @@ Segment *segments; * * And, when predicted foredetect enters a new segment we advance the * predicted tail (as described above). We set pred_vacated and - * until_here, and remove the departing segments from the kind and - * train-relative orientation tallies. + * until, and remove the departing segments from tallies. * * If all of this works then pred_present and pred_vacated constitute - * the new ownership. + * the new ownership and motion constitutes the new plan. We commit + * to it by rewriting owner and det_* and actually requesting any + * movfeat changes. * * If not then we issue an signal stop command (we'd better not be - * doing that already!) or countermand the speed increase or whatever */ + * doing that already!) or countermand the speed increase or whatever. + */ /* * Here is how we use the stuff in the Segment: * @@ -102,16 +107,18 @@ Segment *segments; * movposcomb in an owned segment, if moving, means that * & we have a promise that the feature * moving will be OK by the time we get there - * at our current speed - * - * move_reservation 0 for unowned segments (although during prediction - * may be non-0 for a bit, in which case - * we garbage collect it in a bit) - * - * for an owned segment is our reservation which + * & at our current speed + * motion if not moving then motion is our reservation which * allows us to know that we are going to * be able to change this segment between * the tail leaving it and the head arriving + * in each case movpos_change_intent tells us the plan + * + * during prediction, motion can be non-0 for + * unowned segments as we make our plan. + * If we succeed we will end up + * owning the segment, and if we fail + * we garbage collect it * * det_ignore we expect interference detection here due to a * crossing (unowned segment), or @@ -148,6 +155,9 @@ void update_head(Train *tra, Segment *seg) { safety_panic(tra,seg, "track route not set and train has arrived"); } +typedef void PredictionProblemCallback(void *pu, Train *tra, TrackSegment *seg, + const char *fmt, va_list al); + typedef struct { unsigned accelerating:1; @@ -155,6 +165,9 @@ typedef struct { TrackAdvanceContext nosec, tailc, fdetc; TimeInterval elapsed; Distance was_distance; + + PredictionProblemCallback *problem_callback; + void *problem_callback_u; /* tally counts segments which have been entered in fdet_nextseg but * not left in tail_nextseg (ie not the same ones as pred_present), @@ -162,6 +175,21 @@ typedef struct { int noninv_tally[2]; } PredictUserContext; +static ErrorCode predict_vproblem(PredicUserContext *u, TrackSegment *seg, + const char *fmt, va_list al) { + u->problem_callback(u->train,seg,fmt,al); + return EC_ProblemPredicted; +} +static ErrorCode predict_problem(PredicUserContext *u, TrackSegment *seg, + const char *fmt, ...) { + ErrorCode ec; + va_list al; + va_start(al,fmt); + ec= predict_vproblem(u,seg,fmt,al); + va_end(al); + return ec; +} + static int initpresent_nextseg(TrackLocation *t, TrackAdvanceContext *c, MovPosComb *mpc_io, Segment *before) { PredictUserContext *u= c->u; @@ -172,124 +200,130 @@ static int initpresent_nextseg(TrackLocation *t, TrackAdvanceContext *c, static int nose_nextseg(TrackLocation *t, TrackAdvanceContext *c, MovPosComb *mpc_io, Segment *before) { PredictUserContext *u= c->u; + MovPosComb route_plan; + MovPosChange *route_change; /* Is it empty ? */ + if (u->train->sigstopping && t->seg->owner != u->train) + return EC_SignalStopHorizonReached; + if (t->seg->owner) { if (t->seg->owner != u->train) - return safety_problem(u->train, t->seg, "impeded by %s", - t->seg->owner->pname); + return predict_problem(u, t->seg, "impeded by %s", + t->seg->owner->pname); } if (t->seg->pred_present) - return safety_problem(u->train, t->seg, "will collide with itself!"); + return predict_problem(u, t->seg, "will collide with itself!"); - /* Is it set for us ? */ + /* What about the route ? */ if (t->seg->i->n_poscombs==1) goto movement_ok; if (t->seg->moving) { if (!t->seg->owner) - return safety_problem(u->train, t->seg, "route not yet set"); -no good if we are trying to accelerate - may get there too soon - goto movement_ok; + return predict_problem(u, t->seg, "route not yet set"); + if (!u->accelerating) { + *mpc_io= movpos_change_intent(t->seg->motion); + goto movement_ok; + } } - /* Maybe we can set it apropriately, or plan to. */ - - if (t->seg->pred_vacated) { - /* We're just predicting that we'll have it vacated. */ - MovPosChange *newres; - - if (t->seg->move_reservation && !u->accelerating) + if (t->seg->motion) { + /* We already have a plan. */ + route_plan= movpos_change_intent(t->seg->motion); + if (!u->accelerating) { + *mpc_io= route_plan goto movement_ok; - -need to calculate new intended movposcomb and remember it -so we get right answer next time - ec= movpos_reserve(t->seg, u->elapsed - t->seg->until, &newres); - if (ec) return safety_problem(u->train, t->seg, "cannot promise to" - " set route in time: %s", ec2str(ec)); - movpos_unreserve(t->seg->move_reservation); - t->seg->move_reservation= newres; + } } else { - /* Hah! We can change it! */ - /* This also copes with the case where in fact it was set right - * all along. In that case movpos's minimisation algorithm will - * chose to implement our request without any actual motions. */ - ec= movpos_change_bysegs(before,t->seg,0, t->seg->until, - t->seg->move_reservation); -stash intended movposcomb in new field in Segment -need to make us owner now as well -ownership should last until it stops moving at least - no actually this is still wrong - t->seg->move_reservation= 0; - if (ec) return safety_problem(u->train, t->seg, "cannot" - " set route in time: %s", ec2str(ec)); + /* Extend the plan. */ + ec= movpos_findcomb_bysegs(before,t->seg,0,*mpc_io, &route_plan); + assert(!ec); /* there must be _some_ route since + we're moving into t->seg */ } + if (route_plan == *mpc_io && !t->seg->moving) { + /* Well, that's all fine then. */ + movpos_unreserve(t->seg->motion); /* we don't need this */ + t->seg->motion= 0; + goto movement_ok; + } + /* We have a plan but it involves some motion: */ + ec= movpos_reserve(t->seg, + !t->seg->pred_vacated ? u->elapsed + : u->elapsed - t->seg->until, + &route_reservation, route_plan, *mpc_io); + if (ec) return predict_problem(u, t->seg, "cannot promise to" + " set route: %s", ec2str(ec)); + + movpos_unreserve(t->seg->motion); + t->seg->motion= route_reservation; + *mpc_io= route_plan; movement_ok: + /* Now we definitely have a plan which sets a good route at t->seg. */ + t->seg->tr_backwards= t->backwards; t->seg->pred_present= 1; t->seg->until= u->elapsed; + return 0; /* yay! */ +} - adjust - - & - - - const MovPosCombInfo *pci; - const SegmentLinkInfo *link; - - r= trackloc_getlink(t,0,0,&link,-1,1); - if (!r && link->next==before) - goto movement_ok; - - - - pci= t->seg->i->poscombs[ - link= t->backwards ? &tryi->forwards : &tryi->backwards; - - MovPosComb only_ok= -1, try; - for (try=0, tryi=t->seg->i->poscombs; - try < t->seg->i->n_poscombs; try++, tryi++) { - link= t->backwards ? &tryi->forwards : &tryi->backwards; - if (link->next != before) continue; - if (only_ok >= 0) { only_ok=-1; goto several_combs_ok; } - only_ok= try; - } - assert(only_ok >= 0); /* otherwise graph is full of lies */ - several_combs_ok: - - if (t->seg->movposcomb < 0 || t->seg->movposcomb != only_ok) { - - else if (t->seg->movposcomb < 0) { - +static int tail_nextseg(TrackLocation *t, TrackAdvanceContext *c, + MovPosComb *mpc_io, Segment *leaving) { + PredictUserContext *u= c->u; - return safety_problem( + if (t->seg->motion) + *mpc_io= movpos_change_intent(t->seg->motion); - t->seg->pred_present= 1; + u->noninv_tally[leaving->tr_backwards]--; + if (t->seg->pred_vacated) return 0; /* only vacate once */ + t->seg->pred_present= 0; + t->seg->pred_vacated= 1; + t->seg->until= u->elapsed; - safety_problem + return 0; +} static int fdet_nextseg(TrackLocation *t, TrackAdvanceContext *c, - Segment *next, MovPosComb *mpc_io) { + MovPosComb *mpc_io, Segment *before) { PredictUserContext *u= c->u; int advanced; - advanced= c->u->was_distance - c->distance; + if (t->seg->motion) + *mpc_io= movpos_change_intent(t->seg->motion); + + advanced= u->was_distance - c->distance; u->nosec.distance= advanced; r= trackloc_advance(&u->nose,&u->nosec); if (r) return r; -tally add new segment + if (!t->seg->invertible) { + u->noninv_tally[t->backwards]++; + if (u->noninv_tally[0] && u->noninv_tally[1]) + return predict_problem(u, t->seg, "cannot set track polarity"); + } u->tailc.distance= advanced; - r= + r= trackloc_advance(&u->tail,&u->tailc); assert(!r); -void predict_and_provide(Train *tra) { + if (u->was_distance == INT_MAX) + c->distance= speedmanager_stoppingdistance(u->train); + + u->was_distance= c->distance; + return 0; +} + +static ErrorCode predict_confirm(Train *tra, int accelerate, + PredictionProblemCallback *ppc, void *ppcu) { + /* Caller must call this with different situations until it succeeds! */ PredictUserContext u; memset(&u,0,sizeof(u)); + u.accelerating= accelerate; + u.problem_callback= ppc; + u.problem_callback_u= ppcu; trackloc_set_maxinto(&u.fdet, tra->foredetect, tra->foredetect->tr_backwards); @@ -315,7 +349,7 @@ void predict_and_provide(Train *tra) { u.nosec.distance= tra->detectable + (tra->backwards ? tra->tail : tra->head); u.nosec.nextseg= nose_nextseg; u.nosec.trackend= pred_trackend; - u.nosec.getmovpos= pred_getmovpos; + u.nosec.getmovpos= 0; u.nosec.u= &u; r= trackloc_advance(&u.nose,&u.nosec); @@ -323,15 +357,33 @@ void predict_and_provide(Train *tra) { /* predict the future */ - fdetc.distance= u.was_distance= INT_MAX; - fdetc.nextseg= fdet_nextseg; - fdetc.trackend= pred_trackend; - fdetc.getmovpos= pred_getmovpos; - fdetc.u= &u; + u.fdetc.distance= u.was_distance= INT_MAX; + u.fdetc.nextseg= fdet_nextseg; + u.fdetc.trackend= pred_trackend; + u.fdetc.getmovpos= 0; + u.fdetc.u= &u; + + u.tailc.nextseg= tail_nextseg; r= trackloc_advance(&fdet,&fdetc); - - + if (r) return r; + + /* commit here */ + FOR_SEG { + intr= interferes(seg); + if (seg->owner == tra) { + seg->det_ignore= 0; + seg->det_expect= 0; + seg->owner= 0; + if (intr) { + assert(!intr->owner || intr->owner==tra); + intr->det_ignore= 0; + } + } + if (seg->pred_present || seg->pred_vacated) { + seg->owner= tra; + if (seg->until) + predict the future fdet.seg= tra->foredetect; diff --git a/hostside/safety.h b/hostside/safety.h index 36481b7..eb51e00 100644 --- a/hostside/safety.h +++ b/hostside/safety.h @@ -43,7 +43,7 @@ struct Train { backwards:1, /* train is moving backwards wrt its own front and back */ /* Speed: */ - estopping:1, /* set and cleared by speed.c */ + sigstopping:1, /* set and cleared by speed.c */ /* Startup resolution (resolve.c): */ resolution:2; @@ -67,16 +67,14 @@ struct Segment { unsigned tr_backwards:1, /* train's motion is (would be) backwards wrt track */ ho_backwards:1, /* home train has its front and rear backwards wrt track */ - cm_autostop:1, /* train should stop on detection */ seg_inverted:1, /* polarity is inverted */ det_ignore:1, det_expected:1, /* safety.c */ + moving:1, /* feature(s) have been told to change */ mark0,mark1,mark2,mark3, /* for temporary private uses */ res_detect:1; /* detection noticed here during resolution */ - TimeInterval until_here; /* ) nonnegative; */ /* ) always valid but */ - /* ) 0 if already */ /* ) meaningful iff owner */ - MovPosComb movposcomb; /* -1 means not known or moving */ - MovPosChange *moving, /* non-0 iff feature(s) have been told to change */ - *move_reservation; /* see safety.c */ + MovPosComb movposcomb, /* -1 means not known or moving */ + MovPosChange *motion; /* if ->moving, owned by movpos, otherwise by safety */ + TimeInterval until; /* for use by safety.c */ const SegmentInfo *i; }; @@ -140,35 +138,44 @@ movpos_change(Segment *tomove, MovPosComb target, * reservation should be 0, or the results of movpos_reservechange * on the same move. It is always consumed, even on error. * - * On successful exit, tomove->moving is set non-0; from then on - * until ->moving becomes 0, movposcomb may not reflect the real - * physical state of the layout; instead it gives only information - * about the target configuration. (Choreographers are allowed to - * know implementation details and may know what movposcomb means - * for certain segments depending on the movement requested.) + * One of the following must be true of tomove on entry: + * moving==1 motion already owned by movpos, see above + * motion==0 motion empty, will become owned by movpos * - * Returns EC_Invalid if there is no movposcomb of tomove matching - * back/fwd, or EC_MovFeatTooLate if the maxdelay_ms could not be - * met because of lack of ability to change points. + * On successful exit, tomove->moving=1 and tomove->motion!=0; from + * then on until ->moving becomes 0, movposcomb may not reflect the + * real physical state of the layout; instead it gives only + * information about the target configuration. (Choreographers are + * allowed to know implementation details and may know what + * movposcomb means for certain segments depending on the movement + * requested.) */ -ErrorCode -movpos_change_bysegs(Segment *back, Segment *tomove, Segment *fwd, - int maxdelay_ms, MovPosChange *reservation); - /* back and fwd may be 0 if we don't care (and must be if there is - * no track in that direction. It is immaterial which is back and - * which fwd. +ErrorCode movpos_findcomb_bysegs(Segment *back, Segment *move, Segment *fwd, + MovPosComb startpoint, MovPosComb *chosen_r); + /* Looks for a movposcomb of move where the adjacent segment in one + * direction is back and the other fwd. back and fwd may be 0 if we + * don't care (and must be if there is no track in that direction. + * It is immaterial which is back and which fwd. + * + * The returned movposcomb is the `best' one which is the one + * closest to the starting point (and if that is not unique, the + * lowest-numbered). + * + * startpoint=-1 means starting with current state. chosen_r may be 0. */ ErrorCode -movpos_reserve(Segment *move, int maxdelay_ms, MovPosChange **res_r); - /* Returns EC_MovFeatTooLate if the maxdelay_ms could not be met. - * The resulting MovPosChange is a reservation which is guaranteed - * to be useable successfully later for any movpos_change for - * the same move and a greater or equal maxdelay_ms. On successful - * exit *res_r is set to non-0. On transition out of Sta_Run, - * all unconfirmed reservations must be unreserved before - * points_all_abandon is called (see startup.c); +movpos_reserve(Segment *move, int maxdelay_ms, MovPosChange **res_r, + MovPosComb target, MovPosComb startpoint /*as for findcomb*/); + /* The resulting MovPosChange is a reservation which is guaranteed + * to be useable successfully later for any movpos_change for the + * same move, target and startpoing and a greater or equal + * maxdelay_ms. On successful exit *res_r is set to non-0. + * + * On transition out of Sta_Run, all unconfirmed reservations must + * be unreserved before points_all_abandon is called (see + * startup.c); */ void movpos_unreserve(MovPosChange *reservation /* 0 ok */); @@ -178,6 +185,18 @@ MovPosComb movpos_poscomb_actual(Segment *seg); * -1 means not known or cannot be represented as a MovPosComb */ +MovPosComb movpos_change_intent(MovPosChange *chg); + /* Returns the target value supplied to _reserve or _change */ + + /* Error returns from movpos calls + * + * EC_Invalid there is no movposcomb of tomove matching back/fwd + * EC_MovFeatTooLate maxdelay_ms could not be met + * EC_MovFeatReservationInapplicable + * reservation not compatible with change request + * and/or current situation + */ + /*========== speedmgr.c ==========*/ void speedmanager_speedchange_request(Train *tra, long speed);