chiark / gitweb /
wip before start to try to compile realtime
authorian <ian>
Wed, 3 May 2006 23:04:59 +0000 (23:04 +0000)
committerian <ian>
Wed, 3 May 2006 23:04:59 +0000 (23:04 +0000)
20 files changed:
hostside/Makefile
hostside/Structure
hostside/cdumgr.c [new file with mode: 0644]
hostside/cmdinput.c [new file with mode: 0644]
hostside/commands.c
hostside/common.h
hostside/daemons.h [new file with mode: 0644]
hostside/eventhelp.c [new file with mode: 0644]
hostside/hostside.h
hostside/multiplex.h [new file with mode: 0644]
hostside/obc.c
hostside/parse-proto-spec
hostside/parseutils.c
hostside/realtime.c [new file with mode: 0644]
hostside/realtime.h [new file with mode: 0644]
hostside/selectout.c [new file with mode: 0644]
hostside/serialio.c
hostside/skelproto-pic.h
hostside/startup.c [new file with mode: 0644]
hostside/utils.c

index a56c4609a7c600437694c6a1bd48ee085fe6e678..9e31d709f68d5c5713d240e4610bf17b9975504d 100644 (file)
@@ -5,7 +5,7 @@ AUTOINCS=       selectors.h
 include ../common.make
 include ../cprogs.make
 
-TARGETS=       hostside hostside-old gui-plan-bot
+TARGETS=       hostside hostside-old gui-plan-bot realtime
 
 default:       all
 recurse:       all
@@ -29,8 +29,6 @@ gui-plan-bot: gui-plan-%: gui-plan.o utils.o parseutils.o \
                 __oop-read-copy.o -loop
                $(LINK) -L/usr/X11R6/lib -lXpm -lX11
 
-commands.o auproto-pic.o: auproto-pic.h
-
 auproto-%:     parse-proto-spec proto-expanded skelproto-%
                ./$+ $o
 
@@ -40,8 +38,14 @@ layoutinfo.h:        ../layout/ours.layout-data.c Makefile
 selectors.h:   selectors.h.gen
                ./$< $o
 
+%.o:           auproto-pic.h
 safety.o trackloc.o: layoutinfo.h
 
+realtime:      realtime.o startup.o cdumgr.o
+               cmdinput.o
+               utils.o serialio.o auproto-pic.o
+               $(LINK)
+
 safety:                safety.o utils.o trackloc.o ../layout/ours.layout-data.o
                $(LINK)
 
index 1e565462e2f07ee29e6a5e77d37571262b6da786..8694d1b82567b648c3bffbaeb6b377d8212d4d74 100644 (file)
@@ -30,7 +30,15 @@ all real-time stuff so clients can be confident of no misthings ?
                  if so check whether we'll be out of the way
          plot new path for this train
 
-deadline scheduler for point change and cdu
+ deadline scheduler for point change and cdu
+
+ for points autochanging
+  lay train an extra 600ms or so
+
+commsn between realtime and multiplexer
+  each command produces `ack' or `error'
+  multiplexer counts responses for flow control
 
 multiplex
  talks to all clients
@@ -39,8 +47,6 @@ multiplex
 
 
 
+startup state machine
 
