chiark / gitweb /
Merge and end branch-hostside-wip-2008-01-25 PROPERLY; cvs up -j branch-hostside...
[trains.git] / hostside / safety.h
index be00b05201da7bb968036f762defcf3f76164c6b..8e6d0e5c6b31f5766aaedd2c6b98d804427e236a 100644 (file)
 #ifndef SAFETY_H
 #define SAFETY_H
 
-/*========== basic types etc. ==========*/
+#include <stdarg.h>
 
-typedef unsigned short TrainNum;
-typedef unsigned short SegmentNum;
-typedef unsigned short LocationNum;
-typedef unsigned short MovPosComb;
-typedef unsigned char Small;
-typedef short TimeInterval;
-typedef short Distance;
-typedef char Speed; /* non-negative, units of 4mm/s */
+#include "../layout/layout-data.h"
+#include "layoutinfo.h"
+#include "errorcodes.h"
+
+/*========== more basic types etc. ==========*/
+
+typedef short TimeInterval; /*ms*/
+
+/*---------- units and scales ----------*/
+
+/*
+ * Distances are in mm.
+ * Times are in ms.
+ * Speeds are in fixed point: unit is 1/SPEED_UNIT m/s
+ *
+ * To calculate with speeds and times without using floating point
+ * it turns out that we can cope with distances of up to
+ *   2^(31-SPEED_SHIFT) mm
+ */
+
+#define SPEED_SHIFT 16     /* units of 15um/s, max distance 2^15mm =~ 32m */
+#define SPEED_UNIT (1L<<SPEED_SHIFT) /* ms/mm */
 
 /*========== state of the layout ==========*/
 
+typedef struct MovPosChange MovPosChange;
+
 typedef struct {
-  SegmentNum foredetect;   /* train's detectable part is at most maxinto   */
+  int step;
+  long speed;
+  TimeInterval upwait, downwait; /* between this insn and next one */
+} SpeedCurveEntry;
+
+struct Train {
+  /* Configuration (excluding speed curve): */
+  char *pname;
+  int addr;
+  Distance head, detectable, tail;
+
+  /* Location: */
+  struct Segment *foredetect; /* train's detectable part is at most maxinto */
   Distance maxinto, uncertainty;   /*   into foredetect but train may be   */
   unsigned                         /*   uncertainty less far advanced      */
-    backwards:1; /* train is moving backwards wrt its own front and back */
-  Speed speed;
-} TrainState;
+    backwards:1, /* train is moving backwards wrt its own front and back */
 
-typedef struct {
+  /* Speed: */
+    estopping:1, /* set and cleared by speed.c */
+
+  /* Startup resolution (resolve.c): */
+    resolution:2;
+  Speed speed; /* when accelerating/decelerating, is maximum at this moment */
+
+  struct {
+    int target; /* index into curve */
+    int commanded; /* when ac-/decel, eq last value xmitted */
+    TimeoutEvent more; 
+    RetransmitUrgentNode rn;
+
+    /* Configuration for acceleration: */
+    SpeedCurveEntry *curve;
+    int curvesz;
+  } accel;
+};
+
+struct Segment {
+  Train *owner;                                  /* or 0 */
+  Train *home;                                   /* or 0 */
   unsigned
-    owned:1, /* this track segment is reserved for a train */
     tr_backwards:1, /* train's motion is (would be) backwards wrt track */
-    movfeat_moving:1, /* feature(s) have been told to change to movposcomb */
+    ho_backwards:1, /* home train has its front and rear backwards wrt track */
     cm_autostop:1, /* train should stop on detection */
     seg_inverted:1, /* polarity is inverted */
-    tr_updated:1; /* for use by safety.c:lay_train etc.; otherwise 0 */
-  TimeInterval until_here, /* ) nonnegative; */  /* ) always valid but */
-    until_detect;          /* ) 0 if already */  /* )  only meaningful */
-  TrainNum owner;                                /* )  iff owned       */
+    tr_updated:1, /* for use by safety.c:lay_train etc.; otherwise 0 */
+    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;
-  /*polarity?*/
-} SegmentState;
-
-typedef struct {
-  unsigned next_backwards:1;
-  SegmentNum next;
-} SegmentLinkInfo;
-
-typedef struct {
-  const char *pname;
-  Small posns;
-  MovPosComb weight;
-} MovFeatInfo;
-
-typedef struct {
-  const char *pname;
-  SegmentLinkInfo backwards, forwards;
-  Distance dist;
-} SegPosCombInfo;
+  MovPosChange *moving; /* non-0 iff feature(s) have been told to change */
+  const SegmentInfo *i;
+};
 
-typedef struct {
-  const char *pname;
-  unsigned invertible:1;
-  Small n_movfeats;
-  const MovFeatInfo *movfeats;
-  MovPosComb n_poscombs;
-  const SegPosCombInfo *poscombs;
-  Small board, object;
-} SegmentInfo;
+extern int n_trains;
+extern Train *trains;
+extern Segment *segments;
 
