chiark / gitweb /
simulation - compiles but not yet tested
authorian <ian>
Sun, 4 May 2008 15:42:30 +0000 (15:42 +0000)
committerian <ian>
Sun, 4 May 2008 15:42:30 +0000 (15:42 +0000)
14 files changed:
hostside/Makefile
hostside/README.commands
hostside/cmdinput.c
hostside/common.h
hostside/daemons.h
hostside/eventhelp.c
hostside/gui-plan.c
hostside/obc.c
hostside/realtime.c
hostside/realtime.h
hostside/simulate.c [new file with mode: 0644]
hostside/speed.c
hostside/startup.c
hostside/utils.c

index b1a2c699d4dcd9fea294fa6dc94aec2891872a4e..019e72427d1d062e2c979c9dc9ad50ddc698b2ac 100644 (file)
@@ -29,13 +29,15 @@ on-bessar:  $(TARGETS)
 %.on-bessar:   %
                RSYNC_RSH=fsh rsync $^ $(BESSAR)
 
-realtime:      realtime.o startup.o cdumgr.o safety.o trackloc.o       \
+REALTIME_CORE= realtime.o startup.o cdumgr.o safety.o trackloc.o       \
                 speed.o actual.o retransmit.o persist.o resolve.o      \
-                cmdinput.o commands.o obc.o eventhelp.o                \
+                cmdinput.o commands.o obc.o eventhelp.o simulate.o     \
                 record.o record-l.o record-y.o                         \
                 utils.o serialio.o parseutils.o auproto-pic.o          \
                 nmra.o encode.o movpos.o                               \
-                ../layout/ours.layout-data.o                           \
+                ../layout/ours.layout-data.o
+
+realtime:      $(REALTIME_CORE)                                \
                 __oop-read-copy.o -loop -lm
                $(LINK)
 
index 4d35a5a2861faef4260f389530e8b1d438d9a919..b01092872091241751b51b8324710f59f7f95603 100644 (file)
@@ -8,12 +8,12 @@ POSSIBLY-ASYNCHRONOUS REPORTING OF MESSAGES TO/FROM (MASTER) PIC
        In principle, all output to PICs, in raw form, but
        subject to suppression
 
- U< picioh <timestamp> in junk    <byte> [<byte>...]
- U< picioh <timestamp> in aargh   <byte> [<byte>...]
- U< picioh <timestamp> in hello   <byte> [<byte>...]
- U< picioh <timestamp> in off     <byte> [<byte>...]
- U< picioh <timestamp> in toolong <byte> [<byte>...]
- U< picioh <timestamp> in msg     <byte> [<byte>...]
+ U< picioh in junk    <byte> [<byte>...]
+ U< picioh in aargh   <byte> [<byte>...]
+ U< picioh in hello   <byte> [<byte>...]
+ U< picioh in off     <byte> [<byte>...]
+ U< picioh in toolong <byte> [<byte>...]
+ U< picioh in msg     <byte> [<byte>...]
 
  U< picio out polarity <[<segment>[,...]]>     literal < and > bracket segs
  U< picio out unknown                          data printed in assoc'd picioh
@@ -61,13 +61,16 @@ POSSIBLY-ASYNCHRONOUS REPORTING OF MESSAGES TO/FROM (MASTER) PIC
  U< debug <context> : <debug message>
  U< info : <informational message>
 
+ U> timestamp <seconds>.<microseconds>
+ U> timer-event <class>.<instance>
+
 ======================================================================
 
 COMMANDS AND RESPONSES
 
  P> <command> [<arguments>...]
   results in:
- R< executing <command>
+ R< executing <command> [<arguments>...]
   consequential messages including picio, signalling problems etc.
   then one of these
  R< ack <command> ok
index 376b20855e055114cc7a2b54283317db5bb27506..8bf11d974ca22d7d0506dba58d0e2a63e597321a 100644 (file)
@@ -5,6 +5,8 @@
 
 #include "daemons.h"
 