-
-for points autochanging
- lay train an extra 600ms or so
+ - 
diff --git a/hostside/cdumgr.c b/hostside/cdumgr.c
new file mode 100644 (file)
index 0000000..089d954
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * realtime
+ * cdu and point charge control and scheduler
+ */
+
+#include "realtime.h"
+
+void on_pic_charged(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
+  if (sta_state <= Sta_Settling) return;
+  /* fixme do something here */
+}
+
+void on_pic_pointed(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
+  if (sta_state <= Sta_Settling) return;
+  /* fixme do something here */
+}
diff --git a/hostside/cmdinput.c b/hostside/cmdinput.c
new file mode 100644 (file)
index 0000000..3c93b62
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * realtime & multiplexer
+ * reading and parsing commands from some fd
+ */
+
+#include "daemons.h"
+
+static void *cmdi_exception(oop_source *evts, int fd,
+                           oop_event evt, void *cmdi_v) {
+  CommandInput *cmdi= cmdi_v;
+  cmdi->out.error(&cmdi->out, "error by command source",
+                 "exceptional condition");
+  return OOP_CONTINUE;
+}
+
+static void *cmdi_iferr(oop_source *evts, oop_read *cl_read,
+                       oop_rd_event evt, const char *errmsg, int errnoval,
+                       const char *data, size_t recsz, void *cmdi_v) {
+  CommandInput *cmdi= cmdi_v;
+
+  cmdi->out.error(&cmdi->out, "read",
+               oop_rd_errmsg(cl_read, evt,
+                             errnoval, OOP_RD_STYLE_GETLINE));
+  return OOP_CONTINUE;
+}
+
+static void *client_ifok(oop_source *evts, oop_read *cl_read,
+                        oop_rd_event evt, const char *errmsg, int errnoval,
+                        const char *data, size_t recsz, void *cmdi_v) {
+  CommandInput *cmdi= cmdi_v;
+  ParseState ps;
+
+  if (evt == OOP_RD_EOF) {
+    cmdi->out.error(&cmdi->out,0,0);
+    return OOP_CONTINUE;
+  }
+  
+  if (evt != OOP_RD_OK)
+    return client_iferr(evts,cl_read,evt,errmsg,errnoval,data,recsz,cl_v);
+
+  ps.cl= 0;
+  ps.remain= data;
+  cmdi->doline(&ps, cmdi);
+  return OOP_CONTINUE;
+}
+
+void cmdin_new(CommandInput *cmdi, int readfd) {
+  obc_init(&cmdi->out);
+
+  events->on_fd(events, readfd, OOP_EXCEPTION, cmdi_exception, cmdi);
+
+  cmdi->rd= oop_rd_new_fd(events, fd, 0,0);
+  if (!cmdi->rd) diee("oop_rd_new_fd");
+  r= oop_rd_read(cl->rd, OOP_RD_STYLE_GETLINE, 1024,
+                client_ifok, cmdi,
+                client_iferr, cmdi);
+  if (r) diee("oop_rd_read");  
+}
index b14ed033052579e1c4e53162f871744372c3bccc..4683877b2aceb3c3a90a5f68cb27b5364152049f 100644 (file)
@@ -33,6 +33,10 @@ struct NmraParseEncodeCaller {
   jmp_buf jb;
 };
 
+static void ouack(const CmdInfo *ci) {
+  oprintf(UPO, "ack %s\n", ci->name);
+}
+
 unsigned long nmra_argnumber(NmraParseEncodeCaller *pec, int argi) {
   return pec->arg[argi];
 }
@@ -130,6 +134,7 @@ static void cmd_nmra(ParseState *ps, const CmdInfo *ci) {
     }
     free(mrn->name);
     free(mrn);
+    ouack(ci);
     return;
   }
 
@@ -145,19 +150,13 @@ static void cmd_nmra(ParseState *ps, const CmdInfo *ci) {
     retransmit_queue(&mrn->rn);
   else
     serial_transmit(&rn->pi);
+  ouack(ci);
 }
 
 static void cmd_noop(ParseState *ps, const CmdInfo *ci) {
-  oprintf(&ps->cl->ch,"noop successful\n");
+  ouack(ci);
 }
 
