#include <assert.h>
#include <string.h>
#include <errno.h>
+#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
typedef int ErrorCode;
-#include "common.h"
+#include "daemons.h"
#include "../layout/plan-data-format.h"
#include <oop.h>
oop_source *events;
const char *progname= "gui-plan";
-static SegmovfeatState **state, *states_head;
+typedef struct {
+ SegmovfeatState *mfs;
+ unsigned inverted:1, updated:1;
+} SegState;
+
+static SegState *state;
+static SegmovfeatState *states_head;
static Display *d;
static oop_source_sys *sys_events;
static Window w=None;
const char *data, size_t recsz, void *is_v) {
const InputStream *is= is_v;
const char *emsg;
- emsg= oop_rd_errmsg(stdin_read, evt, errnoval, OOP_RD_STYLE_GETLINE)
+ emsg= oop_rd_errmsg(stdin_read, evt, errnoval, OOP_RD_STYLE_GETLINE);
die("%s: %s", is->name, emsg);
}
static void *input_ifok(oop_source *evts, oop_read *cl_read,
oop_rd_event evt, const char *errmsg, int errnoval,
- const char *data, size_t recsz, void *cl_v) {
+ const char *data, size_t recsz, void *is_v) {
const InputStream *is= is_v;
ParseState ps;
if (evt == OOP_RD_EOF) {
is->on_eof();
- abort;
+ abort();
}
if (evt != OOP_RD_OK) {
- input_iferr(evts,cl_read,evt,errmsg,errnoval,data,recsz,cl_v);
+ input_iferr(evts,cl_read,evt,errmsg,errnoval,data,recsz,is_v);
return OOP_CONTINUE;
}
static void stdin_eof(void) { exit(0); }
-static void stdin_input_line() {
+static void stdin_input_line(ParseState *ps) {
const char *slash, *movfeatname;
int invert, det, trainown, segment_ix, movfeat_ix, lmovfeatname;
long posn;
(badcmd(ps,"unknown command"),-1));
}
ps_needword(ps);
- slash= memchr(ps.thisword, '/', ps.lthisword);
+ slash= memchr(ps->thisword, '/', ps->lthisword);
if (slash) {
movfeatname= slash + 1;
- lmovfeatname= (ps.thisword + ps.lthisword) - movfeatname;
- ps.lthisword= slash - ps.thisword;
+ lmovfeatname= (ps->thisword + ps->lthisword) - movfeatname;
+ ps->lthisword= slash - ps->thisword;
} else {
movfeatname= 0;
lmovfeatname= 0;
}
- segment_ix= lstrpdbsearch(ps.thisword, ps.lthisword,
+ segment_ix= lstrpdbsearch(ps->thisword, ps->lthisword,
"segment", ui_plan_data.segments,
ui_plan_data.n_segments, sizeof(*segment_d));
segment_d= &ui_plan_data.segments[segment_ix];
segment_d->n_movfeats, sizeof(*movfeat_d));
movfeat_d= &segment_d->movfeats[movfeat_ix];
- if (ps.remain) {
+ if (ps->remain) {
if (invert<0) badcmd(0,"off may not take movfeatpos");
ps_neednumber(ps, &posn, 0, movfeat_d->n_posns-1, "movfeatpos");
} else {
ps_neednoargs(ps);
- fs= &state[segment_ix][movfeat_ix];
+ fs= &state[segment_ix].mfs[movfeat_ix];
fs->invert= invert;
fs->det= det;
fs->trainown= trainown;
redraw(fs);
xlib_process();
-
- return OOP_CONTINUE;
}
static const InputStream stdin_is= { "stdin", stdin_eof, stdin_input_line };
/*---------- multiplexer client ----------*/
+static OutBufferChain sock= { (char*)"multiplexer socket", -1 };
+
+static void sockvprintf(const char *fmt, va_list al)
+ __attribute__((format(printf,1,0)));
+static void sockprintf(const char *fmt, ...)
+ __attribute__((format(printf,1,2)));
+
+static void sockvprintf(const char *fmt, va_list al) {
+ ovprintf(&sock,fmt,al);
+}
+static void sockprintf(const char *fmt, ...) {
+ va_list al;
+ va_start(al,fmt);
+ sockvprintf(fmt,al);
+ va_end(al);
+}
+
static int sock_clientconnect(const char *node, const char *service) {
struct addrinfo *aires, *try, hints;
char niaddrbuf[256], niportbuf[64];
static void sock_eof(void) { die("EOF on multiplexer connection"); }
-static void
-
-static const char[]= {
- { "?detect", si_detect },
- { "?picio_out_polarity", si_polarity },
- { "?movpos_*_feat", si_movpos },
- { "?stastate", si_stastate },
- { "?picio_out_on", si_pic_on },
- { "?picio_out_off", si_pic_off },
- { "=connected", si_connected },
- { "=permission", 0 },
+static void *sock_exception(oop_source *evts, int fd,
+ oop_event evt, void *cmdi_v) {
+ die("multiplexer socket has exceptional condition");
+}
+
+/*---------- multiplexer protocol ----------*/
+
+static void si_detect(ParseState *ps) {
+}
+
+static void si_polarity(ParseState *ps) {
+}
+
+static void si_movpos(ParseState *ps) {
+}
+
+static void si_on(ParseState *ps) {
+}
+
+static void si_off(ParseState *ps) {
+}
+
+typedef struct MuxEventInfo MuxEventInfo;
+typedef void MuxEventFn(ParseState *ps);
+
+struct MuxEventInfo {
+ const char *prefix; /* 0: sentinel */
+ const char *remainpat; /* 0: no pattern in select needed */
+ MuxEventFn *fn; /* 0: just ignore matching messages */
+};
+static const MuxEventInfo muxeventinfos[];
+
+static void si_connected(ParseState *ps) {
+ const MuxEventInfo *mxi;
+ const char *p;
+ int c;
+
+ sockprintf("select-replay");
+ for (mxi=muxeventinfos; mxi->prefix; mxi++) {
+ sockprintf(" ");
+ for (p=mxi->prefix; (c=*p); p++) {
+ switch (c) {
+ case ' ': c= '_';
+ }
+ sockprintf("%c",c);
+ }
+ sockprintf("%s",mxi->remainpat);
+ }
+ sockprintf("\n");
+}
+
+static void si_problem(ParseState *ps) {
+ die("multiplexer reports problem: %.*s\n",
+ (int)badcmdreport_recsz, badcmdreport_data);
+}
+
+static const MuxEventInfo muxeventinfos[]= {
+ { "?detect ", "", si_detect },
+ { "?picio out polarity", "", si_polarity },
+ { "?movpos ", "*_feat", si_movpos },
+ { "?enco pic on", "", si_on },
+ { "?enco pic off", "", si_off },
+
+ { "=connected", "", si_connected },
+ { "=permission", "", 0 },
+
+ { "+executing", 0, 0 },
+ { "+ack * ok", 0, 0 },
+ { "+ack", 0, si_problem },
+ { "+nak", 0, si_problem },
+ { "=failed", 0, si_problem },
+ { "=denied", 0, si_problem },
{ 0 }
-}
+};
-static void sock_input_line(ParseStatee *ps) {
- if (thiswordstrcmp(ps,"=connected")) {
- write sock ("select ?detect ?stastate ?picio_out_on ?picio_out_off"
- " ?picio_out_polarity
+static void sock_input_line(ParseState *ps) {
+ const MuxEventInfo *mxi;
+ int l;
+ for (mxi=muxeventinfos; mxi->prefix; mxi++) {
+ l= strlen(mxi->prefix);
+ if (!memcmp(mxi->prefix, ps->remain, l))
+ goto found;
+ }
+ return;
+found:
+ if (!mxi->fn) return;
+ ps->remain += l;
+ if (*ps->remain==' ') ps->remain++;
+ mxi->fn(ps);
}
static const InputStream sock_is= {
const char *arg;
XpmAttributes mattribs;
XWindowAttributes wattribs;
- int segment_ix, movfeat_ix, posn, invert, det, oor, sock=-1;
+ int segment_ix, movfeat_ix, posn, invert, det, oor;
XGCValues gcv;
XColor colour;
SegmovfeatState *fs;
} else {
service= STR(TRAINMX_PORT);
}
- sock= clientconnect(node,service);
- if (sock<0) die("unable to connect to multiplexer");
+ sock.fd= sock_clientconnect(node,service);
+ if (sock.fd<0) die("unable to connect to multiplexer");
+ obc_init(&sock);
+ events->on_fd(events, sock.fd, OOP_EXCEPTION, sock_exception, 0);
if (comma) *comma= ',';
} else if (arg[0]=='-') {
die("invalid option(s)");
for (segment_ix= 0, segment_d= ui_plan_data.segments;
segment_ix < ui_plan_data.n_segments;
segment_ix++, segment_d++) {
- state[segment_ix]= fs=
- mmalloc(sizeof(**state) * segment_d->n_movfeats);
+ state[segment_ix].mfs= fs=
+ mmalloc(sizeof(*state[segment_ix].mfs) * segment_d->n_movfeats);
for (movfeat_ix= 0, movfeat_d= segment_d->movfeats;
movfeat_ix < segment_d->n_movfeats;
movfeat_ix++, movfeat_d++, fs++) {
rd= oop_rd_new_fd(events, 0, 0,0);
if (!rd) diee("oop_rd_new_fd");
- if (sock==-1)
+ if (sock.fd==-1) {
+ events->on_fd(events, 0, OOP_EXCEPTION, some_exception, 0);
+
oor= oop_rd_read(rd, OOP_RD_STYLE_GETLINE, 1024,
- stdin_ifok, (void*)&stdin_is,
- stdin_iferr, (void*)&stdin_is);
- else
+ input_ifok, (void*)&stdin_is,
+ input_iferr, (void*)&stdin_is);
+ } else {
oor= oop_rd_read(rd, OOP_RD_STYLE_GETLINE, 1024,
- sock_ifok, (void*)&sock_is,
- sock_iferr, (void*)&sock_is);
+ input_ifok, (void*)&sock_is,
+ input_iferr, (void*)&sock_is);
+ }
if (oor) diee("oop_rd_read");
- events->on_fd(events, 0, OOP_EXCEPTION, some_exception, 0);
events->on_fd(events, ConnectionNumber(d), OOP_READ, xlib_readable, 0);
events->on_fd(events, ConnectionNumber(d), OOP_EXCEPTION, some_exception, 0);