chiark / gitweb /
new nmra retransmit alg designed impln wip; some header file cleanups; send warning...
authorian <ian>
Mon, 5 Jun 2006 00:37:47 +0000 (00:37 +0000)
committerian <ian>
Mon, 5 Jun 2006 00:37:47 +0000 (00:37 +0000)
hostside/realtime.h
hostside/retransmit.c
hostside/safety.c
hostside/safety.h
hostside/startup.c

index 473f415e78982d63bcf9319a00cccc07c4566196..2aa2b3bd9aa3f8cdc6e91ede07bc256880cf18ca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * declarations for multiplexer daemon
+ * declarations for realtime daemon
  */
 
 #ifndef REALTIME_H
 #include <sys/types.h>
 #include <sys/time.h>
 
+/*---------- from retransmit.c ----------*/
+
 typedef struct RetransmitNode RetransmitNode;
+struct RetransmitNode {
+  /* set by caller: */
+  PicInsn pi;
+  /* internal: */
+  unsigned long speedyduetime;
+  struct { RetransmitNode *back, *next; } relaxed, speedy;
+};
+
+void retransmit_queue(RetransmitNode *rn);
+void retransmit_cancel(RetransmitNode *rn);
+
+/*---------- global variables, in realtime.c ----------*/
 
 extern CommandInput cmdi;
 