-typedef struct PicCmdInfo PicCmdInfo;
-struct PicCmdInfo {
-  const char *name;
-  Byte opcode;
-  int argbits;
-};
-
 static void cmd_pic(ParseState *ps, const CmdInfo *ci) {
   const PicInsnInfo *pii;
   PicInsn pi;
@@ -183,6 +182,7 @@ static void cmd_pic(ParseState *ps, const CmdInfo *ci) {
     enco_pic_anyinsn(&pi, pii, arg);
   }
   serial_transmit(&pi);
+  ouack(ci);
 }
 
 const CmdInfo toplevel_cmds[]= {
index ff3c12c9d654c2d71ea5003624552c63b79c7581..1d11bb54b865dfe0ef5a0b21022c0491108fc228 100644 (file)
@@ -9,6 +9,8 @@
 #define COMMON_H
 
 #include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
 
 /*---------- types ----------*/
 
@@ -27,7 +29,7 @@ typedef struct PicInsn {
   int l;
 } PicInsn;
 
-/*---------- from serialio.c ----------*/
+/*---------- from utils.c ----------*/
 
 void vdie(const char *fmt, int ev, va_list al)
      __attribute__((noreturn,format(printf,1,0)));
@@ -35,12 +37,15 @@ void die(const char *fmt, ...) __attribute__((noreturn,format(printf,1,2)));
 void diee(const char *fmt, ...) __attribute__((noreturn,format(printf,1,2)));
 void diem(void) __attribute__((noreturn));
 
-void serial_open(const char *device);
-void serial_transmit_now(const Byte *command, int length);
-
 void *mmalloc(size_t sz);
 char *mstrdupl(const char *s, int l);
 char *mstrdup(const char *s);
+void mgettimeofday(struct timeval *tv);
+
+/*---------- from serialio.c ----------*/
+
+void serial_open(const char *device);
+void serial_transmit_now(const Byte *command, int length);
 
 extern int serial_fd, serial_fudge_delay;
 
diff --git a/hostside/daemons.h b/hostside/daemons.h
new file mode 100644 (file)
index 0000000..836680e
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * declarations common to
+ *  - realtime daemon
+ *  - multiplexer daemon
+ */
+
+#ifndef DAEMONS_H
+#define DAEMONS_H
+
+#include <oop.h>
+#include <oop-read.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+/*---------- from obc.c ----------*/
+
+typedef struct OutBuffer OutBuffer;
+typedef struct OutBufferChain OutBufferChain;
+typedef void OutBufferError(OutBufferChain*, const char *e1, const char *e2
+                           /* both e1 and e2 always non-0.  say `$e1: $e2');
+
+struct OutBufferChain {
+  /* set by user: */
+  char *desc;
+  int fd;
+  OutBufferError *error;
+  /* set/used by obc_..., oprintf, etc., only */
+  int done_of_head;
+  struct { OutBuffer *head, *tail; } obs;
+};
+
+void obc_init(OutBufferChain *ch);
+
+void ovprintf(OutBufferChain *ch, const char *fmt, va_list al)
+     __attribute__((format(printf,2,0)));
+void oprintf(OutBufferChain *ch, const char *msg, ...)
+     __attribute__((format(printf,2,3)));
+void owrite(OutBufferChain *ch, const char *data, int l);
+
+/*---------- from cmdinput.c ----------*/
+
+typedef void CommandInputCallback(ParseState *ps, CommandInput *cmdi);
+
+struct CommandInput {
+  OutBufferChain out;
+  CommandInputCallback *doline;
+  oop_read *rd;
+};
+
+struct ParseState {
+  Client *cl; /* used only by multiplexer */
+  const char *remain;
+  const char *thisword;
+  int lthisword;
+};
+
+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*);    /* B -> 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 */
+
+/*---------- from parseutils.c ----------*/
+
+void vbadcmd(ParseState *ps, const char *fmt, va_list al)
+  __attribute__((format(printf,2,0)));
+void badcmd(ParseState *ps, const char *fmt, ...)
+  __attribute__((format(printf,2,3)));
+
+int lstrstrcmp(const char *a, int la, const char *b);
+int thiswordstrcmp(ParseState *ps, const char *b);
+
+int ps_word(ParseState *ps);
+int ps_needword(ParseState *ps);
+int ps_needhextoend(ParseState *ps, Byte *dbuf, int *len_io);
+int ps_neednumber(ParseState *ps, long *r, long min, long max, const char *wh);
+int ps_neednoargs(ParseState *ps);
+
+/*---------- macro for table lookups, with help from parseutils.c ----------*/
+
+#define some_lookup(ps, infos)                 \
+  ((const typeof(infos[0])*)                   \
+   any_lookup((ps),(infos),sizeof((infos)[0])))
+
+#define some_needword_lookup(ps, infos, what)                  \
+  ((const typeof(infos[0])*)                                   \
+   any_needword_lookup((ps),(infos),sizeof((infos)[0]),(what)))
+
+const void *any_lookup(ParseState *ps, const void *infos, size_t infosz);
+const void *any_needword_lookup(ParseState *ps, const void *infos,
+                               size_t sz, const char *what);
+
+#endif /*DAEMONS_H*/
diff --git a/hostside/eventhelp.c b/hostside/eventhelp.c
new file mode 100644 (file)
index 0000000..8b3dd05
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * daemons
+ * helpers for event handling
+ */
+
+#include "daemons.h"
+
+oop_source *events;
+
index b2c73f5fbc2c6e955cee1c06ed7296bf4fa018a2..8d1ed6d37698a7574793e20395d94e153ac5377b 100644 (file)
@@ -25,34 +25,12 @@ extern oop_source *events;
 
 /*---------- from client.c ----------*/
 
