From: ian Date: Sun, 4 May 2008 15:42:30 +0000 (+0000) Subject: simulation - compiles but not yet tested X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ijackson/git?a=commitdiff_plain;h=073d37ffdf0b4d79a534405e5bd5750fd30332e2;p=trains.git simulation - compiles but not yet tested --- diff --git a/hostside/Makefile b/hostside/Makefile index b1a2c69..019e724 100644 --- a/hostside/Makefile +++ b/hostside/Makefile @@ -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) diff --git a/hostside/README.commands b/hostside/README.commands index 4d35a5a..b010928 100644 --- a/hostside/README.commands +++ b/hostside/README.commands @@ -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 in junk [...] - U< picioh in aargh [...] - U< picioh in hello [...] - U< picioh in off [...] - U< picioh in toolong [...] - U< picioh in msg [...] + U< picioh in junk [...] + U< picioh in aargh [...] + U< picioh in hello [...] + U< picioh in off [...] + U< picioh in toolong [...] + U< picioh in msg [...] U< picio out polarity <[[,...]]> 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 : U< info : + U> timestamp . + U> timer-event . + ====================================================================== COMMANDS AND RESPONSES P> [...] results in: - R< executing + R< executing [...] consequential messages including picio, signalling problems etc. then one of these R< ack ok diff --git a/hostside/cmdinput.c b/hostside/cmdinput.c index 376b208..8bf11d9 100644 --- a/hostside/cmdinput.c +++ b/hostside/cmdinput.c @@ -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; diff --git a/hostside/common.h b/hostside/common.h index 84532bb..3d7a532 100644 --- a/hostside/common.h +++ b/hostside/common.h @@ -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); diff --git a/hostside/daemons.h b/hostside/daemons.h index 2fd57d4..d0878e6 100644 --- a/hostside/daemons.h +++ b/hostside/daemons.h @@ -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*/ diff --git a/hostside/eventhelp.c b/hostside/eventhelp.c index 4471240..1f65f45 100644 --- a/hostside/eventhelp.c +++ b/hostside/eventhelp.c @@ -1,17 +1,23 @@ /* - * daemons + * realtime * helpers for event handling */ #include #include -#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); + } } diff --git a/hostside/gui-plan.c b/hostside/gui-plan.c index 6515cc0..5596ba3 100644 --- a/hostside/gui-plan.c +++ b/hostside/gui-plan.c @@ -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); diff --git a/hostside/obc.c b/hostside/obc.c index 8534890..e572b5a 100644 --- a/hostside/obc.c +++ b/hostside/obc.c @@ -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) { diff --git a/hostside/realtime.c b/hostside/realtime.c index 8fc791b..f9bf1e7 100644 --- a/hostside/realtime.c +++ b/hostside/realtime.c @@ -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(); } diff --git a/hostside/realtime.h b/hostside/realtime.h index ff3e772..06b0446 100644 --- a/hostside/realtime.h +++ b/hostside/realtime.h @@ -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 index 0000000..8123e9e --- /dev/null +++ b/hostside/simulate.c @@ -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; ispeed.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) diff --git a/hostside/startup.c b/hostside/startup.c index 189905d..71a9823 100644 --- a/hostside/startup.c +++ b/hostside/startup.c @@ -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; diff --git a/hostside/utils.c b/hostside/utils.c index f9671a1..e6b35d3 100644 --- a/hostside/utils.c +++ b/hostside/utils.c @@ -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);