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
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
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,
-train santafe home X5 X6
+train santafe home -X5
+train shinkansen home -X9 -A5 -A6
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) */
if (!ec) {
move->moving= chg;
+ move->movposcomb= -1;
pt_check_action();
}
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];
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;
+ feat<movei->n_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;
tcomb<movei->n_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;
- feat<movei->n_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;
feat<movei->n_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; }
if (!res) return;
res->ki->destroy(res);
}
+
+MovPosComb movpos_poscomb_actual(Segment *seg) {
+ return seg->moving ? seg->moving->actual : seg->movposcomb;
+}
void persist_entrails_run_converter(void) {
TRA_IV;
SEG_IV;
+ MovPosComb report;
persist_mapread();
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");
#include "stastate.h"
void sta_startup(void);
+void sta_finalising_done(void);
void serial_moredata(PicInsn *buf);
extern StartupState sta_state;
void resolve_begin(void); /* from resolve.c */
int resolve_complete(void);
+void resolve_motioncheck(void);
/*---------- from/for record.c and persist.c ----------*/
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;
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();
+}
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();
+}
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;
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;
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);
}
}
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");
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;
};
*/
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.
*
* 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.
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);
}
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);
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;
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;
/* 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) {
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");
}
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:
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);
}
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