7 #include "layoutinfo.h"
10 static void seg_clear_stale(SegmentState *seg) {
11 if (!seg->tr_updated) {
13 seg->until_here= seg->until_detect= 0;
20 /* modified in place by lay_train_pass: */
22 int invert_count[1]; /* count of (switchable) segments,
23 * invert_count[0]: inverted from train's pov
24 * iff train is backwards (ie, train not inverted)
25 * invert_count[1]: train is inverted
26 * set to -1 if any unswitchable is the other way */
27 SegmentNum invert_forcer; /* the unswitchable which forces */
30 static void lay_train_pass(LayTrainState *l,
31 TrackLocation tloc, long advance,
32 long speed, unsigned backwards,
33 unsigned check_clash) {
34 State *s= &safety_state;
37 const SegmentInfo *segi;
38 long overall, remain, dist_until, time_until;
39 int *invert_likehere, train_inverted_here;
40 TrainState *tra= &s->trains[l->tran];
44 segn= tra->foredetect;
45 seg= &s->segments[segn];
47 remain= overall= advance + speed * SPEED_CLEAR_MULT;
51 seg= &s->segments[segn];
52 segi= &info_segments[segn];
55 if (seg->tr_updated) {
56 l->ec= safety_problem(l->tran, tloc.segn, "self-collision");
60 if (seg->owner != l->tran) {
61 l->ec= safety_problem(l->tran, tloc.segn, "collision with %s",
62 info_trains[seg->owner].pname);
70 seg->tr_backwards= tloc.backwards ^ backwards;
74 train_inverted_here= seg->seg_inverted ^ seg->tr_backwards;
75 invert_likehere= &l->invert_count[train_inverted_here];
77 if (segi->invertible) {
78 if (*invert_likehere >= 0)
81 if (*invert_likehere < 0) {
82 l->ec= safety_problem(l->tran, NOTA(Segment), "train requires"
83 " noninvertible segments with opposite polarity:"
84 " @%s, @%s", segi->pname,
85 info_segments[l->invert_forcer].pname);
88 assert(!seg->seg_inverted);
90 l->invert_count[!train_inverted_here]= -1;
91 l->invert_forcer= segn;
94 dist_until= (overall - remain) - advance;
95 time_until= !speed ? 0 : SPEED_CALC_TIME(speed, dist_until, DOWN);
96 *(check_clash ? &seg->until_here : &seg->until_detect)= time_until;
99 trackloc_further(&tloc, &remain);
103 static void lay_train_inversions(LayTrainState *l) {
104 State *s= &safety_state;
107 const SegmentInfo *segi;
108 int train_be_inverted, seg_be_inverted;
112 train_be_inverted= l->invert_count[1] > l->invert_count[0];
113 assert(l->invert_count[train_be_inverted] >= 0);
115 actual_inversions_start();
117 for (segn=0, seg=s->segments, segi=info_segments;
118 segn <= NUM_SEGMENTS;
120 if (!seg->tr_updated) continue;
121 assert(seg->owner == l->tran);
122 seg_be_inverted= train_be_inverted ^ seg->tr_backwards;
123 assert(!(seg_be_inverted && !segi->invertible));
124 seg->seg_inverted= seg_be_inverted;
125 actual_inversions_segment(segn);
127 actual_inversions_done();
130 static void lay_train_done(LayTrainState *l) {
131 State *s= &safety_state;
135 for (segn=0, seg=s->segments;
136 segn <= NUM_SEGMENTS;
138 if (seg->owner == l->tran) {
139 if (!seg->tr_updated) seg_clear_stale(seg);
142 assert(!seg->tr_updated);
143 assert(seg->until_detect >= seg->until_here);
147 static ErrorCode lay_train(TrainNum tran, long added_slop) {
148 State *s= &safety_state;
149 TrainState *tra= &s->trains[tran];
150 const TrainInfo *trai= &info_trains[tran];
154 long head, headslop, tail, taildet;
157 segn= tra->foredetect;
158 seg= &s->segments[segn];
161 tloc.into= tra->maxinto;
162 tloc.backwards= seg->tr_backwards ^ tra->backwards;
166 l.invert_count[0]= l.invert_count[1]= 0;
168 head= tra->backwards ? trai->tail : trai->head;
169 headslop= head + added_slop;
172 * update actual train location (train's head and future locations).
175 * update detection (future locations) only.
178 * train location (current location and tail)
180 * Clash checking is done in passes 1 and 3, including checking
181 * whether the train clashes with itself (ie, fail if we find
182 * segment with same train and tr_updated set).
184 lay_train_pass(&l, tloc, headslop, tra->speed, 0, 1);
185 lay_train_pass(&l, tloc, 0, tra->speed, 0, 0);
187 trackloc_reverse(&tloc);
188 seg->tr_updated= 0; /* we're about to do this one again */
189 tail= tra->backwards ? trai->head : trai->tail;
190 taildet= trai->detectable + tail;
192 lay_train_pass(&l, tloc, taildet, 0, 1, 1);
194 lay_train_inversions(&l);
200 static void setspeed(TrainNum tran, Speed newspeed) {
201 /* does not lay the train, caller must do that (or have done it,
202 * in which case they should already have set tra->speed). */
203 State *s= &safety_state;
204 TrainState *tra= &s->trains[tran];
206 tra->speed= newspeed;
207 actual_setspeed(tran);
208 speedmanager_speedchange_notify(tran);
211 void safety_notify_detection(SegmentNum segn) {
212 State *s= &safety_state;
213 SegmentState *seg= &s->segments[segn];
214 TrainNum tran= seg->owner;
215 TrainState *tra= &s->trains[tran];
220 safety_panic(NOTA(Train), segn, "unexpected detection");
222 if (!seg->until_detect)
227 tloc.backwards= seg->tr_backwards;
229 tra->foredetect= segn;
230 tra->maxinto= trackloc_remaininseg(&tloc);
232 if (seg->cm_autostop) {
233 if (tra->speed < AUTOSTOP_MAXSPEED &&
234 tra->maxinto > AUTOSTOP_UNCERTAINTY)
235 /* At some point we may need to allow more slop when the
236 * next segment is points than when this is the last segment
237 * (ie, just buffers next). */
238 tra->maxinto= AUTOSTOP_UNCERTAINTY;
243 tra->uncertainty= tra->maxinto;
245 ec= lay_train(tran, 0);
247 logmsg(ec, tran, segn, "emergency stop");
248 safety_emergencystop(tran);
252 void safety_emergencystop(TrainNum tran) {
253 State *s= &safety_state;
255 TrainState *tra= &s->trains[tran];
258 actual_emergencystop(tran);
259 ec= lay_train(tran, ESTOP_UNCERTAINTY);
260 if (ec) safety_panic(tran, NOTA(Segment), "emergency stop forbidden!");
261 speedmanager_speedchange_notify(tran);
264 void safety_requestspeed(TrainNum tran, long newspeed) {
265 State *s= &safety_state;
267 TrainState *tra= &s->trains[tran];
270 oldspeed= tra->speed;
271 tra->speed= newspeed;
273 ec= lay_train(tran, 0);
276 if (oldspeed && oldspeed < newspeed) {
277 logmsg(ec, tran, NOTA(Segment), "countermanded acceleration"
278 " from %ld to %ld", oldspeed, newspeed);
279 } else if (oldspeed) {
280 safety_panic(tran, NOTA(Segment), "deceleration forbidden!"
281 " (from %ld to %ld", oldspeed, newspeed);
283 logmsg(ec, tran, NOTA(Segment), "countermanded motion start");
285 setspeed(tran, oldspeed);
286 ec= lay_train(tran, 0);
288 safety_panic(tran, NOTA(Segment), "countermanding"
289 " speed change insufficient!");
293 setspeed(tran, newspeed);
298 printf("%d\n",(int)sizeof(State));