-typedef struct {
-  Speed maxspeed;
-  Distance tail, detectable, head;
-  const char *pname;
-} TrainInfo;
+/*========== embed.c ==========*/
+/* surrounds the algorithms and machinery in a program: logging, error
+ * handling, arg parsing, etc.
+ */
 
-extern const TrainInfo info_trains[NUM_TRAINS];
-extern const SegmentInfo info_segments[NUM_SEGMENTS];
+void vlogmsg(ErrorCode ec, Train *tra, const SegmentInfo *segi,
+            const char *fmt, va_list al) __attribute__((format(printf,4,0)));
+void logmsg(ErrorCode ec, Train *tra, const SegmentInfo *segi,
+           const char *fmt, ...) __attribute__((format(printf,4,5)));
 
-typedef struct {
-  TrainState trains[NUM_TRAINS];
-  SegmentState segments[NUM_SEGMENTS];
-} State;
+void safety_vpanic(Train *tra, Segment *seg, const char *fmt, va_list al)
+     __attribute__((format(printf,3,0),noreturn));
+void safety_panic(Train *tra, Segment *seg, const char *fmt,...)
+     __attribute__((format(printf,3,4),noreturn));
 
-extern State s;
+ErrorCode safety_problem(Train *tra, Segment *seg, const char *fmt, ...)
+     __attribute__((format(printf,3,4)));
+     /* simple wrapper around vlogmsg; implies and returns EC_Safety */
 
 /*========== safety.c ==========*/
 /*
@@ -89,26 +116,83 @@ extern State s;
  * etc.).
  */
 
-void safety_emergencystop(TranNum);
+void safety_emergencystop(Train*);
   /* Callable directly in response to application command. */
 
