From 31333f622ad82b2580ab26946ddb2e38a0478c07 Mon Sep 17 00:00:00 2001 From: ian Date: Wed, 3 May 2006 23:04:59 +0000 Subject: [PATCH] wip before start to try to compile realtime --- hostside/Makefile | 10 +- hostside/Structure | 16 +++- hostside/cdumgr.c | 16 ++++ hostside/cmdinput.c | 58 ++++++++++++ hostside/commands.c | 16 ++-- hostside/common.h | 13 ++- hostside/daemons.h | 115 +++++++++++++++++++++++ hostside/eventhelp.c | 9 ++ hostside/hostside.h | 36 -------- hostside/multiplex.h | 46 ++++++++++ hostside/obc.c | 2 + hostside/parse-proto-spec | 1 + hostside/parseutils.c | 27 ++++++ hostside/realtime.c | 144 +++++++++++++++++++++++++++++ hostside/realtime.h | 24 +++++ hostside/selectout.c | 33 +++++++ hostside/serialio.c | 1 + hostside/skelproto-pic.h | 3 + hostside/startup.c | 189 ++++++++++++++++++++++++++++++++++++++ hostside/utils.c | 13 ++- 20 files changed, 714 insertions(+), 58 deletions(-) create mode 100644 hostside/cdumgr.c create mode 100644 hostside/cmdinput.c create mode 100644 hostside/daemons.h create mode 100644 hostside/eventhelp.c create mode 100644 hostside/multiplex.h create mode 100644 hostside/realtime.c create mode 100644 hostside/realtime.h create mode 100644 hostside/selectout.c create mode 100644 hostside/startup.c diff --git a/hostside/Makefile b/hostside/Makefile index a56c460..9e31d70 100644 --- a/hostside/Makefile +++ b/hostside/Makefile @@ -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) diff --git a/hostside/Structure b/hostside/Structure index 1e56546..8694d1b 100644 --- a/hostside/Structure +++ b/hostside/Structure @@ -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 index 0000000..089d954 --- /dev/null +++ b/hostside/cdumgr.c @@ -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 index 0000000..3c93b62 --- /dev/null +++ b/hostside/cmdinput.c @@ -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"); +} diff --git a/hostside/commands.c b/hostside/commands.c index b14ed03..4683877 100644 --- a/hostside/commands.c +++ b/hostside/commands.c @@ -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[]= { diff --git a/hostside/common.h b/hostside/common.h index ff3c12c..1d11bb5 100644 --- a/hostside/common.h +++ b/hostside/common.h @@ -9,6 +9,8 @@ #define COMMON_H #include +#include +#include /*---------- 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 index 0000000..836680e --- /dev/null +++ b/hostside/daemons.h @@ -0,0 +1,115 @@ +/* + * declarations common to + * - realtime daemon + * - multiplexer daemon + */ + +#ifndef DAEMONS_H +#define DAEMONS_H + +#include +#include + +#include +#include + +/*---------- 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 index 0000000..8b3dd05 --- /dev/null +++ b/hostside/eventhelp.c @@ -0,0 +1,9 @@ +/* + * daemons + * helpers for event handling + */ + +#include "daemons.h" + +oop_source *events; + diff --git a/hostside/hostside.h b/hostside/hostside.h index b2c73f5..8d1ed6d 100644 --- a/hostside/hostside.h +++ b/hostside/hostside.h @@ -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 index 0000000..81d3b13 --- /dev/null +++ b/hostside/multiplex.h @@ -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*/ diff --git a/hostside/obc.c b/hostside/obc.c index bc272de..ef294fc 100644 --- a/hostside/obc.c +++ b/hostside/obc.c @@ -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); } diff --git a/hostside/parse-proto-spec b/hostside/parse-proto-spec index 1698eba..5564ca2 100755 --- a/hostside/parse-proto-spec +++ b/hostside/parse-proto-spec @@ -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); diff --git a/hostside/parseutils.c b/hostside/parseutils.c index 99e1385..89ab4ba 100644 --- a/hostside/parseutils.c +++ b/hostside/parseutils.c @@ -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 index 0000000..59285eb --- /dev/null +++ b/hostside/realtime.c @@ -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 index 0000000..b98c547 --- /dev/null +++ b/hostside/realtime.h @@ -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 index 0000000..4f470d0 --- /dev/null +++ b/hostside/selectout.c @@ -0,0 +1,33 @@ +/* + * mulitplexer daemon + * transmissions to clients of their selected messages + */ + +#include +#include + +#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) ); +} diff --git a/hostside/serialio.c b/hostside/serialio.c index 1075de9..f1b9a7c 100644 --- a/hostside/serialio.c +++ b/hostside/serialio.c @@ -1,4 +1,5 @@ /* + * common * general serial i/o and system interface etc. */ diff --git a/hostside/skelproto-pic.h b/hostside/skelproto-pic.h index d2e9036..f748382 100644 --- a/hostside/skelproto-pic.h +++ b/hostside/skelproto-pic.h @@ -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 index 0000000..a72a0b0 --- /dev/null +++ b/hostside/startup.c @@ -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 */ +} diff --git a/hostside/utils.c b/hostside/utils.c index b6c4494..db23184 100644 --- a/hostside/utils.c +++ b/hostside/utils.c @@ -1,4 +1,7 @@ -/**/ +/* + * common + * general utility functions + */ #include #include @@ -6,9 +9,10 @@ #include #include -#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"); +} -- 2.30.2