From: ian Date: Mon, 30 May 2005 11:56:17 +0000 (+0000) Subject: reorganised to be nicer and ready to add stuff X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ijackson/git?a=commitdiff_plain;h=29bb7ac6c5dbcaf2d3b77d4e95d0741d19589362;p=trains.git reorganised to be nicer and ready to add stuff --- diff --git a/hostside/Makefile b/hostside/Makefile index 117bd49..4656267 100644 --- a/hostside/Makefile +++ b/hostside/Makefile @@ -10,7 +10,7 @@ all: $(TARGETS) hostside-old: serialio.o nmra.o main.o encode.o $(LINK) -hostside: hostside.o serialio.o -loop +hostside: hostside.o serialio.o client.o obc.o commands.c -loop $(LINK) layoutinfo.h: ../layout/ours.layout-data.c Makefile diff --git a/hostside/client.c b/hostside/client.c new file mode 100644 index 0000000..e30f8c7 --- /dev/null +++ b/hostside/client.c @@ -0,0 +1,127 @@ +/**/ + +#include +#include +#include + +#include "hostside.h" + +void vbadcmd(ParseState *ps, const char *fmt, va_list al) { + oprintf(&ps->cl->ch,"error "); + ovprintf(&ps->cl->ch,fmt,al); + owrite(&ps->cl->ch,"\n",1); +} + +void badcmd(ParseState *ps, const char *fmt, ...) { + va_list al; + va_start(al,fmt); + vbadcmd(ps,fmt,al); + va_end(al); +} + +int ps_needword(ParseState *ps) { + const char *space; + if (!ps->remain) { badcmd(ps,"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; +} + +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; +} + +const CmdInfo *ps_needword_lookup(ParseState *ps, const CmdInfo *infs) { + if (!ps_needword(ps)) return 0; + return ps_lookup(ps,infs); +} + +void ps_callword(ParseState *ps, const CmdInfo *infs, const char *what) { + const CmdInfo *ci; + ci= ps_needword_lookup(ps,infs); + if (!ci) { badcmd(ps,"unknown %s",what); return; } + ci->fn(ps,ci); +} + +static void *client_iferr(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) { + Client *cl= cl_v; + + cl->ch.error(&cl->ch, "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 *cl_v) { + Client *cl= cl_v; + ParseState ps; + + if (evt == OOP_RD_EOF) { + cl->ch.error(&cl->ch,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= cl; + ps.remain= data; + ps_callword(&ps, toplevel_cmds, "command"); + return OOP_CONTINUE; +} + +static void *client_exception(oop_source *evts, int fd, + oop_event evt, void *cl_v) { + Client *cl= cl_v; + cl->ch.error(&cl->ch,"comms error","exception"); + return OOP_CONTINUE; +} + +static void new_client(int fd, OutBufferError error, char *desc) { + Client *cl; + int r; + + cl= mmalloc(sizeof(*cl)); + + cl->ch.desc= desc; + cl->ch.fd= fd; + cl->ch.error= error; + obc_init(&cl->ch); + + events->on_fd(events, fd, OOP_EXCEPTION, client_exception, cl); + + cl->rd= oop_rd_new_fd(events, fd, 0,0); + if (!cl->rd) diee("oop_rd_new_fd"); + r= oop_rd_read(cl->rd, OOP_RD_STYLE_GETLINE, 1024, + client_ifok, cl, + client_iferr, cl); + if (r) diee("oop_rd_read"); +} + +static void stdin_error(OutBufferChain *ch, const char *e1, const char *e2) { + if (!e1) + exit(0); + fprintf(stderr,"stdin: %s: %s\n", e1, e2); + exit(12); +} + +void stdin_client(void) { + new_client(0, stdin_error, (char*)"stdin"); +} diff --git a/hostside/commands.c b/hostside/commands.c new file mode 100644 index 0000000..5610f90 --- /dev/null +++ b/hostside/commands.c @@ -0,0 +1,20 @@ +/**/ + +#include "hostside.h" + +static void cmd_noop(ParseState *ps, const CmdInfo *ci) { + oprintf(&ps->cl->ch,"noop successful\n"); +} + +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 } +}; diff --git a/hostside/hostside.c b/hostside/hostside.c index bd00f9b..5c14f66 100644 --- a/hostside/hostside.c +++ b/hostside/hostside.c @@ -6,9 +6,6 @@ #include #include -#include -#include - #include "../layout/dlist.h" #include "hostside.h" @@ -19,172 +16,13 @@ static void serial_error(OutBufferChain *ch, const char *e1, const char *e2) { abort(); } -static void stdin_error(OutBufferChain *ch, const char *e1, const char *e2) { - if (!e1) - exit(0); - fprintf(stderr,"stdin: %s: %s\n", e1, e2); - exit(12); -} - static OutBufferChain serial_ochain= { (char*)"serial", -1, serial_error }; -static Client stdin_client= { { (char*)"stdin", 0, stdin_error } }; - -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); - 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; - ch->error(ch,"write",strerror(errno)); - } - assert(r>=0); - ch->done_of_head += r; - assert(ch->done_of_head <= ob->l); - } -} - -static void *client_exception(oop_source *evts, int fd, - oop_event evt, void *cl_v) { - Client *cl= cl_v; - cl->ch.error(&cl->ch,"comms error","exception"); - return OOP_CONTINUE; -} static void *serial_exception(oop_source *evts, int fd, oop_event evt, void *cl_v) { die("serial port - exception"); } -static void ochain_addlink(OutBufferChain *ch, OutBuffer *ob) { - if (!ch->obs.head) - events->on_fd(events, ch->fd, OOP_WRITE, ochain_writeable, ch); - LIST_LINK_TAIL(ch->obs, ob); -} - -static void ovprintf(OutBufferChain *ch, const char *fmt, va_list al) - __attribute__((format(printf,2,0))); -static void ovprintf(OutBufferChain *ch, 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_client.ch, ob); -} - -static void oprintf(OutBufferChain *ch, const char *msg, ...) - __attribute__((format(printf,2,3))); -static void oprintf(OutBufferChain *ch, const char *msg, ...) { - va_list al; - va_start(al,msg); - ovprintf(ch,msg,al); - va_end(al); -} - -static void badcmd(ParseState *ps, const char *how) { - oprintf(&ps->cl->ch,"error %s\n",how); -} - -static void cmd_noop(ParseState *ps, const CmdInfo *ci) { - oprintf(&ps->cl->ch,"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(ps,"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 *client_iferr(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) { - Client *cl= cl_v; - - cl->ch.error(&cl->ch, "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 *cl_v) { - Client *cl= cl_v; - ParseState ps; - const CmdInfo *ci; - - if (evt == OOP_RD_EOF) { - cl->ch.error(&cl->ch,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= cl; - ps.remain= data; - ci= ps_needword_lookup(&ps, toplevel_cmds); - if (!ci) { badcmd(&ps,"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(); @@ -193,26 +31,20 @@ static void *serial_readable(oop_source *evts, int fd, 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"; + + sys_events= oop_sys_new(); if (!sys_events) diee("oop_sys_new"); + events= oop_sys_source(sys_events); assert(events); 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, - client_ifok, 0, client_iferr, 0); - if (r) diee("oop_rd_read(stdin_source,...)"); - events->on_fd(events, 0, OOP_EXCEPTION, client_exception, &stdin_client); + stdin_client(); events->on_fd(events, serial_fd, OOP_READ, serial_readable, 0); events->on_fd(events, serial_fd, OOP_EXCEPTION, serial_exception, 0); diff --git a/hostside/hostside.h b/hostside/hostside.h index 22c8cf4..d34fb34 100644 --- a/hostside/hostside.h +++ b/hostside/hostside.h @@ -5,31 +5,39 @@ #include #include +#include typedef unsigned char Byte; typedef struct OutBuffer OutBuffer; +typedef struct OutBufferChain OutBufferChain; +typedef struct Client Client; +typedef struct ParseState ParseState; +typedef struct CmdInfo CmdInfo; + struct OutBuffer { OutBuffer *back, *next; char *m; int l; }; -typedef struct OutBufferChain OutBufferChain; +typedef void OutBufferError(OutBufferChain*, const char *e1, const char *e2); + struct OutBufferChain { + /* set by user: */ char *desc; int fd; - void (*error)(OutBufferChain *obc, const char *e1, const char *e2); + OutBufferError *error; + /* set/used by obc_..., oprintf, etc., only */ int done_of_head; struct { OutBuffer *head, *tail; } obs; }; -typedef struct Client Client; struct Client { OutBufferChain ch; + oop_read *rd; }; -typedef struct ParseState ParseState; struct ParseState { Client *cl; const char *remain; @@ -37,7 +45,6 @@ struct ParseState { int lthisword; }; -typedef struct CmdInfo CmdInfo; struct CmdInfo { const char *name; void (*fn)(ParseState *ps, const CmdInfo *ci); @@ -50,6 +57,28 @@ 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 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 ps_needword(ParseState *ps); +const CmdInfo *ps_lookup(ParseState *ps, const CmdInfo *inf); +const CmdInfo *ps_needword_lookup(ParseState *ps, const CmdInfo *infs); +void ps_callword(ParseState *ps, const CmdInfo *infs, const char *what); + +extern const CmdInfo toplevel_cmds[]; +void stdin_client(void); + + +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); + +void *mmalloc(size_t sz); + #define COMMAND_ENCODED_MAX 16 #define NMRA_PACKET_MAX ((COMMAND_ENCODED_MAX*7 - 14) / 8) diff --git a/hostside/obc.c b/hostside/obc.c new file mode 100644 index 0000000..7fb3c1a --- /dev/null +++ b/hostside/obc.c @@ -0,0 +1,79 @@ +/**/ + +#include +#include +#include +#include +#include + +#include "hostside.h" +#include "../layout/dlist.h" + +static void *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); + 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; + ch->error(ch,"write",strerror(errno)); + } + assert(r>=0); + ch->done_of_head += r; + assert(ch->done_of_head <= ob->l); + } +} + +static void addlink(OutBufferChain *ch, OutBuffer *ob) { + if (!ch->obs.head) + events->on_fd(events, ch->fd, OOP_WRITE, writeable, ch); + LIST_LINK_TAIL(ch->obs, ob); +} + +void obc_init(OutBufferChain *ch) { + ch->done_of_head= 0; + LIST_INIT(ch->obs); +} + +void ovprintf(OutBufferChain *ch, const char *fmt, va_list al) { + OutBuffer *ob; + + ob= mmalloc(sizeof(*ob)); + ob->l= vasprintf(&ob->m, fmt, al); if (ob->l <= 0) diem(); + addlink(ch, ob); +} + +void oprintf(OutBufferChain *ch, const char *msg, ...) { + va_list al; + va_start(al,msg); + ovprintf(ch,msg,al); + va_end(al); +} + +void owrite(OutBufferChain *ch, const char *data, int l) { + OutBuffer *ob; + ob= mmalloc(sizeof(*ob)); + ob->l= l; + ob->m= mmalloc(l); + memcpy(ob->m, data, l); + addlink(ch,ob); +} diff --git a/hostside/serialio.c b/hostside/serialio.c index 4497f69..952698d 100644 --- a/hostside/serialio.c +++ b/hostside/serialio.c @@ -30,6 +30,14 @@ void diee(const char *fmt, ...) void diem(void) { diee("malloc failed"); } +void *mmalloc(size_t sz) { + void *p; + if (!sz) return 0; + p= malloc(sz); + if (!p) diem(); + return p; +} + void serial_open(const char *device) { assert(serial_fd==-1);