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
__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
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)
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
+startup state machine
-
-for points autochanging
- lay train an extra 600ms or so
-
+ -
--- /dev/null
+/*
+ * 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 */
+}
--- /dev/null
+/*
+ * 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");
+}
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];
}
}
free(mrn->name);
free(mrn);
+ ouack(ci);
return;
}
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;
enco_pic_anyinsn(&pi, pii, arg);
}
serial_transmit(&pi);
+ ouack(ci);
}
const CmdInfo toplevel_cmds[]= {
#define COMMON_H
#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
/*---------- types ----------*/
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)));
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;
--- /dev/null
+/*
+ * 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*/
--- /dev/null
+/*
+ * daemons
+ * helpers for event handling
+ */
+
+#include "daemons.h"
+
+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*/
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);
--- /dev/null
+/*
+ * 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*/
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);
}
$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);
#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);
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;
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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*/
--- /dev/null
+/*
+ * 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) );
+}
/*
+ * common
* general serial i/o and system interface etc.
*/
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);
--- /dev/null
+/*
+ * 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 */
+}
-/**/
+/*
+ * common
+ * general utility functions
+ */
#include <stdarg.h>
#include <errno.h>
#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);
}
char *mstrdup(const char *s) { return mstrdupl(s,strlen(s)); }
+
+void mgettimeofday(struct timeval *tv) {
+ r= gettimeofday(tv,0);
+ if (r) diee("gettimeofday failed");
+}