-void safety_requestspeed(TrainNum tran, long newspeed);
+ErrorCode safety_requestspeed(Train* tra, long newspeed);
   /* To be called only by the speed manager, thus indirectly from
-   * user request.
-   * Will result in a call to speedmanager_speedchange_notify (and of
-   * course to actual_setspeed.  Speed manager must apply accel/decel
-   * curve so that if safety.c agrees the command, the actual speed of
-   * the train changes straight away (at least for decel).
+   * user request.  Any error will have been logged.  On success,
+   * ->speed has been updated.  Speed manager is responsible for
+   * calling actual_setspeed.
+   */
+
+void safety_setdirection(Train* tra, int sense_fixme_define_this_properly);
+
+void safety_notify_detection(Segment *seg);
+  /* Called by startup.c when new train detection occurs in state Run. */
+
+/*========== movpos.c ==========*/
+/*
+ * movpos.c manages the CDU and points and other moveable features.
+ * Only safety.c should request changes.
+ */
+
+ErrorCode
+movpos_change(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.
+   *
+   * 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.
+   *
+   * reservation should be 0, or the results of movpos_reservechange
+   * on the same move.  It is always consumed, even on error.
+   *
+   * On successful exit, tomove->moving is set non-0; from then on
+   * until ->moving becomes 0, movposcomb may not reflect the real
+   * physical state of the layout; instead it gives only information
+   * about the target configuration.  (Choreographers are allowed to
+   * know implementation details and may know what movposcomb means
+   * for certain segments depending on the movement requested.)
+   *
+   * Returns EC_Invalid if there is no movposcomb of tomove matching
+   * back/fwd, or EC_MovFeatTooLate if the maxdelay_ms could not be
+   * met because of lack of ability to change points.
+   */
+
+ErrorCode
+movpos_reserve(Segment *move, int maxdelay_ms, MovPosChange **res_r);
+  /* Returns EC_MovFeatTooLate if the maxdelay_ms could not be met.
+   * The resulting MovPosChange is a reservation which is guaranteed
+   * to be useable successfully later for any movpos_change for
+   * the same move and a greater or equal maxdelay_ms.  On successful
+   * exit *res_r is set to non-0.  On transition out of Sta_Run,
+   * all unconfirmed reservations must be unreserved before
+   * points_all_abandon is called (see startup.c);
    */
 
-void safety_notify_detection(SegmentNum segn);
-  /* To be called by actual.c when new train detection occurs. */
+void movpos_unreserve(MovPosChange *reservation);
 
 /*========== speedmgr.c ==========*/
 
-void speedmanager_speedchange_notify(TrainNum tran);
-  /* To be called only by safety.c, whenever speed is actually set.
-   * New speed has already been recorded in State. */
+void speedmanager_speedchange_request(Train *tra, long speed);
+  /* Callable directly in response to application command.
+   * speed may be LONG_MAX to mean maximum permitted.
+   */
+
+void speedmanager_emergencystop(Train *tra);
+void speedmanager_autostop(Train *tra);
+  /* These are responsible for calling actual_setspeed.
+   *
+   * After speedmanager_autostop, ->speed will have been updated to a
+   * new desired speed.  If it is 0 the train was going slowly and has
+   * been instructed to stop right now.
+   */
+
+void speedmanager_reset_train(Train *tra);
 
 /*========== actual.c ==========*/
 /* actual.c should only be called from safety.c.
@@ -116,33 +200,32 @@ void speedmanager_speedchange_notify(TrainNum tran);
  * repeating the NMRA commands and redacting detection information.
  *
  * In general, when State information is shared between actual.c
- * and safety.c, actual.c is responsible for modifying State, and
+ * and safety.c, safety.c is responsible for modifying State, and
  * will then call an actual_... function to notify the change.
  */
 
-void actual_setspeed(TrainNum tran);
+void actual_setspeed(Train *tra);
+void actual_emergencystop(Train *tra);
 
 void actual_inversions_start(void);
-void actual_inversions_segment(SegmentNum);
+void actual_inversions_segment(Segment *seg);
 void actual_inversions_done(void);
   /* safety.c will call these in this order: first start, then segment
-   * for 0 or more segments (whose inversion may or may not have
-   * changed), and finally done.  At done, the PICs should be told to
-   * (de)invert the segments as specified.
-   */
+   * for 0 or more segments (whose s.segments[segn].seg_inverted may
+   * or may not have changed), and finally done.  At done, the PICs
+   * should be told to (de)invert the segments as specified.  */
   
 /*
- *
  * Entrypoints are:                  Called from, and as a result of:
  *   actual_setspeed                    safety.c
  *   actual_emergencystop               safety.c
-
+ */
 
 /*========== utils.c ==========*/
 
 typedef struct TrackLocation TrackLocation;
 struct TrackLocation { /* transparent, and manipulable by trackloc_... fns */
-  SegmentNum segn; /* current segment */
+  Segment *seg; /* current segment */
   long into; /* distance from start of segment */
   unsigned backwards:1; /* if 1, into is positive and measured from end */
 };
@@ -157,7 +240,59 @@ void trackloc_further(TrackLocation *tloc, long *remain_io);
 void trackloc_reverse(TrackLocation *tloc);
   /* Reverses tloc without changing its actual location. */
 
-const SegmentLinkInfo *trackloc_segmentlink_near(const TrackLocation *tloc);
-const SegmentLinkInfo *trackloc_segmentlink_far(const TrackLocation *tloc);
+const SegPosCombInfo *trackloc_segposcomb(const TrackLocation *tloc);
+const SegmentLinkInfo *trackloc_segmentlink(const TrackLocation *tloc,
+                                           const SegPosCombInfo *pci,
+                                           unsigned far);
+
+/*========== useful macros and declarations ==========*/
+
+/*---------- looping over trains and segments ----------*/
+
+#define SEGMENT_ITERVARS(seg)                  \
+  SegmentNum seg##n;                           \
+  Segment *seg;                                        \
+  const SegmentInfo *seg##i
+
+#define TRAIN_ITERVARS(tra)                    \
+  Train *tra;                                  \
+  int tra##n
+
+#define FOR_SEGMENT(seg, initx, stepx)                 \
+  for (seg##n=0, seg=segments, seg##i=info_segments;   \
+       seg##n < NUM_SEGMENTS;                          \
+       seg##n++, seg++, seg##i++, stepx)
+
+#define FOR_TRAIN(tra, initx, stepx)           \
+  for (tra##n=0, tra=trains, initx;            \
+       tra##n < n_trains;                      \
+       tra##n++, tra++, stepx)
+
+#define SEG_IV SEGMENT_ITERVARS(seg)
+#define FOR_SEG FOR_SEGMENT(seg,(void)0,(void)0)
+  
+#define TRA_IV TRAIN_ITERVARS(tra)
+#define FOR_TRA FOR_TRAIN(tra,(void)0,(void)0)
+
+/*---------- calculations with fixed point speeds ----------*/
+
+#define DIVIDE_ROUNDING_UP(num,den)   (((num) + (den) - 1) / (den))
+#define DIVIDE_ROUNDING_DOWN(num,den) ( (num)             / (den))
+
+#define SPEED_CALC_TIME(speed,dist,round) \
+  DIVIDE_ROUNDING_##round((dist) * SPEED_UNIT, (speed))
+
+#define SPEED_CALC_DIST(speed,time,round) \
+  DIVIDE_ROUNDING_##round((time) * (speed), SPEED_UNIT)
+
+/*---------- safety margin parameters ----------*/
+
+#define CLEAR_FORESIGHT_TIME 500 /*ms*/
+#define AUTOSTOP_MAXSPEED ((50 * SPEED_UNIT)/1000) /* 50 mm/s */
+#define AUTOSTOP_UNCERTAINTY 20  /*mm*/
+#define ESTOP_UNCERTAINTY 300  /*mm*/
+#define ESTOP_DEADTIME    2000 /*ms*/
+
+#define SPEED_CLEAR_MULT SPEED_CALC_DIST(1,CLEAR_FORESIGHT_TIME,UP)
 
 #endif /*SAFETY_H*/