8 #include "../layout/layout-data.h"
9 #include "layoutinfo.h"
10 #include "errorcodes.h"
12 /*========== more basic types etc. ==========*/
14 typedef short TimeInterval; /*ms*/
16 /*---------- units and scales ----------*/
19 * Distances are in mm.
21 * Speeds are in fixed point: unit is 1/SPEED_UNIT m/s
23 * To calculate with speeds and times without using floating point
24 * it turns out that we can cope with distances of up to
25 * 2^(31-SPEED_SHIFT) mm
28 #define SPEED_SHIFT 16 /* units of 15um/s, max distance 2^15mm =~ 32m */
29 #define SPEED_UNIT (1L<<SPEED_SHIFT) /* ms/mm */
31 /*========== state of the layout ==========*/
33 typedef struct MovPosChange MovPosChange;
38 TimeInterval upwait, downwait; /* between this insn and next one */
42 /* Configuration (excluding speed curve): */
45 Distance head, detectable, tail;
48 struct Segment *foredetect; /* train's detectable part is at most maxinto */
49 Distance maxinto, uncertainty; /* into foredetect but train may be */
50 unsigned /* uncertainty less far advanced */
51 backwards:1, /* train is moving backwards wrt its own front and back */
54 estopping:1, /* set and cleared by speed.c */
56 /* Startup resolution (resolve.c): */
58 Speed speed; /* when accelerating/decelerating, is maximum at this moment */
61 int target; /* index into curve */
62 int commanded; /* when ac-/decel, eq last value xmitted */
64 RetransmitUrgentNode rn;
66 /* Configuration for acceleration: */
67 SpeedCurveEntry *curve;
73 Train *owner; /* or 0 */
74 Train *home; /* or 0 */
76 tr_backwards:1, /* train's motion is (would be) backwards wrt track */
77 ho_backwards:1, /* home train has its front and rear backwards wrt track */
78 cm_autostop:1, /* train should stop on detection */
79 seg_inverted:1, /* polarity is inverted */
80 tr_updated:1, /* for use by safety.c:lay_train etc.; otherwise 0 */
81 res_detect:1; /* detection noticed here during resolution */
82 TimeInterval until_here, /* ) nonnegative; */ /* ) always valid but */
83 until_detect; /* ) 0 if already */ /* ) meaningful iff owner */
84 MovPosComb movposcomb; /* -1 means not known */
85 MovPosChange *moving; /* non-0 iff feature(s) have been told to change */
89 /*========== embed.c ==========*/
90 /* surrounds the algorithms and machinery in a program: logging, error
91 * handling, arg parsing, etc.
94 void vlogmsg(ErrorCode ec, Train *tra, const SegmentInfo *segi,
95 const char *fmt, va_list al) __attribute__((format(printf,4,0)));
96 void logmsg(ErrorCode ec, Train *tra, const SegmentInfo *segi,
97 const char *fmt, ...) __attribute__((format(printf,4,5)));
99 void safety_vpanic(Train *tra, Segment *seg, const char *fmt, va_list al)
100 __attribute__((format(printf,3,0),noreturn));
101 void safety_panic(Train *tra, Segment *seg, const char *fmt,...)
102 __attribute__((format(printf,3,4),noreturn));
104 ErrorCode safety_problem(Train *tra, Segment *seg, const char *fmt, ...)
105 __attribute__((format(printf,3,4)));
106 /* simple wrapper around vlogmsg; implies and returns EC_Safety */
108 /*========== safety.c ==========*/
110 * safety.c is responsible for ensuring that things don't go
111 * physically wrong (eg, collisions, derailments, short circuits,
115 void safety_emergencystop(Train*);
116 /* Callable directly in response to application command. */
118 ErrorCode safety_requestspeed(Train* tra, long newspeed);
119 /* To be called only by the speed manager, thus indirectly from
120 * user request. Any error will have been logged. On success,
121 * ->speed has been updated. Speed manager is responsible for
122 * calling actual_setspeed.
125 void safety_setdirection(Train* tra, int sense_fixme_define_this_properly);
127 void safety_notify_detection(Segment *seg);
128 /* Called by startup.c when new train detection occurs in state Run. */
130 /*========== movpos.c ==========*/
132 * movpos.c manages the CDU and points and other moveable features.
133 * Only safety.c should request changes.
137 movpos_change(Segment *back, Segment *tomove, Segment *fwd,
138 int maxdelay_ms, MovPosChange *reservation);
139 /* back and fwd may be 0 if we don't care (and must be if there is
140 * no track in that direction. It is immaterial which is back and
143 * If segment has already been requested to change, an attempt is
144 * made to replace that change with the new request; if this is not
145 * successful then the existing change will still happen.
147 * reservation should be 0, or the results of movpos_reservechange
148 * on the same move. It is always consumed, even on error.
150 * On successful exit, tomove->moving is set non-0; from then on
151 * until ->moving becomes 0, movposcomb may not reflect the real
152 * physical state of the layout; instead it gives only information
153 * about the target configuration. (Choreographers are allowed to
154 * know implementation details and may know what movposcomb means
155 * for certain segments depending on the movement requested.)
157 * Returns EC_Invalid if there is no movposcomb of tomove matching
158 * back/fwd, or EC_MovFeatTooLate if the maxdelay_ms could not be
159 * met because of lack of ability to change points.
163 movpos_reserve(Segment *move, int maxdelay_ms, MovPosChange **res_r);
164 /* Returns EC_MovFeatTooLate if the maxdelay_ms could not be met.
165 * The resulting MovPosChange is a reservation which is guaranteed
166 * to be useable successfully later for any movpos_change for
167 * the same move and a greater or equal maxdelay_ms. On successful
168 * exit *res_r is set to non-0. On transition out of Sta_Run,
169 * all unconfirmed reservations must be unreserved before
170 * points_all_abandon is called (see startup.c);
173 void movpos_unreserve(MovPosChange *reservation);
175 /*========== speedmgr.c ==========*/
177 void speedmanager_speedchange_request(Train *tra, long speed);
178 /* Callable directly in response to application command.
179 * speed may be LONG_MAX to mean maximum permitted.
182 void speedmanager_emergencystop(Train *tra);
183 void speedmanager_autostop(Train *tra);
184 /* These are responsible for calling actual_setspeed.
186 * After speedmanager_autostop, ->speed will have been updated to a
187 * new desired speed. If it is 0 the train was going slowly and has
188 * been instructed to stop right now.
191 void speedmanager_reset_train(Train *tra);
193 /*========== actual.c ==========*/
194 /* actual.c should only be called from safety.c.
195 * It is responsible for communicating with the PICs, including
196 * repeating the NMRA commands and redacting detection information.
198 * In general, when State information is shared between actual.c
199 * and safety.c, safety.c is responsible for modifying State, and
200 * will then call an actual_... function to notify the change.
203 void actual_setspeed(Train *tra);
204 void actual_emergencystop(Train *tra);
206 void actual_inversions_start(void);
207 void actual_inversions_segment(Segment *seg);
208 void actual_inversions_done(void);
209 /* safety.c will call these in this order: first start, then segment
210 * for 0 or more segments (whose s.segments[segn].seg_inverted may
211 * or may not have changed), and finally done. At done, the PICs
212 * should be told to (de)invert the segments as specified. */
215 * Entrypoints are: Called from, and as a result of:
216 * actual_setspeed safety.c
217 * actual_emergencystop safety.c
220 /*========== utils.c ==========*/
222 typedef struct TrackLocation TrackLocation;
223 struct TrackLocation { /* transparent, and manipulable by trackloc_... fns */
224 Segment *seg; /* current segment */
225 long into; /* distance from start of segment */
226 unsigned backwards:1; /* if 1, into is positive and measured from end */
229 long trackloc_remaininseg(const TrackLocation *tloc);
230 /* Returns dist that tloc can advance before it goes into next segment. */
232 void trackloc_further(TrackLocation *tloc, long *remain_io);
233 /* Advances tloc, decrementing *remain_io, until either
234 * *remain_io becomes zero, or tloc->segn changes. */
236 void trackloc_reverse(TrackLocation *tloc);
237 /* Reverses tloc without changing its actual location. */
239 const SegPosCombInfo *trackloc_segposcomb(const TrackLocation *tloc);
240 const SegmentLinkInfo *trackloc_segmentlink(const TrackLocation *tloc,
241 const SegPosCombInfo *pci,
244 /*========== useful macros and declarations ==========*/
246 /*---------- looping over trains and segments ----------*/
248 #define SEGMENT_ITERVARS(seg) \
251 const SegmentInfo *seg##i
253 #define TRAIN_ITERVARS(tra) \
257 #define FOR_SEGMENT(seg, initx, stepx) \
258 for (seg##n=0, seg=segments, seg##i=info_segments; \
259 seg##n < NUM_SEGMENTS; \
260 seg##n++, seg++, seg##i++, stepx)
262 #define FOR_TRAIN(tra, initx, stepx) \
263 for (tra##n=0, tra=trains, initx; \
265 tra##n++, tra++, stepx)
267 #define SEG_IV SEGMENT_ITERVARS(seg)
268 #define FOR_SEG FOR_SEGMENT(seg,(void)0,(void)0)
270 #define TRA_IV TRAIN_ITERVARS(tra)
271 #define FOR_TRA FOR_TRAIN(tra,(void)0,(void)0)
273 /*---------- calculations with fixed point speeds ----------*/
275 #define DIVIDE_ROUNDING_UP(num,den) (((num) + (den) - 1) / (den))
276 #define DIVIDE_ROUNDING_DOWN(num,den) ( (num) / (den))
278 #define SPEED_CALC_TIME(speed,dist,round) \
279 DIVIDE_ROUNDING_##round((dist) * SPEED_UNIT, (speed))
281 #define SPEED_CALC_DIST(speed,time,round) \
282 DIVIDE_ROUNDING_##round((time) * (speed), SPEED_UNIT)
284 /*---------- safety margin parameters ----------*/
286 #define CLEAR_FORESIGHT_TIME 500 /*ms*/
287 #define AUTOSTOP_MAXSPEED ((50 * SPEED_UNIT)/1000) /* 50 mm/s */
288 #define AUTOSTOP_UNCERTAINTY 20 /*mm*/
289 #define ESTOP_UNCERTAINTY 300 /*mm*/
290 #define ESTOP_DEADTIME 2000 /*ms*/
292 #define SPEED_CLEAR_MULT SPEED_CALC_DIST(1,CLEAR_FORESIGHT_TIME,UP)