chiark / gitweb /
new "hostside" wip has an event loop
authorian <ian>
Mon, 30 May 2005 01:32:03 +0000 (01:32 +0000)
committerian <ian>
Mon, 30 May 2005 01:32:03 +0000 (01:32 +0000)
hostside/.cvsignore
hostside/Makefile
hostside/README
hostside/hostside.c [new file with mode: 0644]
hostside/hostside.h
hostside/serialio.c

index 52a5ddffe5c12720384fbc95cf1d2cef9c3207ec..d8fc9926f99c88d241514379a70740c16ce13efd 100644 (file)
@@ -1,4 +1,5 @@
 hostside
+hostside-old
 safety
 t
 layoutinfo.h
index 545a9910172ca78d7eb8ce637786c3b6ee82d36e..117bd491d59bebfd170b18647795303ec9f2bb61 100644 (file)
@@ -3,14 +3,14 @@
 include ../common.make
 include ../cprogs.make
 
-TARGETS=       hostside #safety
-CFLAGS=                -Wall -Werror -Wstrict-prototypes -Wmissing-prototypes \
-               -Wpointer-arith -Wwrite-strings -g $(OPTIMISE)
-OPTIMISE=      -O2
+TARGETS=       hostside hostside-old
 
 all:           $(TARGETS)
 
-hostside:      serialio.o nmra.o main.o encode.o
+hostside-old:  serialio.o nmra.o main.o encode.o
+               $(LINK)
+
+hostside:      hostside.o serialio.o -loop
                $(LINK)
 
 layoutinfo.h:  ../layout/ours.layout-data.c Makefile
index 8f8e7f893c27100075735230f4ac353b7923f22f..5fc572cc885b8ee68c7ad666f1abf89fc945d487 100644 (file)
@@ -36,14 +36,14 @@ Protocol over new hostside stdin:
 
  P> nmra-x <nmra-command> [<nmra-args>...]
  P> nmra-1 <nmra-command> [<nmra-args>...]
- P> nmra-raw-x <nmra-data-hex>...
- P> nmra-raw-1 <nmra-data-hex>...
+ P> xmit-x <nmra-data-hex>...
+ P> xmit-1 <nmra-data-hex>...
        *-1 means transmit it once
        *-x means put it in the transmission cycle; to cancel,
             ask for   nmra-x idle
 
- P> raw <pic-command-data-hex>...
  P> pic <pic-command> [<pic-args>...]
