From: ian Date: Sun, 13 Apr 2008 20:00:06 +0000 (+0000) Subject: new resolution arrangements X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ijackson/git?a=commitdiff_plain;h=3a24aa0a8c100945230507ebb1c5dd2745575aca;p=trains.git new resolution arrangements --- diff --git a/hostside/TODO b/hostside/TODO index 90e7b6f..8d7b959 100644 --- a/hostside/TODO +++ b/hostside/TODO @@ -1,10 +1,6 @@ before can test commands for speed manager - write trivial initial settlement to get data array right - write out layout data on crash check that everything in Train and Segment is init'd - do lay_train in resolution, or moral equivalent - set points under existing trains according to existing movposcomb dunno but maybe before can test wiring to gui display @@ -12,10 +8,6 @@ dunno but maybe before can test things not yet considered at all in safety code coming up against points the wrong way min. curve specifications - crossovers - -initialise safety_state with appropriate stuff - make safety stop not be estop diff --git a/hostside/commands.c b/hostside/commands.c index 1c9953a..f6a638c 100644 --- a/hostside/commands.c +++ b/hostside/commands.c @@ -202,7 +202,7 @@ static void cmd_movfeat(ParseState *ps, const CmdInfo *ci) { if (!ps_neednoargs(ps)) return; - ec= movpos_change(back,move,fwd,ms,0); + ec= movpos_change_bysegs(back,move,fwd,ms,0); if (ec) { badcmd(ps,"movfeat %s %s %s %ld %s", back->i->pname, move->i->pname, fwd->i->pname, diff --git a/hostside/homes.record b/hostside/homes.record index 284fbf2..808cb37 100644 --- a/hostside/homes.record +++ b/hostside/homes.record @@ -1 +1,2 @@ -train santafe home X5 X6 +train santafe home -X5 +train shinkansen home -X9 -A5 -A6 diff --git a/hostside/movpos.c b/hostside/movpos.c index 6abf02b..98c3dc7 100644 --- a/hostside/movpos.c +++ b/hostside/movpos.c @@ -35,18 +35,18 @@ typedef struct MovPosChange { /* valid in: filled in by and when: */ MovPosComb actual; /* CD see below */ /* kind-specific data follows */ /* varies kind-specific code, varies */ } Change; - /* `actual' contains the kind's record of the physical state. It is - * initialised by indep (just before confirm) from move->moving->actual - * or move->movposcomb as the case may be. It should be updated - * by the kind, since it is used by indep for calculating the number - * and identities of the features which may need to change when a - * new move request is intended to replace an existing one - ie, the - * contents of the motions[] provided to a subsequent confirm(). - * So while a change is Confirmed, the physical state is recorded - * only in the relevant change, and not in the segment's movposcomb. - * Once a change goes to Confirmed, the indep code never untangles it - * so the kind can manage the proper transition. - */ + /* `actual' contains the kind's public opinion about the physical + * state. It is initialised by indep (just before confirm) from + * move->moving->actual or move->movposcomb as the case may be. It + * should be updated by the kind, since it is used by indep for + * calculating the number and identities of the features which may + * need to change when a new move request is intended to replace an + * existing one - ie, the contents of the motions[] provided to a + * subsequent confirm(). So while a change is Confirmed, the + * physical state is recorded only in the relevant change, and not + * in the segment's movposcomb. Once a change goes to Confirmed, + * the indep code never untangles it so the kind can manage the + * proper transition. */ struct KindInfo { Change *(*allocate)(int alloc_motions); /* U->A (always succeeds) */ @@ -355,6 +355,7 @@ fprintf(stderr," point confirm\n"); if (!ec) { move->moving= chg; + move->movposcomb= -1; pt_check_action(); } @@ -372,7 +373,10 @@ static void point_destroy(Change *chg) { /* X->XA and then free it */ static void pt_check_action(void) { PicInsn piob; - if (!pt_confirmed.n) return; + if (!pt_confirmed.n) { + if (sta_state == Sta_Finalising) resolve_motioncheck(); + return; + } PointReq *r= pt_confirmed.l[0]; @@ -475,73 +479,94 @@ static Change *mp_allocate(const KindInfo *ki, Segment *move, return chg; } -ErrorCode -movpos_change(Segment *back, Segment *move, Segment *fwd, - int maxdelay_ms, MovPosChange *chg) { +static int movpos__evaluate_target(Segment *move, MovPosComb target) { + /* returns number of features which have to change to reach target */ const SegmentInfo *movei= move->i; - const SegPosCombInfo *pci; + int feat, tchanges; + MovPosComb actual; const MovFeatInfo *feati; - int feat; - MovPosComb actual, tcomb, bestcomb=0; - int tchanges, bestchanges=INT_MAX; - ErrorCode ec; - MovFeatKind kind= mfk_none; - if (move->moving) { - kind= move->moving->ki - methodinfos; - actual= move->moving->actual; - } else { - actual= move->movposcomb; - } + actual= movpos_poscomb_actual(move); + + for (feat=0, feati=movei->movfeats, tchanges=0; + featn_movfeats; + feat++) + if (actual<0 || (target - actual) / feati->weight % feati->posns) + tchanges++; + return tchanges; +} + +ErrorCode +movpos_change_bysegs(Segment *back, Segment *move, Segment *fwd, + int maxdelay_ms, MovPosChange *chg) { + const SegmentInfo *movei= move->i; + MovPosComb tcomb, bestcomb=0; + int tchanges, bestchanges=INT_MAX; + const SegPosCombInfo *pci; -fprintf(stderr,"moving %s\n",move->i->pname); + //fprintf(stderr,"moving %s\n",move->i->pname); for (tcomb=0, pci=movei->poscombs; tcombn_poscombs; tcomb++, pci++) { -fprintf(stderr," tcomb %lu\n",tcomb); + //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:"-" - ); + //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"); + //fprintf(stderr," several feats\n"); /* we have to search for the one which is least effort, then */ - for (feat=0, feati=movei->movfeats, tchanges=0; - featn_movfeats; - feat++) - if (actual<0 || (tcomb - actual) / feati->weight % feati->posns) - tchanges++; + tchanges= movpos__evaluate_target(move, tcomb); if (tchanges > bestchanges) continue; } else { tchanges= 1; } -fprintf(stderr," best %lu changes %d\n",tcomb,tchanges); + //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) { ec= EC_Invalid; goto x; } + //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); +} + +ErrorCode movpos_change(Segment *move, MovPosComb target, + int maxdelay_ms, MovPosChange *chg) { + const SegmentInfo *movei= move->i; + const MovFeatInfo *feati; + int feat; + MovPosComb actual; + ErrorCode ec; + MovFeatKind kind= mfk_none; + + if (move->moving) { + kind= move->moving->ki - methodinfos; + actual= move->moving->actual; + } else { + actual= move->movposcomb; + } { int n_motions=0; Motion motions[movei->n_movfeats]; -fprintf(stderr," motions... best=%lu actual=%ld\n",bestcomb,actual); +fprintf(stderr," motions... best=%lu actual=%ld\n",target,actual); for (feat=0, feati=movei->movfeats; featn_movfeats; feat++, feati++) { fprintf(stderr," checking %s w=%lu posns=%d\n", feati->pname,feati->weight,(int)feati->posns); - if (actual>=0 && !((bestcomb - actual) / feati->weight % feati->posns)) + if (actual>=0 && !((target - actual) / feati->weight % feati->posns)) continue; - MovPosComb posn= bestcomb / feati->weight % feati->posns; + MovPosComb posn= target / feati->weight % feati->posns; fprintf(stderr," motion %s %lu kind=%d\n",feati->pname,posn,kind); if (kind) { if (feati->kind != kind) { ec= EC_MovFeatKindsCombination; goto x; } @@ -606,3 +631,7 @@ void movpos_unreserve(MovPosChange *res) { if (!res) return; res->ki->destroy(res); } + +MovPosComb movpos_poscomb_actual(Segment *seg) { + return seg->moving ? seg->moving->actual : seg->movposcomb; +} diff --git a/hostside/persist.c b/hostside/persist.c index f2abe17..1335bc7 100644 --- a/hostside/persist.c +++ b/hostside/persist.c @@ -365,6 +365,7 @@ static void persist_mapread(void) { void persist_entrails_run_converter(void) { TRA_IV; SEG_IV; + MovPosComb report; persist_mapread(); @@ -382,6 +383,11 @@ void persist_entrails_run_converter(void) { continue; printf("seg %s has %s%s\n", segi->pname, seg->tr_backwards ? "-" : "", seg->owner->pname); + + if (segi->n_poscombs>1 && + (report= movpos_poscomb_actual(seg)) >=0 && + report < segi->n_poscombs) + printf("seg %s at %s\n", segi->pname, segi->poscombs[report].pname); } if (ferror(stdout) || fflush(stdout)) diee("entrails converter: stdout write error"); diff --git a/hostside/realtime.h b/hostside/realtime.h index 15007c9..8bc4a3b 100644 --- a/hostside/realtime.h +++ b/hostside/realtime.h @@ -110,6 +110,7 @@ extern int picio_send_noise; #include "stastate.h" void sta_startup(void); +void sta_finalising_done(void); void serial_moredata(PicInsn *buf); extern StartupState sta_state; @@ -117,6 +118,7 @@ extern const char *const stastatelist[]; void resolve_begin(void); /* from resolve.c */ int resolve_complete(void); +void resolve_motioncheck(void); /*---------- from/for record.c and persist.c ----------*/ diff --git a/hostside/resolve.c b/hostside/resolve.c index 317f9ac..c527bd8 100644 --- a/hostside/resolve.c +++ b/hostside/resolve.c @@ -213,6 +213,11 @@ int resolve_complete(void) { goto not_3a; } + if (d->movposcomb < 0) { + oprintf(UPO, "resolving track-unknown-position\n"); + goto not_3a; + } + if (t->resolution == RR_E) /* we added it in this sweep and have found another d */ goto already_3a; @@ -279,19 +284,74 @@ int resolve_complete(void) { if (phase<2) continue; - oprintf(UPO, "resolving inexplicable @%s\n", di->pname); + oprintf(UPO, "resolution inexplicable @%s\n", di->pname); d->res_detect= 0; problems++; } } - if (problems) oprintf(UPO,"resolve problems %d\n",problems); + FOR_SEGMENT(d,NOOP,NOOP) { + d->tr_updated= 0; + d->cm_autostop= 0; + + MovPosComb target= -1; + + if (d->owner) { + d->until_detect= 1; + switch (d->owner->resolution) { + case RR_H: + d->tr_backwards= d->ho_backwards; + target= 0; /* a bit kludgey */ + break; + case RR_E: + target= d->movposcomb; + d->tr_backwards ^= d->owner->backwards; + /* ... we set d->owner->backwards to 0 below, so cancel that out */ + break; + default: + abort(); + } + } + if (d->i->n_poscombs>1) { + d->movposcomb= -1; + if (target >= 0) { + ErrorCode ec= movpos_change(d,target,INT_MAX,0); + if (ec) { + oprintf(UPO, "resolution movpos-change-failed %s/%s %s\n", + d->i->pname, d->i->poscombs[target].pname, + errorcodelist[ec]); + problems++; + } + } + } + } - FOR_SEGMENT(d,NOOP,NOOP) - d->tr_updated= d->res_detect= 0; + FOR_TRAIN(t,NOOP,NOOP) { + if (t->resolution == RR_E) + t->backwards= 0; + } - if (problems) + if (problems) { + oprintf(UPO,"resolution problems (%d)\n",problems); return -1; + } return 0; } + +void resolve_motioncheck(void) { + SEG_IV; + assert(sta_state == Sta_Finalising); + + FOR_SEG + if (seg->moving) return; + + FOR_SEG { + if (seg->res_detect) { + seg->res_detect= 0; + safety_notify_detection(seg); + } + } + + sta_finalising_done(); +} diff --git a/hostside/retransmit.c b/hostside/retransmit.c index d6f1648..52aaa9c 100644 --- a/hostside/retransmit.c +++ b/hostside/retransmit.c @@ -137,3 +137,13 @@ void retransmit_urgent_cancel(RetransmitUrgentNode *urg) { DLIST2_REMOVE(speedies[urg->u.ix].queue,urg,u.queue); retransmit_relaxed_cancel(&urg->u.relaxed); } + + +void on_pic_nmradone(const PicInsnInfo *pii, const PicInsn *pi, int objnum) { + if (!objnum) die("PIC sent NUL!"); + if (sta_state <= Sta_Settling) return; + if (sta_state != Sta_Run) die("PIC sent NMRADONE in Resolving"); + + while (objnum--) + retransmit_something(); +} diff --git a/hostside/safety.c b/hostside/safety.c index c4bb33b..7f18853 100644 --- a/hostside/safety.c +++ b/hostside/safety.c @@ -30,23 +30,10 @@ typedef struct { Segment *invert_forcer; /* the unswitchable which forces */ } LayTrainState; -static void lay_train_check_clash(LayTrainState *l, Segment *check, - Segment *report) { - const char *exi1="", *exi2=""; - if (check!=report) { exi1= " at "; exi2= check->i->pname; } - - if (seg->tr_updated) { - l->ec= safety_problem(l->tra, report, "self-collision%s%s", exi1,exi2); - return; - } - if (seg->owner) { - if (seg->owner != l->tra) { - l->ec= safety_problem(l->tra, tloc.seg, "collision with %s" - "%s%s", seg->owner->pname, exi1,exi2); - return; - } - } -} +#define INTERFERING_MOVPOSCOMB(seg,segi) \ + ((seg)->moving || \ + (seg)->movposcomb < 0 || \ + (segi)->interferes_movposcomb_map & (1u << (seg)->movposcomb)) static Segment *interferes(Segment *base) { const SegmentInfo *basei, *interi; @@ -54,28 +41,46 @@ static Segment *interferes(Segment *base) { Segment *inter; basei= base->i; - intern= seg->i->interferes; + intern= basei->interferes; if (!SOMEP(intern)) return 0; - if (!(segi->interferes_movposcomb_map & (1u << base->movposcomb))) - return 0; + if (!INTERFERING_MOVPOSCOMB(base,basei)) return 0; inter= &segments[intern]; interi= &info_segments[intern]; - assert(base == &info_segments[interi->interferes]); - if (!inter->moving && - !(interi->interferes_movposcomb_map & (1u << inter->movposcomb))) - return 0; + assert(basei == &info_segments[interi->interferes]); + if (!INTERFERING_MOVPOSCOMB(inter,interi)) + return 0; return inter; } +static void lay_train_check_clash(LayTrainState *l, Segment *check, + Segment *report) { + const char *exi1="", *exi2=""; + if (check!=report) { exi1= " at "; exi2= check->i->pname; } + + if (check->tr_updated) { + l->ec= safety_problem(l->tra, report, "self-collision%s%s", exi1,exi2); + return; + } + if (check->owner) { + if (check->owner != l->tra) { + l->ec= safety_problem(l->tra, report, "collision with %s" + "%s%s", check->owner->pname, exi1,exi2); + return; + } + } + if (check->movposcomb < 0) + l->ec= safety_problem(l->tra, report, "track route not set"); +} + static void lay_train_pass(LayTrainState *l, TrackLocation tloc, long advance, long speed, unsigned backwards, unsigned check_clash) { - Segment *seg; + Segment *seg, *inter; long overall, remain, dist_until, time_until; int *invert_likehere, train_inverted_here; Train *tra= l->tra; @@ -91,7 +96,7 @@ static void lay_train_pass(LayTrainState *l, if (check_clash) { lay_train_check_clash(l,seg,seg); - inter= interfere_physical(seg); + inter= interferes(seg); if (inter) lay_train_check_clash(l,inter,seg); } @@ -242,7 +247,7 @@ void safety_notify_detection(Segment *seg) { } tra->uncertainty= tra->maxinto; - if (!tra->estopping) { + if (!(tra->estopping || tra->speed==0)) { ec= lay_train(tra, 0); if (ec) { logmsg(ec,tra,seg->i, "emergency stop"); diff --git a/hostside/safety.h b/hostside/safety.h index 518a54b..a3b54f2 100644 --- a/hostside/safety.h +++ b/hostside/safety.h @@ -81,7 +81,7 @@ struct Segment { res_detect:1; /* detection noticed here during resolution */ TimeInterval until_here, /* ) nonnegative; */ /* ) always valid but */ until_detect; /* ) 0 if already */ /* ) meaningful iff owner */ - MovPosComb movposcomb; /* -1 means not known */ + MovPosComb movposcomb; /* -1 means not known or moving */ MovPosChange *moving; /* non-0 iff feature(s) have been told to change */ const SegmentInfo *i; }; @@ -134,13 +134,9 @@ void safety_notify_detection(Segment *seg); */ ErrorCode -movpos_change(Segment *back, Segment *tomove, Segment *fwd, +movpos_change(Segment *tomove, MovPosComb target, 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. - * - * If segment has already been requested to change, an attempt is + /* If segment has already been requested to change, an attempt is * made to replace that change with the new request; if this is not * successful then the existing change will still happen. * @@ -159,6 +155,14 @@ movpos_change(Segment *back, Segment *tomove, Segment *fwd, * met because of lack of ability to change points. */ +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_reserve(Segment *move, int maxdelay_ms, MovPosChange **res_r); /* Returns EC_MovFeatTooLate if the maxdelay_ms could not be met. @@ -172,6 +176,11 @@ movpos_reserve(Segment *move, int maxdelay_ms, MovPosChange **res_r); void movpos_unreserve(MovPosChange *reservation); +MovPosComb movpos_poscomb_actual(Segment *seg); + /* gives actual current position as published by movfeatkind + * -1 means not known or cannot be represented as a MovPosComb + */ + /*========== speedmgr.c ==========*/ void speedmanager_speedchange_request(Train *tra, long speed); diff --git a/hostside/startup.c b/hostside/startup.c index f6a318c..5f55c13 100644 --- a/hostside/startup.c +++ b/hostside/startup.c @@ -47,6 +47,7 @@ static void initial_ping(void) { } void sta_startup(void) { sta_goto(Sta_Flush); } +void sta_finalising_done(void) { sta_goto(Sta_Run); } static void sta_goto(StartupState new_state) { toev_stop(&sta_toev); @@ -68,12 +69,13 @@ static void sta_goto(StartupState new_state) { case Sta_Fault: break; case Sta_Settling: sta_toev.duration= 750; break; case Sta_Resolving: sta_toev.duration= 500; break; + case Sta_Finalising: break; case Sta_Run: break; } if (new_state < Sta_Run) choreographers_all_abandon(); - if (new_state < Sta_Resolving) + if (new_state < Sta_Finalising) points_all_abandon(); piob.l= 0; @@ -88,10 +90,13 @@ static void sta_goto(StartupState new_state) { points_turning_on(); enco_pic_on(&piob); break; - case Sta_Run: + case Sta_Finalising: if (resolve_complete() <0) /* in this case, we get stuck - user has to power cycle the layout */ return; + /* resolve_motioncheck will move us to Run eventually, we hope */ + break; + case Sta_Run: persist_install(); retransmit_start(); break; @@ -104,6 +109,7 @@ static void sta_goto(StartupState new_state) { /* notify various people: */ oprintf(UPO, "stastate %s\n", stastatelist[sta_state]); /* ... add others here. */ + if (sta_state == Sta_Finalising) resolve_motioncheck(); } void serial_moredata(PicInsn *buf) { @@ -194,7 +200,8 @@ void on_pic_fault(const PicInsnInfo *pii, const PicInsn *pi, int objnum) { void on_pic_wtimeout(const PicInsnInfo *pii, const PicInsn *pi, int objnum) { if (sta_state <= Sta_Settling) return; - if (sta_state == Sta_Resolving) die("PIC sent WTIMEOUT in Resolving"); + if (sta_state == Sta_Resolving || sta_state == Sta_Finalising) + die("PIC sent WTIMEOUT in Resolving or Finalising"); oprintf(UPO, "warning watchdog \"PIC watchdog timer triggered\"\n"); } @@ -222,9 +229,11 @@ static SegmentNum on_pic_detect_prep(int detyn, int objnum) { void on_pic_detect1(const PicInsnInfo *pii, const PicInsn *pi, int objnum) { SegmentNum segn; Segment *seg; + const char *pname; segn= on_pic_detect_prep(1,objnum); seg= &segments[segn]; + pname= info_segments[segn].pname; switch (sta_state) { case Sta_Flush: @@ -232,25 +241,22 @@ void on_pic_detect1(const PicInsnInfo *pii, const PicInsn *pi, int objnum) { case Sta_Ping: case Sta_Fault: case Sta_Settling: - oprintf(UPO, "warning fixme ignored non-Run detection @%s\n", - info_segments[segn].pname); break; - case Sta_Resolving: seg->res_detect= 1; break; - case Sta_Run: safety_notify_detection(seg); break; + case Sta_Resolving: + seg->res_detect= 1; + break; + case Sta_Finalising: + if (!seg->res_detect) { + oprintf(UPO, "resolution new-detection-in-finalising @%s\n", pname); + sta_goto(Sta_Settling); + } + break; + case Sta_Run: + safety_notify_detection(seg); + break; } } -/*---------- fixme move these to where they want to go ----------*/ - -void on_pic_nmradone(const PicInsnInfo *pii, const PicInsn *pi, int objnum) { - if (!objnum) die("PIC sent NUL!"); - if (sta_state <= Sta_Settling) return; - if (sta_state != Sta_Run) die("PIC sent NMRADONE in Resolving"); - - while (objnum--) - retransmit_something(); -} - void on_pic_detect0(const PicInsnInfo *pii, const PicInsn *pi, int objnum) { on_pic_detect_prep(0,objnum); } diff --git a/hostside/stastate.h.gen b/hostside/stastate.h.gen index faa07fb..91a2405 100755 --- a/hostside/stastate.h.gen +++ b/hostside/stastate.h.gen @@ -3,14 +3,14 @@ set -e Sta () { l="$l $1"; } - # sta_toev ping_toev - Sta Flush # R 300 I ? - Sta Off # I ? I ? - Sta Ping # I ? I ? - Sta Fault # I ? R set - Sta Settling # I ? R set - Sta Resolving # I ? R set - Sta Run # I ? R set + Sta Flush + Sta Off + Sta Ping + Sta Fault + Sta Settling + Sta Resolving + Sta Finalising + Sta Run echo 'typedef enum {' for s in $l; do echo " Sta_$s,"; done