-struct ParseState {
-  Client *cl;
-  const char *remain;
-  const char *thisword;
-  int lthisword;
-};
-
 struct CmdInfo {
   const char *name;
   void (*fn)(ParseState *ps, const CmdInfo *ci);
   int xarg;
 };
 
-int lstrstrcmp(const char *a, int la, const char *b);
-int thiswordstrcmp(ParseState *ps, const char *b);
-
-int ps_word(ParseState *ps);
-int ps_needword(ParseState *ps);
-int ps_needhextoend(ParseState *ps, Byte *dbuf, int *len_io);
-void ps_callword(ParseState *ps, const CmdInfo *infs, const char *what);
-int ps_neednumber(ParseState *ps, long *r, long min, long max, const char *wh);
-int ps_neednoargs(ParseState *ps);
-
-void vbadcmd(ParseState *ps, const char *fmt, va_list al)
-     __attribute__((format(printf,2,0)));
-void badcmd(ParseState *ps, const char *fmt, ...)
-     __attribute__((format(printf,2,3)));
-
 void stdin_client(void);
 
 extern const CmdInfo toplevel_cmds[]; /* defined in commands.c*/
@@ -67,17 +45,3 @@ struct RetransmitNode {
 
 void retransmit_queue(RetransmitNode *rn);
 void retransmit_cancel(RetransmitNode *rn);
-
-/*---------- macro for table lookups, with help from client.c ----------*/
-
-#define some_lookup(ps, infos)                 \
-  ((const typeof(infos[0])*)                   \
-   any_lookup((ps),(infos),sizeof((infos)[0])))
-
-#define some_needword_lookup(ps, infos, what)                  \
-  ((const typeof(infos[0])*)                                   \
-   any_needword_lookup((ps),(infos),sizeof((infos)[0]),(what)))
-
-const void *any_lookup(ParseState *ps, const void *infos, size_t infosz);
-const void *any_needword_lookup(ParseState *ps, const void *infos,
-                               size_t sz, const char *what);
diff --git a/hostside/multiplex.h b/hostside/multiplex.h
new file mode 100644 (file)
index 0000000..81d3b13
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * multiplexer daemon
+ * declarations
+ */
+
+#ifndef MULTIPLEX_H
+#define MULTIPLEX_H
+
+#include "daemons.h"
+
+typedef struct Client Client;
+
+/*---------- from output.c ----------*/
+
+typedef unsigned long Selector;
+#include "selectors.h"
+
+void sovprintf(Selector sel, const char *fmt, va_list al)
+     __attribute__((format(printf,2,0)));
+void soprintf(Selector sel, const char *fmt, ...)
+     __attribute__((format(printf,2,3)));
+void sowrite(Selector sel, const char *data, int l);
+
+void serial_transmit(const PicInsn *pi);
+
+void output_hex(Selector sel, const char *work,
+               const Byte *command, int length);
+
+
+
+
+ unredacted
+
+struct ClientList { Client *head, *tail; };
+extern struct ClientList clients;
+
+struct Client {
+  CommandInput ci;
+  Client *back, *next;
+  Selector sel;
+};
+
+
+
+
+#endif /*MULTIPLEX_H*/
index bc272de697ba1000aba52dcaa20e20031ba7fe0f..ef294fcdf01bf1ab4c481df94cb249ca0ccb1371 100644 (file)
@@ -57,6 +57,8 @@ static void addlink(OutBufferChain *ch, OutBuffer *ob) {
 
 void obc_init(OutBufferChain *ch) {
   ch->done_of_head= 0;
+  r= oop_fd_nonblock(ch->fd, 1);
+  if (r) diee("nonblock(OutBufferChain->fd,1)");
   LIST_INIT(ch->obs);
 }
 
index 1698ebab49f899f0f25c00868ce834cd2dbf6b57..5564ca2d5a1b95ffec0179c22c32ecf1cf76cafd 100755 (executable)
@@ -93,6 +93,7 @@ sub process_line () {
        $v{dname}= $dname;
        $v{cname}= $cname;
        $v{cnameyn}= $cname.$yval;
+       $v{cnameynu}= uc($cname.$yval);
        $v{opcode}= b2xh($opcode, 0);
        $v{opcodeyn}= b2xh($opcode, $ybit * $yval);
        $v{opcodemask}= b2xh($opcodemask, 0);
index 99e138504ca6da39bba686d2097009b6def1b570..89ab4ba6be8d06ec3d6b3191905961ee87f96270 100644 (file)
@@ -7,6 +7,12 @@
 
 #include "hostside.h"
 
+void vbadcmd(ParseState *ps, const char *fmt, va_list al) {
+  oprintf(&ps->ci->out,"error ");
+  ovprintf(&ps->ci->out,fmt,al);
+  owrite(&ps->ci->out,"\n",1);
+}
+
 void badcmd(ParseState *ps, const char *fmt, ...) {
   va_list al;
   va_start(al,fmt);
@@ -90,6 +96,27 @@ int ps_needhextoend(ParseState *ps, Byte *d, int *len_io) {
   return 1;
 }
 
+
+const void *any_lookup(ParseState *ps, const void *inf, size_t sz) {
+  const char *tname;
+  
+  for (;
+       (tname= *(const char *const*)inf);
+       inf= (const char*)inf + sz)
+    if (!thiswordstrcmp(ps,tname))
+      return inf;
+  return 0;
+}
+
+const void *any_needword_lookup(ParseState *ps, const void *infs,
+                               size_t sz, const char *what) {
+  const void *r;
+  if (!ps_needword(ps)) return 0;
+  r= any_lookup(ps,infs,sz);
+  if (!r) { badcmd(ps,"unknown %s",what); return 0; }
+  return r;
+}
+
 int lstrstrcmp(const char *a, int la, const char *b) {
   int lb, minl, r;
 
diff --git a/hostside/realtime.c b/hostside/realtime.c
new file mode 100644 (file)
index 0000000..59285eb
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * main program for realtime control
+ */
+
+#include "realtime.h"
+
+/*---------- global variables ----------*/
+
+CommandInput cmdi;
+
+static const char *device;
+
+/*---------- general event handling ----------*/
+
+static void comms_error(const char *ch, const char *e1,
+                       const char *e2 /* may be 0 */) {
+  die("communications error: %s: %s%s%s", ch, e1, e2?": ":"", e2?e2:"");
+}
+
+static void *read_exception(oop_source *evts, int fd,
+                           oop_event evt, void *cl_v) {
+  OutBufferChain *ch;
+  char bufc;
+  int r;
+
+  ch= (fd==up_ochain.fd ? up_ochain.desc :
+       fd==serial_fd ? "serial port" :
+       0);
+  
+  r= read(fd, &bufc, 1);
+  if (r==-1) comms_error(ch, "read error", strerror(errno));
+  else if (r==0) comms_error(ch, "reports exception, reads EOF", 0);
+  else comms_error(ch, "reports exception, but readable", 0);
+}
+
+/*---------- command channel handling (oop_read, obc) ----------*/
+
+static void command_doline(ParseState *ps, CommandInput *cmdi) {
+  const CmdInfo *ci;
+  ci= some_needword_lookup(ps, toplevel_cmds, "command");
+  if (ci) ci->fn(ps,ci);
+}
+
+void oupicio(const char *dirn, const PicInsnInfo *pii, int objnum) {
+  if (!pii->argbits)
+    oprintf(UPO, "picio %s %s\n", dirn, pii->name);
+  else
+    oprintf(UPO, "picio %s %s %u\n", dirn, pii->name, objnum);
+}
+
+static void obc_error(OutBufferChain *ch, const char *e1, const char *e2) {
+  comms_error(ch->desc, e1, e2);
+}
+
+void ouhex(const char *word, const Byte *command, int length) {
+  oprintf(UPO, "%s", word);
+  while (length) {
+    oprintf(UPO, " %02x", *command++);
+    length--;
+  }
+  oprintf(UPO, "\n");
+}
+
+/*---------- serial input (via oop) ----------*/
+
+static PicInsn serial_buf;
+
+static void *serial_readable(oop_source *evts, int fd,
+                            oop_event evt, void *u0) {
+  const Byte *ep;
+  int r, buf_used;
+
+  r= read(serial_fd, &serial_buf.d, sizeof(serial_buf.d) - serial_buf.l);
+  if (r==0) die("serial port - eof");
+  if (r==-1) {
+    if (errno == EWOULDBLOCK || errno == EINTR)
+      return OOP_CONTINUE;
+    diee("serial port - read error");
+  }
+  assert(r>0);
+
+  buf_used= serial_buf.l;
+  buf_used += r;
+
+  for (;;) {
+    serial_buf.l= buf_used;
+    serial_moredata(&serial_buf);
+    if (!serial_buf.l) break;
+    buf_used -= serial_buf.l;
+    memmove(serial_buf.d, serial_buf.d + serial_buf.l, buf_used);
+  }
+  serial_buf.l= buf_used;
+  return OOP_CONTINUE;
+}
+
+/*---------- serial port output (not via liboop) ----------*/
+
+void serial_transmit(const PicInsn *pi) {
+  const PicInsnInfo *pii;
+  int objnum;
+  
+  picinsn_decode(pi, pic_command_infos, &pii, &objnum);
+
+  if (!pii)
+    oprintf(UPO, "picio out unknown\n");
+  else
+    oupicio("out",pii,objnum);
+
+  ouhex("picioh out", pi->d, pi->l);
+
+  /* note that the serial port is still in nonblocking mode.  if
+   * we ever buffer up far enough that the kernel wants to make us
+   * block, we should die! */
+  serial_transmit_now(pi->d, pi->l);
+}
+
+/*---------- initialisation ----------*/
+
+int main(int argc, const char **argv) {
+  oop_source_sys *sys_events;
+  int r;
+
+  device= argv[1];
+  if (!device) device= "/dev/ttyS0";
+
+  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);
+
+  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);
+
+  oop_sys_run(sys_events);
+  abort();
+}
diff --git a/hostside/realtime.h b/hostside/realtime.h
new file mode 100644 (file)
index 0000000..b98c547
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * declarations for multiplexer daemon
+ */
+
+#ifndef REALTIME_H
+#define REALTIME_H
+
+typedef struct RetransmitNode RetransmitNode;
+
+extern CommandInput cmdi;
+
+typedef enum {   /* sta_toev   ping_toev    */
+  Sta_Flush,     /*  R 300      I ?         */
+  Sta_Off,       /*  I ?        I ?         */
+  Sta_Ping,      /*  I ?        I ?         */
+  Sta_Fault,     /*  I ?        R set       */
+  Sta_Settling,  /*  I ?        R set       */
+  Sta_Resolving, /*  I ?        R set       */
+  Sta_Run        /*  I ?        R set       */
+} StartupState;
+
+#define UPO (&(cmdi->out));
+
+#endif /*REALTIME_H*/
diff --git a/hostside/selectout.c b/hostside/selectout.c
new file mode 100644 (file)
index 0000000..4f470d0
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * mulitplexer daemon
+ * transmissions to clients of their selected messages
+ */
+
+#include <string.h>
+#include <stdarg.h>
+
+#include "multiplex.h"
+#include "auproto-pic.h"
+
+#define FOR_CLS(s) do{                         \
+    Client *cl, *next_cl;                      \
+    for (cl= clients.head;                     \
+        cl;                                    \
+        cl= next_cl) {                         \
+      OutBufferChain *ch= &cl->ch;             \
+      next_cl= cl->next;                       \
+      if (!(sel & cl->sel)) continue;          \
+      s;                                       \
+    }                                          \
+  }while(0)
+
+void sovprintf(Selector sel, const char *fmt, va_list al) {
+  FOR_CLS( ovprintf(ch, fmt, al) );
+}
+
+void soprintf(Selector sel, const char *fmt, ...)
+  { va_list al; va_start(al,fmt); sovprintf(sel,fmt,al); va_end(al); }
+
+void sowrite(Selector sel, const char *data, int l) {
+  FOR_CLS( owrite(ch, data, l) );
+}
index 1075de9f9d5fd7e0bd69713c0b2cbb502f271228..f1b9a7cdd5b342aa06c54a663a0aa439d3cfa95a 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * common
  * general serial i/o and system interface etc.
  */
 
index d2e9036078863a24347064d2b74a76131b0ba308..f748382bbf1abd13b3e22664949eb394ea9ec738 100644 (file)
@@ -16,6 +16,9 @@ typedef void PicInputFn(const PicInsnInfo *pii, const PicInsn *pi, int objnum);
 void enco_pic_@cname@(PicInsn *out);            @h2p@ @arglentf=0@
 void enco_pic_@cname@(PicInsn *out, int objum); @h2p@ @arglentf=1@
 PicInputFn on_pic_@cnameyn@;                    @p2h@
+#define PICMSG_@cnameynu@       @opcodeyn@
+#define PICMSG_@cnameynu@_M     @opcodemaskyn@
+#define PICMSG_@cnameynu@_P(v)  (((v) & @opcodemaskyn@) == @opcodeyn@)
 
 extern void enco_pic_polarity_begin(PicInsn *out);
 extern void enco_pic_polarity_setbit(PicInsn *out, int objnum);
diff --git a/hostside/startup.c b/hostside/startup.c
new file mode 100644 (file)
index 0000000..a72a0b0
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * realtime
+ * startup state machine
+ */
+
+#include "realtime.h"
+
+static StartupState sta_state;
+static TimeoutEvent sta_toev;
+
+static int ping_seq;
+static PicInsn *piob;
+static void sta_goto(StartupState new_state);
+
+static void timedout_onward(TimeoutEvent *toev) {
+  assert(sta_state != Sta_Run);
+  sta_goto(sta_state + 1);
+}
+
+static void timedout_ping(TimeoutEvent *toev) {
+  assert(sta_state >= Sta_Ping);
+  sta_goto(Sta_Off);
+}
+
+static void timefor_ping(TimeoutEvent *toev) {
+  serial_transit(&ping_pi);
+  toev_start(&ping_toev);
+}
+
+static void initial_ping(void) {
+  struct timeval now;
+  
+  ping_toev.callback= timedout_ping;
+  ping_toev.duration=  300;
+  mgettimeofday(&now);
+  ping_seq= (now.tv_sec & 0x1fU) << 5; /* bottom 5bi of secs: period 32s */
+  ping_seq |= (now.tv_usec >> 15);      /* top 5bi of 20bi us: res.~2^15us */
+  enco_pic_ping(&piob, ping_seq);
+  serial_transmit(&piob);
+  timefor_ping(0);
+}
+
+static void sta_goto(StartupState new_state) {
+  toev_stop(&sta_toev);
+  sta_toev.callback= timedout_onward;
+  sta_toev.callback= -1;
+
+  toev_stop(&ping_toev);
+  ping_toev.callback= timedout_ping;
+  ping_toev.duration= -1;
+
+  if (new_state < Sta_Ping) {
+    toev_stop(&ping_toev);
+  } else if (new_state == Sta_Ping) {
+    initial_ping();
+  } else {
+    assert(sta_state >= Sta_Ping);
+  }
+
+  switch (new_state) {
+  case Sta_Flush:      sta_toev.duration=   300;   break;
+  case Sta_Off:                                    break;
+  case Sta_Ping:                                   break;
+  case Sta_Fault:                                  break;
+  case Sta_Settling:   sta_toev.duration=  2000;   break;
+  case Sta_Resolving:  sta_toev.duration=   500;   break;
+  case Sta_Run:                                    break;
+  }
+
+  piob.l= 0;
+  switch (new_state) {
+  case Sta_Flush:                                                  break;
+  case Sta_Off:   if (sta_state > Sta_Ping) enco_pic_off(&piob);   break;
+  case Sta_Ping:                                                   break;
+  case Sta_Fault:                                                  break;
+  case Sta_Settling:                        enco_pic_off(&piob);   break;
+  case Sta_Resolving:                       enco_pic_on(&piob);    break;
+  case Sta_Run:                                                    break;
+  }
+  if (piob.l) serial_transmit(&piob);
+
+  toev_start(&sta_toev);
+  sta_state= new_state;
+  notify_startup(new_state);
+}   
+
+void serial_moredata(PicInsn *buf) {
+  const PicInsnInfo *pii;
+  int objnum;
+  char *&ep
+
+  /* Called when more data is received from PICs.
+   * On entry, buf->l is amount of data available.
+   * Does one of the following:
+   *  - determines that there is no complete message; sets buf->l = 0
+   *  - finds and handles one PicInsn message, sets buf->l = message length
+   *  - handles some series of bytes structured some other way,
+   *       sets buf->l to the numer of bytes handled.
+   */
+  assert(buf->l > 0);
+  
+  if (sta_state == Sta_Flush) {
+    toev_start(&sta_toev);
+    ouhex("picioh in junk", buf->d, buf->l);
+    return; /* junk absolutely everything */
+  }
+  if (PICMSG_AAARGH_P(buf->d[0])) {
+    ouhex("picioh in aaargh", buf->d, buf->l);
+    die("PIC sent us AAARGH!");
+  }
+  if (PICMSG_HELLO_P(buf->d[0])) {
+    ouhex("picioh in hello", buf->d, 1);
+    abandon_run();
+    sta_goto(Sta_Flush);
+    buf->l= 1;
+    return;
+  }
+  if (sta_state == Sta_Off) {
+    ouhex("picioh in off", buf->d, 1);
+    buf->l= 1;
+    return;
+  }
+
+  assert(sta_state >= Sta_Ping);
+  /* So, we are expecting properly formed messages. */
+  
+  for (ep= buf->d; ep < buf->d + buf->l; ep++)
+    if (!(*ep & 0x80u))
+      goto found_end;
+
+  if (buf->l == sizeof(buf->d)) {
+    ouhex("picioh in toolong", buf->d, buf->l);
+    die("PIC sent packet too long");
+  }
+  return 0;
+
+ found_end:
+  /* Aha! */
+  buf->l= ep - buf->d;
+  ouhex("picioh in msg", buf->d, buf->l);
+  picinsn_decode(&buf, pic_reply_infos, &pii, &objnum);
+  if (!pii) { oprintf(UPO, "picio in unknown\n"); return; }
+  oupicio("in",pii,objnum);
+  pii->input_fn(pii,pi,objnum);
+}
+
+void on_pic_pong(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
+  if (objnum != ping_seq)
+    die("PIC sent wrong ping response (0x%x, wanted 0x%x)", objnum, ping_seq);
+
+  if (sta_state == Sta_Ping) {
+    sta_goto(Sta_Settling);
+  } else {
+    ping_toev.callback= timedfor_ping;
+    toev_start(&ping_toev);
+  }
+}
+
+void on_pic_fixed(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
+  if (sta_state >= Sta_Resolving) die("PIC sent unexpected FIXED");
+  if (sta_state == Sta_Fault) sta_goto(Sta_Settling);
+}
+
+void on_pic_fault(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
+  if (sta_state <= Sta_Ping) return;
+  if (sta_state == Sta_Fault) die("PIC sent two FAULTs");
+  sta_goto(Sta_Fault);
+}
+
+void on_pic_watchdog(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
+  if (sta_state <= Sta_Settling) return;
+  if (sta_state == Sta_Resolving) die("PIC sent WATCHDOG in Resolving");
+  oprintf(UPO, "warning watchdog \"PIC watchdog timer triggered\"\n");
+}
+
+/*---------- fixme move these to where they want to go ----------*/
+
+void on_pic_nmradone(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
+  if (sta_state <= Sta_Settling) return;
+  if (sta_state != Sta_Run) die("PIC sent NMRADONE in Resolving");
+  /* fixme transmit something else (move this to another file?) */
+}
+
+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 */
+}
index b6c44948f8f7a14fb9b0a4e706f21702c5b2bc9f..db2318471bd78543cff85416481424f9af7de5a6 100644 (file)
@@ -1,4 +1,7 @@
-/**/
+/*
+ * common
+ * general utility functions
+ */
 
 #include <stdarg.h>
 #include <errno.h>
@@ -6,9 +9,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#include "hostside.h"
+#include "common.h"
 
 void vdie(const char *fmt, int ev, va_list al) {
+  fprintf(stderr, "%s: fatal: ", progname);
   vfprintf(stderr,fmt,al);
   if (ev) fprintf(stderr,": %s",strerror(ev));
   fputc('\n',stderr);
@@ -39,3 +43,8 @@ char *mstrdupl(const char *s, int l) {
 }
                  
 char *mstrdup(const char *s) { return mstrdupl(s,strlen(s)); }
+
+void mgettimeofday(struct timeval *tv) {
+  r= gettimeofday(tv,0);
+  if (r) diee("gettimeofday failed");
+}