chiark / gitweb /
Merge and end branch-hostside-wip-2008-01-25 PROPERLY; cvs up -j branch-hostside...
[trains.git] / hostside / safety.h
1 /**/
2
3 #ifndef SAFETY_H
4 #define SAFETY_H
5
6 #include <stdarg.h>
7
8 #include "../layout/layout-data.h"
9 #include "layoutinfo.h"
10 #include "errorcodes.h"
11
12 /*========== more basic types etc. ==========*/
13
14 typedef short TimeInterval; /*ms*/
15
16 /*---------- units and scales ----------*/
17
18 /*
19  * Distances are in mm.
20  * Times are in ms.
21  * Speeds are in fixed point: unit is 1/SPEED_UNIT m/s
22  *
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
26  */
27
28 #define SPEED_SHIFT 16     /* units of 15um/s, max distance 2^15mm =~ 32m */
29 #define SPEED_UNIT (1L<<SPEED_SHIFT) /* ms/mm */
30
31 /*========== state of the layout ==========*/
32
33 typedef struct MovPosChange MovPosChange;
34
35 typedef struct {
36   int step;
37   long speed;
38   TimeInterval upwait, downwait; /* between this insn and next one */
39 } SpeedCurveEntry;
40
41 struct Train {
42   /* Configuration (excluding speed curve): */
43   char *pname;
44   int addr;
45   Distance head, detectable, tail;
46
47   /* Location: */
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 */
52
53   /* Speed: */
54     estopping:1, /* set and cleared by speed.c */
55
56   /* Startup resolution (resolve.c): */
57     resolution:2;
58   Speed speed; /* when accelerating/decelerating, is maximum at this moment */
59
60   struct {
61     int target; /* index into curve */
62     int commanded; /* when ac-/decel, eq last value xmitted */
63     TimeoutEvent more; 
64     RetransmitUrgentNode rn;
65
66     /* Configuration for acceleration: */
67     SpeedCurveEntry *curve;
68     int curvesz;
69   } accel;
70 };
71
72 struct Segment {
73   Train *owner;                                  /* or 0 */
74   Train *home;                                   /* or 0 */
75   unsigned
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;
85   MovPosChange *moving; /* non-0 iff feature(s) have been told to change */
86   const SegmentInfo *i;
87 };
88
89 extern int n_trains;
90 extern Train *trains;
91 extern Segment *segments;
92
93 /*========== embed.c ==========*/
94 /* surrounds the algorithms and machinery in a program: logging, error
95  * handling, arg parsing, etc.
96  */
97
98 void vlogmsg(ErrorCode ec, Train *tra, const SegmentInfo *segi,
99              const char *fmt, va_list al) __attribute__((format(printf,4,0)));
100 void logmsg(ErrorCode ec, Train *tra, const SegmentInfo *segi,
101             const char *fmt, ...) __attribute__((format(printf,4,5)));
102
103 void safety_vpanic(Train *tra, Segment *seg, const char *fmt, va_list al)
104      __attribute__((format(printf,3,0),noreturn));
105 void safety_panic(Train *tra, Segment *seg, const char *fmt,...)
106      __attribute__((format(printf,3,4),noreturn));
107
108 ErrorCode safety_problem(Train *tra, Segment *seg, const char *fmt, ...)
109      __attribute__((format(printf,3,4)));
110      /* simple wrapper around vlogmsg; implies and returns EC_Safety */
111
112 /*========== safety.c ==========*/
113 /*
114  * safety.c is responsible for ensuring that things don't go
115  * physically wrong (eg, collisions, derailments, short circuits,
116  * etc.).
117  */
118
119 void safety_emergencystop(Train*);
120   /* Callable directly in response to application command. */
121
122 ErrorCode safety_requestspeed(Train* tra, long newspeed);
123   /* To be called only by the speed manager, thus indirectly from
124    * user request.  Any error will have been logged.  On success,
125    * ->speed has been updated.  Speed manager is responsible for
126    * calling actual_setspeed.
127    */
128
129 void safety_setdirection(Train* tra, int sense_fixme_define_this_properly);
130
131 void safety_notify_detection(Segment *seg);
132   /* Called by startup.c when new train detection occurs in state Run. */
133
134 /*========== movpos.c ==========*/
135 /*
136  * movpos.c manages the CDU and points and other moveable features.
137  * Only safety.c should request changes.
138  */
139
140 ErrorCode
141 movpos_change(Segment *back, Segment *tomove, Segment *fwd,
142               int maxdelay_ms, MovPosChange *reservation);
143   /* back and fwd may be 0 if we don't care (and must be if there is
144    * no track in that direction.  It is immaterial which is back and
145    * which fwd.
146    *
147    * If segment has already been requested to change, an attempt is
148    * made to replace that change with the new request; if this is not
149    * successful then the existing change will still happen.
150    *
151    * reservation should be 0, or the results of movpos_reservechange
152    * on the same move.  It is always consumed, even on error.
153    *
154    * On successful exit, tomove->moving is set non-0; from then on
155    * until ->moving becomes 0, movposcomb may not reflect the real
156    * physical state of the layout; instead it gives only information
157    * about the target configuration.  (Choreographers are allowed to
158    * know implementation details and may know what movposcomb means
159    * for certain segments depending on the movement requested.)
160    *
161    * Returns EC_Invalid if there is no movposcomb of tomove matching
162    * back/fwd, or EC_MovFeatTooLate if the maxdelay_ms could not be
163    * met because of lack of ability to change points.
164    */
165
166 ErrorCode
167 movpos_reserve(Segment *move, int maxdelay_ms, MovPosChange **res_r);
168   /* Returns EC_MovFeatTooLate if the maxdelay_ms could not be met.
169    * The resulting MovPosChange is a reservation which is guaranteed
170    * to be useable successfully later for any movpos_change for
171    * the same move and a greater or equal maxdelay_ms.  On successful
172    * exit *res_r is set to non-0.  On transition out of Sta_Run,
173    * all unconfirmed reservations must be unreserved before
174    * points_all_abandon is called (see startup.c);
175    */
176
177 void movpos_unreserve(MovPosChange *reservation);
178
179 /*========== speedmgr.c ==========*/
180
181 void speedmanager_speedchange_request(Train *tra, long speed);
182   /* Callable directly in response to application command.
183    * speed may be LONG_MAX to mean maximum permitted.
184    */
185
186 void speedmanager_emergencystop(Train *tra);
187 void speedmanager_autostop(Train *tra);
188   /* These are responsible for calling actual_setspeed.
189    *
190    * After speedmanager_autostop, ->speed will have been updated to a
191    * new desired speed.  If it is 0 the train was going slowly and has
192    * been instructed to stop right now.
193    */
194
195 void speedmanager_reset_train(Train *tra);
196
197 /*========== actual.c ==========*/
198 /* actual.c should only be called from safety.c.
199  * It is responsible for communicating with the PICs, including
200  * repeating the NMRA commands and redacting detection information.
201  *
202  * In general, when State information is shared between actual.c
203  * and safety.c, safety.c is responsible for modifying State, and
204  * will then call an actual_... function to notify the change.
205  */
206
207 void actual_setspeed(Train *tra);
208 void actual_emergencystop(Train *tra);
209
210 void actual_inversions_start(void);
211 void actual_inversions_segment(Segment *seg);
212 void actual_inversions_done(void);
213   /* safety.c will call these in this order: first start, then segment
214    * for 0 or more segments (whose s.segments[segn].seg_inverted may
215    * or may not have changed), and finally done.  At done, the PICs
216    * should be told to (de)invert the segments as specified.  */
217   
218 /*
219  * Entrypoints are:                  Called from, and as a result of:
220  *   actual_setspeed                    safety.c
221  *   actual_emergencystop               safety.c
222  */
223
224 /*========== utils.c ==========*/
225
226 typedef struct TrackLocation TrackLocation;
227 struct TrackLocation { /* transparent, and manipulable by trackloc_... fns */
228   Segment *seg; /* current segment */
229   long into; /* distance from start of segment */
230   unsigned backwards:1; /* if 1, into is positive and measured from end */
231 };
232
233 long trackloc_remaininseg(const TrackLocation *tloc);
234   /* Returns dist that tloc can advance before it goes into next segment. */
235
236 void trackloc_further(TrackLocation *tloc, long *remain_io);
237   /* Advances tloc, decrementing *remain_io, until either
238    * *remain_io becomes zero, or tloc->segn changes. */
239
240 void trackloc_reverse(TrackLocation *tloc);
241   /* Reverses tloc without changing its actual location. */
242
243 const SegPosCombInfo *trackloc_segposcomb(const TrackLocation *tloc);
244 const SegmentLinkInfo *trackloc_segmentlink(const TrackLocation *tloc,
245                                             const SegPosCombInfo *pci,
246                                             unsigned far);
247
248 /*========== useful macros and declarations ==========*/
249
250 /*---------- looping over trains and segments ----------*/
251
252 #define SEGMENT_ITERVARS(seg)                   \
253   SegmentNum seg##n;                            \
254   Segment *seg;                                 \
255   const SegmentInfo *seg##i
256
257 #define TRAIN_ITERVARS(tra)                     \
258   Train *tra;                                   \
259   int tra##n
260
261 #define FOR_SEGMENT(seg, initx, stepx)                  \
262   for (seg##n=0, seg=segments, seg##i=info_segments;    \
263        seg##n < NUM_SEGMENTS;                           \
264        seg##n++, seg++, seg##i++, stepx)
265
266 #define FOR_TRAIN(tra, initx, stepx)            \
267   for (tra##n=0, tra=trains, initx;             \
268        tra##n < n_trains;                       \
269        tra##n++, tra++, stepx)
270
271 #define SEG_IV SEGMENT_ITERVARS(seg)
272 #define FOR_SEG FOR_SEGMENT(seg,(void)0,(void)0)
273   
274 #define TRA_IV TRAIN_ITERVARS(tra)
275 #define FOR_TRA FOR_TRAIN(tra,(void)0,(void)0)
276
277 /*---------- calculations with fixed point speeds ----------*/
278
279 #define DIVIDE_ROUNDING_UP(num,den)   (((num) + (den) - 1) / (den))
280 #define DIVIDE_ROUNDING_DOWN(num,den) ( (num)             / (den))
281
282 #define SPEED_CALC_TIME(speed,dist,round) \
283   DIVIDE_ROUNDING_##round((dist) * SPEED_UNIT, (speed))
284
285 #define SPEED_CALC_DIST(speed,time,round) \
286   DIVIDE_ROUNDING_##round((time) * (speed), SPEED_UNIT)
287
288 /*---------- safety margin parameters ----------*/
289
290 #define CLEAR_FORESIGHT_TIME 500 /*ms*/
291 #define AUTOSTOP_MAXSPEED ((50 * SPEED_UNIT)/1000) /* 50 mm/s */
292 #define AUTOSTOP_UNCERTAINTY 20  /*mm*/
293 #define ESTOP_UNCERTAINTY 300  /*mm*/
294 #define ESTOP_DEADTIME    2000 /*ms*/
295
296 #define SPEED_CLEAR_MULT SPEED_CALC_DIST(1,CLEAR_FORESIGHT_TIME,UP)
297
298 #endif /*SAFETY_H*/