+#define UPO (&(cmdi.out))
+
+/*---------- from/for startup.c ----------*/
+
 typedef enum {   /* sta_toev   ping_toev    */
   Sta_Flush,     /*  R 300      I ?         */
   Sta_Off,       /*  I ?        I ?         */
@@ -31,16 +49,19 @@ typedef enum {   /* sta_toev   ping_toev    */
   Sta_Run        /*  I ?        R set       */
 } StartupState;
 
-#define UPO (&(cmdi.out))
+void sta_startup(void);
+void serial_moredata(PicInsn *buf);
+
+extern StartupState sta_state;
+
+/*---------- from/for realtime.c ----------*/
 
 void oupicio(const char *dirn, const PicInsnInfo *pii, int objnum);
 void ouhex(const char *word, const Byte *command, int length);
 
-void serial_moredata(PicInsn *buf);
 void serial_transmit(const PicInsn *pi);
 
-void sta_startup(void);
-extern StartupState sta_state;
+/*---------- tbi ----------*/
 
 void abandon_run(void);
 
index 54c4fda8efea87341c6d35a8004c9f7a7e891115..9306209416fa0f0a3dd393b960af714ea7cb7c4e 100644 (file)
 /*
+ * realtime
  * nmra retransmission
  */
 
-#include "hostside.h"
+#include "realtime.h"
 
-void retransmit_queue(RetransmitNode *rn) {
+/*
+ * There are two kinds of messages: urgent and relaxed.
+ *
+ * Urgent messages may be due for speedy transmission.  The due urgent
+ * message with the highest priority is always transmitted as soon as
+ * a slot is available.  This is known as `speedy transmission'.
+ * 
+ * When no urgent messages are due for speedy transmission, messages
+ * (urgent or relaxed) are transmitted in a round-robin fashion.  This
+ * round-robin transmission is completely independent of the speedy
+ * transmission.
+ *
+ * Each urgent message is due for speedy transmission as follows:
+ *   - When it is first queued and has not yet been
+ *     speedily transmitted:
+ *         immediately due, with maximum priority
+ *   - Following each speedy transmission:
+ *         due after an interval since the previous
+ *           transmission; this interval increases exponentially
+ *           for each transmission
+ *         with priority which decreases with later transmissions
+ *         until it has been speedily transmitted a certain number of times
+ *   - Thereafter:
+ *         no longer ever due; subject to round-robin transmission only.
+ * Intervals are measured in messages regardless of length.
+ */
+/*
+ * Implementation:
+ *  All messages are on the single relaxed queue.
+ *  There is one queue for each speady retransmission; messages are on
+ *  it in chronological order of dueness.
+ */
+
+#define RETRANS_SPEEDYCOUNT 20
+#define RETRANS_SPEEDYEXP 1.3
+
+#define HALFWAY ((~(Retransmit__Time)0) >> 1)
+
+typedef struct {
+  DLIST2_HEAD(RetransmitUrgentNode) queue; /* msgs transmitted ix times */
+  Retransmit__Time interval; /* interval after this retransmission */
+} PerSpeedyTrans;
+
+static const PicInsn linefill= { { 0xff, 0x7f }, 2 };
+
+static DLIST2_HEAD(RetransmitRelaxedNode) relaxed;
+static elapsed;
+static PerSpeedyTrans speedies[RETRANS_SPEEDYCOUNT];
+
+static void retransmit_this(const PicInsn *pi) {
+  serial_transmit(pi);
+  elapsed++;
 }
 
-void retransmit_cancel(RetransmitNode *rn) {
+static void retransmit_something() {
+  PerSpeedyTrans *spd;
+  RetransmitUrgentNode *urg;
+  RetransmitRelaxedNode *rlx;
+  
+  for (ix=0, spd=speedies;
+       ix < RETRANS_SPEEDYCOUNT;
+       ix++, spd++) {
+    urg= spd->head;
+    if (!urg) continue;
+    if (elapsed - urg->u.when > HALFWAY) continue;
+
+    /* found one to transmit: */
+    DLIST2_REMOVE(spd->queue,urg,u.queue);
+    if (++ix < RETRANS_SPEEDYCOUNT) {
+      urg->u.ix= ix;
+      urg->u.when= elapsed + spd->interval;
+      spd++;
+      DLIST2_APPEND(spd->queue,urg,u.queue);
+    } else {
+      urg->d.urgent_ix= -1;
+    }
+    retransmit_this(&urg->pi);
+    return;
+  }
+
+  rlx= relaxed.head) {
+  if (rlx) {
+    DLIST2_REMOVE(relaxed,rlx,rr);
+    DLIST2_APPEND(relaxed,rlx,rr);
+    retransmit_this(&rlx->pi);
+    return;
+  }
+
+  serial_transmit(&linefill);
+}
+
+void retransmit_relaxed_queue(RetransmitRelaxedNode *rlx) {
+  DLIST2_PREPEND(relaxed,rn,rr);
+}
+void retransmit_relaxed_cancel(RetransmitRelaxedNode *rlx) {
+  DLIST2_REMOVE(relaxed,rlx,rr);
+}
+
+void retransmit_urgent_queue(RetransmitUrgentNode *urg) {
+  urg->u.ix= 0;
+  urg->u.when= elapsed;
+  DLIST2_APPEND(speedies[0].queue,urg,u.queue);
+  retransmit_relaxed_queue(&urg->u.relaxed);
+}
+void retransmit_urgent_cancel(RetransmitUrgentNode *urg) {
+  if (urg->u.ix >= 0)
+    DLIST2_REMOVE(speedies[urg->u.ix].queue,urg,u.queue);
+  retransmit_relaxed_cancel(&urg->u.relaxed);
 }
index d9b48ae50ad23b01aeb5ef43ad5f92dbdebede9f..41c16187999994d23931d38a087bc77ba37abd74 100644 (file)
@@ -283,6 +283,8 @@ void safety_requestspeed(TrainNum tran, long newspeed) {
       logmsg(ec, tran, NOTA(Segment), "countermanded motion start");
     }
     setspeed(tran, oldspeed);
+    oprintf(UPO, "countermanded %s %l %l\n",
+           info_trains[tran].pname, oldspeed, newspeed);
     ec= lay_train(tran, 0);
     if (ec)
       safety_panic(tran, NOTA(Segment), "countermanding"
@@ -292,9 +294,3 @@ void safety_requestspeed(TrainNum tran, long newspeed) {
 
   setspeed(tran, newspeed);
 }
-                            
-
-int main(void) {
-  printf("%d\n",(int)sizeof(State));
-  return 0;
-}
index 2408248a11ccbfe162e6c6eeae48e19e3170b748..26788d2aa6f841afc0b24376f35d67c98e933b32 100644 (file)
@@ -78,17 +78,18 @@ ErrorCode safety_problem(TrainNum tran, SegmentNum segn, const char *fmt,...)
 void safety_emergencystop(TrainNum);
   /* Callable directly in response to application command. */
 
+void safety_setdirection(TrainNum tran, int sense_fixme_define_this_properly);
 void safety_requestspeed(TrainNum tran, 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
+   * 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).
    */
 
 void safety_notify_detection(SegmentNum segn);
-  /* To be called by actual.c when new train detection occurs. */
+  /* Called by startup.c when new train detection occurs in state Run. */
 
 /*========== speedmgr.c ==========*/
 
@@ -102,7 +103,7 @@ 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.
  */
 
index 64c53d3ef2cd29611a95825e56e00f4aeac7be60..8a5b98b80deffc9a8815ec46528b824ae131bde4 100644 (file)
@@ -185,6 +185,16 @@ void on_pic_hello(const PicInsnInfo *pii, const PicInsn *pi, int objnum)
 void on_pic_aaargh(const PicInsnInfo *pii, const PicInsn *pi, int objnum)
   { abort(); }
 
+void on_pic_detect1(const PicInsnInfo *pii, const PicInsn *pi, int segn) {
+  if (segn >= NUM_SEGMENTS) die("PIC sent detect @#%d out of range",segn);
+  if (sta_state < Sta_Run) {
+    oprintf(UPO, "warning fixme ignored non-Run detection @%s\n",
+           info_segments[segn].pname);
+    return;
+  }
+  safety_notify_detection(segn);
+}
+
 /*---------- fixme move these to where they want to go ----------*/
 
 void on_pic_nmradone(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
@@ -196,10 +206,6 @@ void on_pic_nmradone(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
 void on_pic_detect0(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
 }
 
-void on_pic_detect1(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
-  /* fixme do something here */
-}
-
 void abandon_run(void) {
   /* fixme do something here */
 }