+ P> raw <pic-command-data-hex>...
        eg  pic point 3  ==  raw a003
        for commands with no `...' in README.protocol only
  P> polarity <bit-string-in-hex>....
diff --git a/hostside/hostside.c b/hostside/hostside.c
new file mode 100644 (file)
index 0000000..414e769
--- /dev/null
@@ -0,0 +1,213 @@
+/**/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <oop.h>
+#include <oop-read.h>
+
+#include "../layout/dlist.h"
+#include "hostside.h"
+
+oop_source *events;
+FILE *dump_stream= 0;
+
+typedef struct OutBuffer OutBuffer;
+struct OutBuffer {
+  OutBuffer *back, *next;
+  char *m;
+  int l;
+};
+typedef struct OutBufferChain OutBufferChain;
+struct OutBufferChain {
+  const char *what;
+  int fd;
+  int done_of_head;
+  struct { OutBuffer *head, *tail; } obs;
+};
+static OutBufferChain stdin_ochain= { "stdin", 0 };
+static OutBufferChain serial_ochain= { "serial", -1 };
+
+static void *ochain_writeable(oop_source *evts, int fd,
+                             oop_event evt, void *ch_v) {
+  OutBufferChain *ch= ch_v;
+  OutBuffer *ob;
+  int r;
+  
+  assert(fd == ch->fd);
+  assert(evt == OOP_WRITE);
+
+  for (;;) {
+    ob= ch->obs.head;
+    if (!ob) {
+      events->cancel_fd(events, fd, OOP_WRITE);
+      events->cancel_fd(events, fd, OOP_EXCEPTION);
+      return OOP_CONTINUE;
+    }
+    if (ch->done_of_head == ob->l) {
+      LIST_UNLINK(ch->obs, ob);
+      free(ob);
+      free(ob->m);
+      ch->done_of_head= 0;
+      continue;
+    }
+    r= write(ch->fd, ob->m + ch->done_of_head, ob->l - ch->done_of_head);
+    if (r==-1) {
+      if (errno==EINTR) continue;
+      if (errno==EWOULDBLOCK) return OOP_CONTINUE;
+      diee(ch->what);
+    }
+    assert(r>=0);
+    ch->done_of_head += r;
+    assert(ch->done_of_head <= ob->l);
+  }
+}
+
+static void *ochain_exception(oop_source *evts, int fd,
+                             oop_event evt, void *ch_v) {
+  OutBufferChain *ch= ch_v;
+  die(ch->what);
+}
+
+static void ochain_addlink(OutBufferChain *ch, OutBuffer *ob) {
+  if (!ch->obs.head) {
+    events->on_fd(events, ch->fd, OOP_WRITE, ochain_writeable, ch);
+    events->on_fd(events, ch->fd, OOP_EXCEPTION, ochain_exception, ch);
+  }
+  LIST_LINK_TAIL(ch->obs, ob);
+}
+
+static void ovprintf(const char *fmt, va_list al)
+     __attribute__((format(printf,1,0)));
+static void ovprintf(const char *fmt, va_list al) {
+  OutBuffer *ob;
+
+  ob= malloc(sizeof(*ob));  if (!ob) diem();
+  ob->l= vasprintf(&ob->m, fmt, al);  if (ob->l <= 0) diem();
+  ochain_addlink(&stdin_ochain, ob);
+}
+
+static void oprintf(const char *msg, ...) __attribute__((format(printf,1,2)));
+static void oprintf(const char *msg, ...) {
+  va_list al;
+  va_start(al,msg);
+  ovprintf(msg,al);
+  va_end(al);
+}
+
+static void badcmd(const char *how) {
+  oprintf("error %s\n",how);
+}
+
+static void cmd_noop(ParseState *ps, const CmdInfo *ci) {
+  oprintf("noop successful\n");
+}
+
+static const CmdInfo toplevel_cmds[]= {
+#if 0
+  { "nmra-x", cmd_nmra_x  },
+  { "nmra-1", cmd_nmra_1  },
+  { "xmit-x", cmd_xmit_x  },
+  { "xmit-1", cmd_xmit_1  },
+  { "pic",    cmd_pic     },
+  { "raw",    cmd_raw     },
+#endif
+  { "noop",   cmd_noop    },
+  { 0 }
+};
+
+static int ps_needword(ParseState *ps) {
+  const char *space;
+  if (!ps->remain) { badcmd("too few args"); return 0; }
+  space= strchr(ps->remain, ' ');
+  ps->thisword= ps->remain;
+  if (space) {
+    ps->lthisword= space - ps->thisword;
+    ps->remain= space + 1;
+  } else {
+    ps->lthisword= strlen(ps->remain);
+    ps->remain= 0;
+  }
+  return 1;
+}
+
+static const CmdInfo *ps_lookup(ParseState *ps, const CmdInfo *inf) {
+  for (;
+       inf->name;
+       inf++)
+    if (ps->lthisword == strlen(inf->name) &&
+       !memcmp(ps->thisword, inf->name, ps->lthisword))
+      return inf;
+  return 0;
+}
+
+static const CmdInfo *ps_needword_lookup(ParseState *ps, const CmdInfo *infs) {
+  if (!ps_needword(ps)) return 0;
+  return ps_lookup(ps,infs);
+}
+  
+static void *stdin_iferr(oop_source *evts, oop_read *stdin_read,
+                        oop_rd_event evt, const char *errmsg, int errnoval,
+                        const char *data, size_t recsz, void *u0)
+     __attribute__((noreturn));
+static void *stdin_iferr(oop_source *evts, oop_read *stdin_read,
+                        oop_rd_event evt, const char *errmsg, int errnoval,
+                        const char *data, size_t recsz, void *u0) {
+  fprintf(stderr,"stdin %s\n",
+         oop_rd_errmsg(stdin_read, evt, errnoval, OOP_RD_STYLE_GETLINE));
+  exit(4);
+}
+
+static void *stdin_ifok(oop_source *evts, oop_read *stdin_read,
+                       oop_rd_event evt, const char *errmsg, int errnoval,
+                       const char *data, size_t recsz, void *u0) {
+  ParseState ps;
+  const CmdInfo *ci;
+
+  if (evt == OOP_RD_EOF)
+    exit(0);
+  if (evt != OOP_RD_OK)
+    stdin_iferr(evts,stdin_read,evt,errmsg,errnoval,data,recsz,u0);
+  
+  ps.remain= data;
+  ci= ps_needword_lookup(&ps, toplevel_cmds);
+  if (!ci) { badcmd("unknown command"); return OOP_CONTINUE; }
+  ci->fn(&ps,ci);
+  return OOP_CONTINUE;
+}
+
+static void *serial_readable(oop_source *evts, int fd,
+                            oop_event evt, void *u0) {
+  abort();
+}
+
+const char *device;
+
+int main(int argc, const char **argv) {
+  oop_read *stdin_source;
+  oop_source_sys *sys_events;
+  int r;
+
+  device= argv[1];
+  if (!device) device= "/dev/ttyS0";
+  
+  serial_open(device);
+  r= oop_fd_nonblock(serial_fd, 1);  if (r) diee("nonblock(serial_fd,1)");
+  serial_ochain.fd= serial_fd;
+
+  sys_events= oop_sys_new();  if (!sys_events) diee("oop_sys_new");
+  events= oop_sys_source(sys_events);  assert(events);
+
+  stdin_source= oop_rd_new_fd(events, 0, 0,0);
+  if (!stdin_source) diee("oop_rd_new_fd(,0,,)");
+  r= oop_rd_read(stdin_source, OOP_RD_STYLE_GETLINE, 1024,
+                stdin_ifok, 0, stdin_iferr, 0);
+  if (r) diee("oop_rd_read(stdin_source,...)");
+
+  events->on_fd(events, serial_fd, OOP_READ, serial_readable, 0);
+  oop_sys_run(sys_events);
+  abort();
+}
index 26e1a0a3ef2fba30b9b6730635485b720b400724..f3d63bf092d8edf94162a8fe575abb732f2161cc 100644 (file)
@@ -4,9 +4,30 @@
 #define HOSTSIDE_H
 
 #include <stdio.h>
+#include <oop.h>
 
 typedef unsigned char Byte;
 
+
+typedef struct ParseState ParseState;
+struct ParseState {
+  const char *remain;
+  const char *thisword;
+  int lthisword;
+};
+
+typedef struct CmdInfo CmdInfo;
+struct CmdInfo {
+  const char *name;
+  void (*fn)(ParseState *ps, const CmdInfo *ci);
+};
+
+extern oop_source *events;
+void die(const char *m) __attribute__((noreturn));
+void diee(const char *m) __attribute__((noreturn));
+void diem(void) __attribute__((noreturn));
+
+
 #define COMMAND_ENCODED_MAX 16
 #define NMRA_PACKET_MAX ((COMMAND_ENCODED_MAX*7 - 14) / 8)
 
@@ -25,6 +46,6 @@ void dump(const char *what, const Byte *data, int length);
 void sysfatal(const char *m);
 void serial_open(const char *device);
 
-extern int serial_fudge_delay;
+extern int serial_fd, serial_fudge_delay;
 
 #endif /*HOSTSIDE_H*/
index fae0f9733654f8b535d5ac1986dcc0831a516aae..5d964eacaf8f9ac334f10709c60101b5d1322224 100644 (file)
 #include "hostside.h"
 
 int serial_fudge_delay= 0;
+int serial_fd= -1;
 
-static int serial_fd= -1;
-
-void sysfatal(const char *m) { perror(m); exit(12); }
+void die(const char *m) { fprintf(stderr,"%s\n",m); exit(8); }
+void diee(const char *m) { perror(m); exit(12); }
+void diem(void) { perror("malloc failed"); exit(16); }
 
 void serial_open(const char *device) {
   assert(serial_fd==-1);
 
   serial_fd= open(device,O_RDWR);
-  if (serial_fd<0) sysfatal(device);
+  if (serial_fd<0) diee(device);
 }
 
 void dump(const char *what, const Byte *data, int length) {
@@ -46,7 +47,7 @@ void xmit_command(const Byte *command, int length) {
             serial_fudge_delay ? 1 : length);
     if (r==-1) {
       if (errno == EINTR) continue;
-      sysfatal("command_transmit");
+      diee("command_transmit");
     }
     assert(r<=length);
     command += r;