+oop_source *events;
+
 static void *cmdi_exception(oop_source *evts, int fd,
                            oop_event evt, void *cmdi_v) {
   CommandInput *cmdi= cmdi_v;
@@ -38,7 +40,6 @@ static void *cmdi_ifok(oop_source *evts, oop_read *cl_read,
   if (evt != OOP_RD_OK)
     return cmdi_iferr(evts,cl_read,evt,errmsg,errnoval,data,recsz,cmdi_v);
 
-  ps.cl= 0;
   ps.remain= data;
   cmdi->doline(&ps, cmdi);
   return OOP_CONTINUE;
index 84532bbb0428c01e30aa80271e277fa04c0b3600..3d7a532a80081a3021e86900c9c8a46c1d249659 100644 (file)
@@ -38,7 +38,6 @@ typedef struct PicInsn {
 /*---------- from parseutils.c ----------*/
 
 struct ParseState {
-  Client *cl; /* used only by multiplexer */
   const char *remain;
   const char *thisword;
   int lthisword;
@@ -122,7 +121,7 @@ void *mmalloc(size_t sz);
 void *mrealloc(void *old, size_t sz);
 char *mstrdupl(const char *s, int l);
 char *mstrdup(const char *s);
-void mgettimeofday(struct timeval *tv);
+void real_mgettimeofday(struct timeval *tv);
 
 void mrename(const char *old, const char *new);
 
index 2fd57d418121d518db108a734211e2520e7b5047..d0878e637388a5f6d40feced62499bb418b1e879 100644 (file)
@@ -34,6 +34,7 @@ struct OutBufferChain {
 };
 
 void obc_init(OutBufferChain *ch);
+void obc_init_core(OutBufferChain *ch); /* doesn't mess with fd */
 int obc_tryflush(OutBufferChain *ch);
  /* returns 0 for all flushed or errno, including particularly EWOULDBLOCK */
 
@@ -47,6 +48,8 @@ void voerror(OutBufferChain *ch, const char *fmt, va_list al)
 
 /*---------- from cmdinput.c ----------*/
 
+extern oop_source *events;
+
 typedef void CommandInputCallback(ParseState *ps, CommandInput *cmdi);
 
 struct CommandInput {
@@ -59,27 +62,4 @@ void cmdin_new(CommandInput *cmdi, int readfd);
   /* fill in cmdi->out's `set by user' fields before calling cmdin_new,
    * as cmdin_new will call obc_init and will use cmdi->out->fd. */
 
-/*---------- from eventhelp.c ----------*/
-
-extern oop_source *events;
-
-typedef struct TimeoutEvent TimeoutEvent;
-typedef void TimeoutEventFn(TimeoutEvent*);
-struct TimeoutEvent {       /* Undefined   Idle      Running     set by   */
-  int running;              /*  any         0         1           toev_   */
-  int duration; /*ms*/      /*  any         any[1]    any[1]      caller  */
-  TimeoutEventFn *callback; /*  any         any       valid[2]    caller  */
-  struct timeval abs;       /*  any         any       valid       toev_   */
-};  /* [1] duration must be >=0 or -1 when toev_start is called;
-     * [2] callback may be modified while timeout is running;
-     *      value used is that prevailing when timeout happens
-     * when the timeout happens, TimeoutEvent's state goes from R to I
-     * and then callback member is read and the function called
-     */
-
-void toev_init(TimeoutEvent*);    /* U -> I */
-void toev_start(TimeoutEvent*);   /* IR -> R; reads duration */
-  /* if duration is -1 then is same as toev_stop */
-void toev_stop(TimeoutEvent*);    /* IR -> I */
-
 #endif /*DAEMONS_H*/
index 44712407c27757f0b660b237e1ca748931dc3be4..1f65f4552da4f06de652d135fc4489dfe22be56f 100644 (file)
@@ -1,17 +1,23 @@
 /*
- * daemons
+ * realtime
  * helpers for event handling
  */
 
 #include <assert.h>
 #include <limits.h>
 
-#include "daemons.h"
+#include "realtime.h"
 
-oop_source *events;
+void real_mgettimeofday(struct timeval *tv) {
+  int r;
+  r= gettimeofday(tv,0);
+  if (r) diee("gettimeofday failed");
+  oprintf(UPO,"timestamp %ld.%06ld\n", tv->tv_sec, tv->tv_usec);
+}
 
-static void *toev_callback(oop_source *source, struct timeval tv, void *t_v) {
+void *toev_callback(oop_source *source, struct timeval tv, void *t_v) {
   TimeoutEvent *toev= t_v;
+  oprintf(UPO,"timer-event %s.%s\n", toev->pclass, toev->pinst);
   toev->running= 0;
   toev->callback(toev);
   return OOP_CONTINUE;
@@ -28,11 +34,21 @@ void toev_start(TimeoutEvent *toev) {
   toev->abs.tv_usec += toev->duration * 1000;
   toev->abs.tv_sec += toev->abs.tv_usec / 1000000;
   toev->abs.tv_usec %= 1000000;
-  events->on_time(events, toev->abs, toev_callback, toev);
+  if (simulate) sim_toev_start(toev);
+  else events->on_time(events, toev->abs, toev_callback, toev);
 }
 
 void toev_stop(TimeoutEvent *toev) {
   if (!toev->running) return;
   toev->running= 0;
-  events->cancel_time(events, toev->abs, toev_callback, toev);
+  if (simulate) sim_toev_stop(toev);
+  else events->cancel_time(events, toev->abs, toev_callback, toev);
+}
+
+void mgettimeofday(struct timeval *tv) {
+  if (simulate) {
+    sim_mgettimeofday(tv);
+  } else {
+    real_mgettimeofday(tv);
+  }
 }
index 6515cc0daa72476961f5bcb3d08acdbb1d6edda2..5596ba320d197f466accec5cde14e4238a6f229f 100644 (file)
@@ -261,7 +261,6 @@ static void *stdin_ifok(oop_source *evts, oop_read *cl_read,
   badcmdreport_data= data;
   badcmdreport_recsz= recsz;
 
-  ps.cl= 0;
   ps.remain= data;
   ps_needword(&ps);
 
index 853489055b36229a7b9a39e88114e1679444f059..e572b5ac6d8437783eb078d9e1b4cd95a31a6a97 100644 (file)
@@ -73,14 +73,18 @@ static void addlink(OutBufferChain *ch, OutBuffer *ob) {
   }
 }
 
-void obc_init(OutBufferChain *ch) {
-  int r;
+void obc_init_core(OutBufferChain *ch) {
   ch->done_of_head= 0;
   ch->total= 0;
   if (!ch->limit) ch->limit= 128*1024;
+  LIST_INIT(ch->obs);
+}
+
+void obc_init(OutBufferChain *ch) {
+  int r;
+  obc_init_core(ch);
   r= oop_fd_nonblock(ch->fd, 1);
   if (r) diee("nonblock(OutBufferChain->fd,1)");
-  LIST_INIT(ch->obs);
 }
 
 void ovprintf(OutBufferChain *ch, const char *fmt, va_list al) {
index 8fc791bbf0aa3ead4e1ba296a0377ba88e9ce342..f9bf1e70d004ec538f49d5d05278e40237af39ae 100644 (file)
@@ -200,10 +200,10 @@ int vbadcmd(ParseState *ps, const char *fmt, va_list al) {
 static void command_doline(ParseState *ps, CommandInput *cmdi_arg) {
   int r;
 
+  oprintf(UPO, "executing %s\n",ps->remain);
   ci= 0;
   ci= some_needword_lookup(ps, toplevel_cmds, "command");
   if (!ci) return;
-  oprintf(UPO, "executing %s\n", ci->name);
   r= ci->fn(ps,ci);
   switch (r) {
   case 0:  oprintf(UPO, "ack %s ok\n", ci->name);                    break;
@@ -247,7 +247,7 @@ void die_hook(void) {
 
 /*---------- serial input (via oop) ----------*/
 
-static PicInsn serial_buf;
+PicInsn serial_buf;
 
 static void *serial_readable(oop_source *evts, int fd,
                             oop_event evt, void *u0) {
@@ -265,7 +265,11 @@ static void *serial_readable(oop_source *evts, int fd,
   assert(r>0);
 
   buf_used= serial_buf.l + r;
+  serial_indata_process(buf_used);
+  return OOP_CONTINUE;
+}
 
+void serial_indata_process(int buf_used) {
   for (;;) {
     serial_buf.l= buf_used;
     serial_moredata(&serial_buf);
@@ -275,7 +279,6 @@ static void *serial_readable(oop_source *evts, int fd,
     if (!buf_used) break;
   }
   serial_buf.l= buf_used;
-  return OOP_CONTINUE;
 }
 
 /*---------- serial port output (not via liboop) ----------*/
@@ -334,37 +337,47 @@ int main(int argc, const char **argv) {
     /* do this before we call malloc so that MAP_FIXED is sure to work */
     persist_entrails_run_converter();
 
-  sys_events= oop_sys_new();  if (!sys_events) diee("oop_sys_new");
-  events= oop_sys_source(sys_events);  massert(events);
-
-  cmdi.out.desc= (char*)"command";
-  cmdi.out.fd= 1;
-  cmdi.out.error= obc_error;
-  cmdi.doline= command_doline;
-
-  cmdin_new(&cmdi, 0);
-
   while ((arg=*++argv) && *arg=='-') {
     arg++;
     switch (*arg++) {
     case 's': device= arg; break;
     case 'p': persist_fn= arg; break;
     case 'v': picio_send_noise= atoi(arg); break;
+    case 'S': simulate= arg; break;
     default: badusage("unknown option");
     }
   }
 
+  cmdi.out.desc= (char*)"command";
+  cmdi.out.fd= 1;
+  cmdi.out.error= obc_error;
+  cmdi.doline= command_doline;
+
   persist_entrails_interpret();
   records_parse(argv);
 
-  serial_open(device);
-  r= oop_fd_nonblock(serial_fd, 1);  if (r) diee("nonblock(serial_fd,1)");
+  if (!simulate) {
+    sys_events= oop_sys_new();  if (!sys_events) diee("oop_sys_new");
+    events= oop_sys_source(sys_events);  massert(events);
+
+    cmdin_new(&cmdi, 0);
+
+    serial_open(device);
+    r= oop_fd_nonblock(serial_fd, 1);  if (r) diee("nonblock(serial_fd,1)");
 
-  events->on_fd(events, serial_fd, OOP_READ, serial_readable, 0);
-  events->on_fd(events, serial_fd, OOP_EXCEPTION, read_exception, 0);
+    events->on_fd(events, serial_fd, OOP_READ, serial_readable, 0);
+    events->on_fd(events, serial_fd, OOP_EXCEPTION, read_exception, 0);
+
+  } else {
+    sim_initialise();
+    sys_events= 0;
+  }
 
   sta_startup();
-  oop_sys_run(sys_events);
+
+  if (!simulate) oop_sys_run(sys_events);
+  else sim_run();
+
   abort();
 }
 
index ff3e7729e3942e1745c8e0da8499e93e72f7072b..06b04463c73697db6a14618a435e0b9c25a4aa66 100644 (file)
@@ -33,6 +33,7 @@
 
 typedef struct Segment Segment;
 typedef struct Train Train;
+typedef struct TimeoutEvent TimeoutEvent;
 
 /*---------- from retransmit.c ----------*/
 
@@ -148,6 +149,23 @@ void ouhex(const char *word, const Byte *command, int length);
 
 void serial_transmit(const PicInsn *pi);
 
+/*---------- for/from simulate.c ----------*/
+
+const char *simulate;
+void serial_indata_process(int buf_used);
+
+void sim_initialise(void);
+void sim_run(void);
+
+void mgettimeofday(struct timeval *tv); /* contains magic for simulation */
+void *toev_callback(oop_source *source, struct timeval tv, void *t_v);
+
+void sim_toev_start(TimeoutEvent *toev);
+void sim_toev_stop(TimeoutEvent *toev);
+void sim_mgettimeofday(struct timeval *tv);
+
+extern PicInsn serial_buf;
+
 /*---------- from actual.c ----------*/
 
 int picinsn_polarity_testbit(const PicInsn *pi, const SegmentInfo *segi);
@@ -159,6 +177,27 @@ int picinsn_polarity_testbit(const PicInsn *pi, const SegmentInfo *segi);
 void points_turning_on(void);
 void points_all_abandon(void);
 
+/*---------- from eventhelp.c ----------*/
+
+typedef void TimeoutEventFn(TimeoutEvent*);
+struct TimeoutEvent {         /* Undefined   Idle      Running     set by   */
+  int running;                /*  any         0         1           toev_   */
+  int duration; /*ms*/        /*  any         any[1]    any[1]      caller  */
+  TimeoutEventFn *callback;   /*  any         any       valid[2]    caller  */
+  struct timeval abs;         /*  any         any       valid       toev_   */
+  const char *pclass, *pinst; /*  any         any       valid       caller  */
+};  /* [1] duration must be >=0 or -1 when toev_start is called;
+     * [2] callback may be modified while timeout is running;
+     *      value used is that prevailing when timeout happens
+     * when the timeout happens, TimeoutEvent's state goes from R to I
+     * and then callback member is read and the function called
+     */
+
+void toev_init(TimeoutEvent*);    /* U -> I */
+void toev_start(TimeoutEvent*);   /* IR -> R; reads duration */
+  /* if duration is -1 then is same as toev_stop */
+void toev_stop(TimeoutEvent*);    /* IR -> I */
+
 /*---------- tbi ----------*/
 
 void choreographers_all_abandon(void);
diff --git a/hostside/simulate.c b/hostside/simulate.c
new file mode 100644 (file)
index 0000000..8123e9e
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * realtime
+ * simulation harness
+ */
+
+#include "realtime.h"
+
+typedef struct SimTimeout {
+  struct { struct SimTimeout *back, *next; } l;
+  TimeoutEvent *toev;
+} SimTimeout;
+
+typedef void SimEventFn(void);
+
+static SimEventFn se_timestamp, se_timerevent;
+static SimEventFn se_serial, se_command, se_eof;
+
+static SimTimeout *simtimeouts;
+
+static FILE *siminput;
+static char *sevent_buf;
+static size_t sevent_buflen;
+
+static SimEventFn *sevent_type;
+static char *sevent_data, *sevent_extrap;
+static struct timeval sevent_abst;
+
+/*---------- simulation input stream parser ----------*/
+
+static void simbad(const char *how) __attribute__((noreturn));
+static void simbad(const char *how) {
+  die("bad simulation (in `%s'): %s", sevent_buf, how);
+}
+
+static void sevent(void) {
+  ssize_t gr;
+  char *p;
+
+  if (sevent_type)
+    return;
+
+  for (;;) {
+    gr= getline(&sevent_buf,&sevent_buflen,siminput);
+    if (feof(siminput)) { sevent_type= se_eof; return; }
+    if (ferror(siminput)) diee("read simulation input failed");
+    assert(gr>0);
+    assert(sevent_buf[gr-1]=='\n');
+    sevent_buf[gr-1]= 0;
+    
+#define IF_ET(pfx, et)                                                 \
+    if (!strncmp(pfx " ", sevent_buf, sizeof(pfx))                     \
+       && (sevent_type=(et), p=sevent_buf+(sizeof(pfx))))
+
+    IF_ET("executing", se_command) {
+      sevent_data= p;
+      return;
+    }
+    IF_ET("picioh in", se_serial) {
+      p= strchr(p,' ');
+      if (!p) simbad("missing space after `in'");
+      sevent_data= p+1;
+      return;
+    }
+    IF_ET("timer-event", se_timerevent) {
+      sevent_extrap= strchr(p,'.');
+      if (!sevent_extrap) simbad("missing `.' in timer event name");
+      *sevent_extrap++= 0;
+      sevent_data= p;
+      return;
+    }
+    IF_ET("timestamp", se_timestamp) {
+      int n, r;
+      n=-1;
+      r= sscanf(p,"%ld.%ld%n", &sevent_abst.tv_sec, &sevent_abst.tv_usec, &n);
+      if (r<2 || !(n==-1 || !p[n])) simbad("unparseable timestamp");
+      return;
+    }
+  }
+}
+
+/*---------- hooks for eventhelp ----------*/
+
+void sim_toev_start(TimeoutEvent *toev) {
+  SimTimeout *s= mmalloc(sizeof(*s));
+  s->toev= toev;
+  DLIST1_PREPEND(simtimeouts,s,l);
+}
+
+static void sim_toev_remove(SimTimeout *s) {
+  DLIST1_REMOVE(simtimeouts,s,l);
+  free(s);
+}
+
+void sim_toev_stop(TimeoutEvent *toev) {
+  SimTimeout *s;
+  for (s=simtimeouts; !(s->toev==toev); s=s->l.next);
+  sim_toev_remove(s);
+}
+
+void sim_mgettimeofday(struct timeval *tv) {
+  sevent();
+  *tv= sevent_abst;
+  if (sevent_type==se_timestamp)
+    sevent_type= 0;
+}
+
+/*---------- simulation events ----------*/
+
+static void se_timestamp(void) { }
+
+static void se_timerevent(void) {
+  TimeoutEvent *toev;
+  SimTimeout *s;
+
+  for (s=simtimeouts; s; s=simtimeouts->l.next) {
+    toev= s->toev;
+    if (!strcmp(toev->pclass, sevent_data) &&
+       !strcmp(toev->pinst, sevent_extrap))
+      goto found;
+  }
+  simbad("timeout event not found");
+  
+ found:
+  sim_toev_remove(s);
+  toev_callback(0, sevent_abst, toev);
+}
+
+static void se_serial(void) {
+  int l, buf_used, i;
+  char c[3], *ep;
+  const char *p;
+  Byte *q;
+
+  l= strlen(sevent_data);
+  if (l%2) simbad("odd number of hex digits");
+  l /= 2;
+
+  buf_used= serial_buf.l + l;
+  if (buf_used > sizeof(serial_buf.d)) simbad("serial_buf overrun");
+
+  c[2]= 0;
+  for (i=0, p=sevent_data, q=serial_buf.d+serial_buf.l; i<l; i++, q++) {
+    c[0]= *p++;
+    c[1]= *p++;
+    *q= strtoul(c,&ep,16);
+    if (*ep) simbad("bad hex");
+  }
+  serial_indata_process(buf_used);
+}
+
+static void se_command(void) {
+  ParseState ps;
+  ps.remain= sevent_data;
+  ps.thisword= 0;
+  ps.lthisword= 0;
+  cmdi.doline(&ps,&cmdi);
+}
+
+static void se_eof(void) {
+  exit(0);
+}
+
+/*---------- core ----------*/
+
+void sim_initialise(void) {
+  obc_init_core(&cmdi.out);
+  serial_fd= open("/dev/null",O_WRONLY);
+  if (serial_fd<0) diee("open /dev/null for dummy serial");
+  siminput= fopen(simulate,"r");
+  if (!siminput) diee("open simulation input %s",simulate);
+}
+
+void sim_run(void) {
+  for (;;) {
+    sevent();
+    sevent_type();
+    obc_tryflush(&cmdi.out);
+  }
+}
index 56abfac7b157b8dd7ba27fab1b3fad8930179fcf..d29937895372ab51c6399d4bfddf670b758ce14c 100644 (file)
@@ -132,6 +132,8 @@ void speedmanager_reset_train(Train *tra) {
   tra->speed.step= 0;
   toev_init(&tra->speed.decel);
   tra->speed.decel.callback= decel_done;
+  tra->speed.decel.pclass= "decel";
+  tra->speed.decel.pinst= tra->pname;
   tra->speed.speed= 0;
   tra->speed.try_speed= -1;
   if (tra->addr < 0)
index 189905d069f5a1777ae79fdafa7faa22e36f436a..71a9823e83dc55b0422224b47e1d1d722757953e 100644 (file)
@@ -8,8 +8,8 @@
 const char *const stastatelist[]= DEFINE_STASTATE_DATA;
 StartupState sta_state;
 
-static TimeoutEvent sta_toev;
-static TimeoutEvent ping_toev;
+static TimeoutEvent sta_toev= { .pclass="startup", .pinst="sta" };
+static TimeoutEvent ping_toev= { .pclass="startup", .pinst="ping" };
 
 static int ping_seq;
 static PicInsn piob;
index f9671a118a8d90af09938ecb0528a43ebf4d4f4a..e6b35d3a877c51c84be93654019d62a55aaca468 100644 (file)
@@ -71,12 +71,6 @@ char *mstrdupl(const char *s, int l) {
                  
 char *mstrdup(const char *s) { return mstrdupl(s,strlen(s)); }
 
-void mgettimeofday(struct timeval *tv) {
-  int r;
-  r= gettimeofday(tv,0);
-  if (r) diee("gettimeofday failed");
-}
-
 void mrename(const char *old, const char *new) {
   if (rename(old,new))
     diee("failed to rename `%s' to `%s'", old,new);