hostside-old: serialio.o nmra.o main.o encode.o
$(LINK)
-hostside: hostside.o serialio.o client.o obc.o commands.c -loop
+hostside: hostside.o serialio.o client.o obc.o commands.o \
+ nmra.o encode.o retransmit.o -loop
$(LINK)
layoutinfo.h: ../layout/ours.layout-data.c Makefile
va_end(al);
}
-int ps_needword(ParseState *ps) {
+int ps_word(ParseState *ps) {
const char *space;
- if (!ps->remain) { badcmd(ps,"too few args"); return 0; }
+ if (!ps->remain) return 0;
space= strchr(ps->remain, ' ');
ps->thisword= ps->remain;
if (space) {
return 1;
}
+int ps_needword(ParseState *ps) {
+ if (!ps_word(ps)) { badcmd(ps,"too few args"); return 0; }
+ return 1;
+}
+
+int ps_needhextoend(ParseState *ps, Byte *d, int *remain_io) {
+ Byte *d_end;
+ char buf[3], *ep;
+
+ d_end= d + *remain_io;
+ buf[2]= 0;
+
+ if (!ps->remain) { badcmd(ps,"need hex data block"); return 0; }
+ for (;;) {
+ if (!ps_word(ps)) return 0;
+ while (ps->lthisword > 0) {
+ if (ps->lthisword & 1) {
+ badcmd(ps,"hex data block with odd number of digits in part");
+ return 0;
+ }
+ buf[0]= ps->thisword[0];
+ buf[1]= ps->thisword[1];
+ if (d >= d_end) { badcmd(ps,"hex data block too long"); return 0; }
+ *d++= strtoul(buf,&ep,16);
+ if (*ep) { badcmd(ps,"invalid digit in hex data block"); return 0; }
+ ps->lthisword -= 2;
+ ps->thisword += 2;
+ }
+ }
+
+ *remain_io= d_end - d;
+ return 1;
+}
+
const CmdInfo *ps_lookup(ParseState *ps, const CmdInfo *inf) {
for (;
inf->name;
/**/
+#include <setjmp.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+
#include "hostside.h"
-#if 0
-static void cmd_nmra_c(ParseState *ps, const CmdInfo *ci) {
+#define NMRA_MAX_NARGS 10
+
+typedef struct ManualRetransmitNode ManualRetransmitNode;
+struct ManualRetransmitNode {
+ ManualRetransmitNode *back, *next;
+ char *name;
+ int lname;
+ RetransmitNode rn;
+};
+
+#define bogus_volatile /*empty*/
+#ifdef __GNUC__
+#if __GNUC__ == 2
+#undef bogus_volatile
+#define bogus_volatile volatile
+#endif
+#endif
+
+struct NmraParseEncodeCaller {
+ ParseState *ps;
+ unsigned long arg[NMRA_MAX_NARGS];
+ jmp_buf jb;
+};
+
+unsigned long nmra_argnumber(NmraParseEncodeCaller *pec, int argi) {
+ return pec->arg[argi];
+}
+
+void nmra_problem(NmraParseEncodeCaller *pec, const char *problem) {
+ badcmd(pec->ps,problem);
+ longjmp(pec->jb, 1);
+}
+
+static int cmd_nmra_command(ParseState *ps, RetransmitNode *rn) {
+ int hex;
+ const char *cmdarg;
+ int lcmdarg;
+ bogus_volatile int argc, checksum;
+ NmraParseEncodeCaller pec;
+ Nmra nmra;
+ char *ep;
+
+ assert(ps->remain);
+ switch (ps->remain[0]) {
+ case '_': ps->remain++; return ps_needhextoend(ps, rn->d, &rn->l);
+ case '=': hex=1; checksum=1; break;
+ case ':': hex=1; checksum=0; break;
+ default: hex=0; checksum=1; break;
+ }
+
+ if (hex) {
+ ps->remain++;
+ nmra.l= NMRA_PACKET_MAX - checksum;
+ if (!ps_needhextoend(ps, nmra.d, &nmra.l))
+ return 0;
+ } else {
+ if (!ps_needword(ps)) return 0;
+ cmdarg= ps->thisword;
+ lcmdarg= ps->lthisword;
+ pec.ps= ps;
+ argc= 0;
+
+ while (ps_word(ps)) {
+ if (argc >= NMRA_MAX_NARGS) {
+ badcmd(ps,"far too many nmra args");
+ return 0;
+ }
+
+ errno=0; pec.arg[argc++]= strtoul(ps->thisword, &ep, 0);
+ if (errno || ep != ps->thisword + ps->lthisword)
+ { badcmd(ps,"bad numeric argument for nmra"); return 0; }
+ }
+ if (setjmp(pec.jb))
+ return 0;
+ nmra_parse_encode(&nmra, cmdarg,lcmdarg, argc, &pec);
+ }
+ if (checksum)
+ nmra_addchecksum(&nmra);
+
+ nmra_encodeforpic(&nmra, rn->d, &rn->l);
+ return 1;
+}
+
+static void cmd_nmra(ParseState *ps, const CmdInfo *ci) {
+ static struct { ManualRetransmitNode *head, *tail; } mrns;
+
+ ManualRetransmitNode *mrn;
+ RetransmitNode *rn, rn_buf;
+
+ if (ps->remain && ps->remain[0]=='*') {
+ const char *mrname;
+ int lmrname;
+
+ ps_word(ps);
+ mrname= ps->thisword+1;
+ lmrname= ps->lthisword-1;
+
+ for (mrn= mrns.head;
+ !(mrn->lname == lmrname &&
+ !memcmp(mrn->name, mrname, lmrname));
+ mrn= mrn->next);
+ if (mrn) {
+ retransmit_cancel(&mrn->rn);
+ } else {
+ mrn= mmalloc(sizeof(*mrn));
+ mrn->name= mmalloc(lmrname);
+ memcpy(mrn->name, mrname, lmrname);
+ mrn->lname= lmrname;
+ }
+ } else {
+ mrn= 0;
+ }
+
+ if (!ps->remain) {
+ if (!mrn) {
+ badcmd(ps,"nmra must have slot to cancel or data to send");
+ return;
+ }
+ free(mrn->name);
+ free(mrn);
+ return;
+ }
+
+ rn= mrn ? &mrn->rn : &rn_buf;
+ rn->l= sizeof(rn->d);
+
+ if (!cmd_nmra_command(ps, rn)) {
+ if (mrn) { free(mrn->name); free(mrn); }
+ return;
+ }
+
+ if (mrn)
+ retransmit_queue(&mrn->rn);
+ else
+ serial_transmit(rn->d, rn->l);
}
-#endif
static void cmd_noop(ParseState *ps, const CmdInfo *ci) {
oprintf(&ps->cl->ch,"noop successful\n");
}
const CmdInfo toplevel_cmds[]= {
+ { "nmra", cmd_nmra, },
+ /* eg nmra [*[slot]] speed28 3 13 1 */
+ /* eg nmra [*[slot]] =0348 */
+ /* eg nmra [*[slot]] :03484b */
+ /* eg nmra [*[slot]] _7f7f00644197 */
+ /* eg nmra [*[slot]] */
#if 0
- { "nmra-cx", cmd_nmra_c }, /* eg nmra-c1 speed28 3 13 1 */
- { "nmra-c1", cmd_nmra_c, 1 },
- { "nmra-hx", cmd_nmra_h },
- { "nmra-h1", cmd_nmra_h, 1 }, /* eg nmra-h1 0348 */
- { "nmra-rx", cmd_nmra_r },
- { "nmra-r1", cmd_nmra_r, 1 }, /* eg nmra-r1 03484b */
- { "pic", cmd_pic }, /* eg pic point 3 */
- { "pic-raw", cmd_pic_raw }, /* pic-raw 7f7f00644197, pic-raw a003 */
+ { "pic-raw" , cmd_pic_raw, 1, },
+ { "pic", cmd_pic }, /* eg pic point 3 */
#endif
- { "noop", cmd_noop },
+ { "noop", cmd_noop },
{ 0 }
};
--- /dev/null
+/*
+ * declarations common to simple test program and real controller daemon
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <stdio.h>
+
+/*---------- types ----------*/
+
+typedef unsigned char Byte;
+
+#define COMMAND_ENCODED_MAX 16
+#define NMRA_PACKET_MAX ((COMMAND_ENCODED_MAX*7 - 14) / 8)
+
+typedef struct Nmra {
+ Byte d[NMRA_PACKET_MAX];
+ int l;
+} Nmra;
+
+/*---------- from serialio.c ----------*/
+
+void vdie(const char *fmt, int ev, va_list al)
+ __attribute__((noreturn,format(printf,1,0)));
+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(const Byte *command, int length);
+
+void *mmalloc(size_t sz);
+
+extern int serial_fd, serial_fudge_delay;
+
+/*---------- nmra parsing, nmra.c et al ----------*/
+
+typedef struct NmraParseEncodeCaller NmraParseEncodeCaller;
+void nmra_parse_encode(Nmra *out, const char *arg, int argl,
+ int argc, NmraParseEncodeCaller *pec);
+ /* will call back to these, supplied by caller: */
+ unsigned long nmra_argnumber(NmraParseEncodeCaller *pec, int argi);
+ void nmra_problem(NmraParseEncodeCaller *pec, const char *problem);
+
+void nmra_addchecksum(Nmra *packet);
+void nmra_encodeforpic(const Nmra *packet, Byte *picdata, int *lpicdata_r);
+ /* picdata should point to COMMAND_ENCODED_MAX bytes */
+
+
+#endif /*COMMON_H*/
-/**/
+/*
+ * arranges for the definitions of
+ * enco_nmra_WHATEVER
+ */
#include <assert.h>
#include <stdlib.h>
#include <string.h>
-#include "hostside.h"
+#include "common.h"
#include "nmra.h"
#define CONST(...) \
static void *serial_readable(oop_source *evts, int fd,
oop_event evt, void *u0) {
- abort();
+ events->cancel_fd(events, serial_fd, OOP_READ);
+ return OOP_CONTINUE;
}
const char *device;
-/**/
+/*
+ * declarations for hostside controller daemon
+ */
#ifndef HOSTSIDE_H
#define HOSTSIDE_H
-#include <stdio.h>
+#include "common.h"
+
#include <oop.h>
#include <oop-read.h>
-typedef unsigned char Byte;
-
-typedef struct OutBuffer OutBuffer;
-typedef struct OutBufferChain OutBufferChain;
typedef struct Client Client;
typedef struct ParseState ParseState;
typedef struct CmdInfo CmdInfo;
+typedef struct RetransmitNode RetransmitNode;
+
+/*---------- from obc.c ----------*/
+typedef struct OutBuffer OutBuffer;
+typedef struct OutBufferChain OutBufferChain;
typedef void OutBufferError(OutBufferChain*, const char *e1, const char *e2);
struct OutBufferChain {
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 hostside.c ----------*/
+
+extern oop_source *events;
+
+/*---------- from client.c ----------*/
+
struct Client {
OutBufferChain ch;
oop_read *rd;
int xarg;
};
-extern oop_source *events;
-void vdie(const char *fmt, int ev, va_list al)
- __attribute__((noreturn,format(printf,1,0)));
-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_word(ParseState *ps);
int ps_needword(ParseState *ps);
+int ps_needhextoend(ParseState *ps, Byte *dbuf, int *len_io);
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)
+void vbadcmd(ParseState *ps, const char *fmt, va_list al)
__attribute__((format(printf,2,0)));
-void oprintf(OutBufferChain *ch, const char *msg, ...)
+void badcmd(ParseState *ps, const char *fmt, ...)
__attribute__((format(printf,2,3)));
-void owrite(OutBufferChain *ch, const char *data, int l);
-void *mmalloc(size_t sz);
+void stdin_client(void);
+extern const CmdInfo toplevel_cmds[]; /* defined in commands.c*/
-#define COMMAND_ENCODED_MAX 16
-#define NMRA_PACKET_MAX ((COMMAND_ENCODED_MAX*7 - 14) / 8)
+/*---------- from retransmit.c ----------*/
-typedef struct Nmra {
- Byte d[NMRA_PACKET_MAX];
+struct RetransmitNode {
+ /* set by caller: */
+ Byte d[COMMAND_ENCODED_MAX];
int l;
-} Nmra;
-
-typedef struct NmraParseEncodeCaller NmraParseEncodeCaller;
-void nmra_parse_encode(Nmra *out, const char *arg, int argl,
- int argc, NmraParseEncodeCaller *pec);
-unsigned long nmra_argnumber(NmraParseEncodeCaller *pec, int argi);
-void nmra_problem(const char *problem);
-
-void xmit_nmra_raw(const Byte *with_csum, int length);
-void xmit_nmra_bytes(const Byte *without_csum, int length);
-void xmit_nmra(const Nmra*);
-void xmit_command(const Byte *command, int length);
-
-extern FILE *dump_stream;
-void dump(const char *what, const Byte *data, int length);
-void sysfatal(const char *m);
-void serial_open(const char *device);
+ /* internal: */
+};
-extern int serial_fd, serial_fudge_delay;
+void retransmit_queue(RetransmitNode *rn);
+void retransmit_cancel(RetransmitNode *rn);
#endif /*HOSTSIDE_H*/
#include <unistd.h>
#include <errno.h>
-#include "hostside.h"
+#include "common.h"
-FILE *dump_stream= 0;
+static FILE *dump_stream= 0;
static int repeat_delay= -1, iterations= -1;
static const char *serial_port;
-static struct {
- Nmra nmra;
- Byte buf[COMMAND_ENCODED_MAX]; /* padding prevents overruns */
-} buf;
+static Nmra buf;
static void badusage(const char *why) {
fprintf(stderr,"bad usage: %s\n",why); exit(8);
int i, l;
Byte *c;
- c= buf.nmra.d;
+ c= buf.d;
while ((data_string= *argv++)) {
l= strlen(data_string);
l >>= 1;
for (i=0; i<l; i++) {
- if (c >= buf.nmra.d + sizeof(buf.nmra.d)) badusage("too much hex");
+ if (c >= buf.d + sizeof(buf.d)) badusage("too much hex");
hbuf[0]= data_string[i*2];
hbuf[1]= data_string[i*2+1];
if (ep!=&hbuf[2]) badusage("bad hex in hex argument");
}
}
- buf.nmra.l= c - buf.nmra.d;
+ buf.l= c - buf.d;
}
struct NmraParseEncodeCaller {
- int argc;
const char *const *argv;
};
char *ep;
unsigned long l;
- if (argi >= pec->argc) badusage("missing numeric arg value");
arg= pec->argv[argi];
errno=0; l= strtoul(arg,&ep,0);
if (errno || *ep || ep==arg) badusage("bad numeric arg value");
return l;
}
-void nmra_problem(const char *problem) {
+void nmra_problem(NmraParseEncodeCaller *pec, const char *problem) {
badusage(problem);
}
+static void dump(const char *what, const Byte *data, int length) {
+ if (!dump_stream) return;
+ fprintf(dump_stream,"%-25s %3d ",what,length);
+ while (length>0) {
+ fprintf(dump_stream," %02x", *data);
+ data++;
+ length--;
+ }
+ fprintf(dump_stream,"\n");
+}
+
+static void xmit_command(void) {
+ dump("xmit_command", buf.d, buf.l);
+ serial_transmit(buf.d, buf.l);
+}
+
+static void xmit_nmra_raw(void) {
+ Byte encoded[COMMAND_ENCODED_MAX];
+ int lencoded;
+
+ dump("xmit_nmra_raw", buf.d, buf.l);
+ nmra_encodeforpic(&buf, encoded, &lencoded);
+ serial_transmit(encoded, lencoded);
+}
+
+static void xmit_nmra_bytes(void) {
+ nmra_addchecksum(&buf);
+ xmit_nmra_raw();
+}
+
int main(int argc, const char **argv) {
- void (*xmitter)(const Byte *d, int l);
+ void (*xmitter)(void);
const char *arg;
if (!*argv++) badusage("need argv[0]");
{
NmraParseEncodeCaller pec;
pec.argv= argv;
- for (pec.argc=0; argv[pec.argc]; pec.argc++);
- nmra_parse_encode(&buf.nmra, arg, strlen(arg), pec.argc, &pec);
+ for (argc=0; argv[argc]; argc++);
+ nmra_parse_encode(&buf, arg, strlen(arg), argc, &pec);
xmitter= xmit_nmra_bytes;
}
serial_open(serial_port);
for (;;) {
- xmitter(buf.nmra.d,buf.nmra.l);
+ xmitter();
if (repeat_delay < 0) break;
if (iterations >= 0 && !iterations--) break;
#include <assert.h>
#include <limits.h>
-#include "hostside.h"
+#include "common.h"
#include "nmra.h"
-void xmit_nmra_raw(const Byte *nmra_packet, int length) {
- Byte encoded[COMMAND_ENCODED_MAX], *encp;
+void nmra_encodeforpic(const Nmra *packet, Byte *encoded, int *lencoded_r) {
+ const Byte *bp;
+ int length;
+ Byte *encp;
unsigned working, newbits;
int working_qty;
- dump("xmit_nmra_raw",nmra_packet,length);
-
+ length= packet->l;
+ bp= packet->d;
+
assert(length > 0);
assert(length <= NMRA_PACKET_MAX);
encp= encoded;
if (length > 0) {
/* plonk new data bits just to right of old data bits */
length--;
- newbits= *nmra_packet++;
+ newbits= *bp++;
newbits <<= 1;
newbits |= !length; /* 9 bits, bottom one is `end of packet' */
working |= (newbits << (7-working_qty));
}
assert(encp > encoded);
encp[-1] |= 0x80; /* `end of command' bit */
-
- xmit_command(encoded, encp - encoded);
+ *lencoded_r= encp - encoded;
}
-void xmit_nmra_bytes(const Byte *without_csum, int length) {
+void nmra_addchecksum(Nmra *packet) {
/* calculates checksum, S9.2 B l.63 */
- Byte with_csum[NMRA_PACKET_MAX];
- const Byte *in;
- Byte *out;
int left;
+ Byte *bp;
unsigned running;
- dump("xmit_nmra",without_csum,length);
+ assert(packet->l >=0 && packet->l < NMRA_PACKET_MAX);
- assert(length >=0 && length < sizeof(with_csum));
- for (left=length, running=0, in=without_csum, out=with_csum;
- left>0;
- in++, out++, left--)
- running ^= (*out = *in);
+ for (left=packet->l, running=0, bp=packet->d;
+ left > 0;
+ bp++, left--)
+ running ^= *bp;
- *out= running;
- xmit_nmra_raw(with_csum, length+1);
+ *bp= running;
+ packet->l++;
}
static long argnumber(NmraParseEncodeCaller *pec, int argi,
- unsigned long *au,
+ unsigned long *au, int argc,
long min, long max) {
long l;
unsigned long abit;
+ if (argi >= argc) nmra_problem(pec,"missing numeric arg value");
+
l= nmra_argnumber(pec, argi);
abit= 1ul << argi;
*au |= abit;
if (l<min || l>LONG_MAX || l>max)
- nmra_problem("numeric arg value out of range");
+ nmra_problem(pec,"numeric arg value out of range");
return l;
}
int argc, NmraParseEncodeCaller *pec) {
unsigned long au= 0;
- #define Aint(x,i) , argnumber(pec,i,&au, INT_MIN,INT_MAX)
- #define Abitmap(x,i) , argnumber(pec,i,&au, 0,~0u>>1)
- #define Abyte(x,i) , argnumber(pec,i,&au, 0,0xff)
+ #define Aint(x,i) , argnumber(pec,i,&au,argc, INT_MIN,INT_MAX)
+ #define Abitmap(x,i) , argnumber(pec,i,&au,argc, 0,~0u>>1)
+ #define Abyte(x,i) , argnumber(pec,i,&au,argc, 0,0xff)
#define Anone
#define NMRA(n,al,body) \
if (argl == sizeof(#n)-1 && !memcmp(arg,#n,argl)) { \
} else
#include "nmra-packets.h"
{
- nmra_problem("unknown instruction");
+ nmra_problem(pec,"unknown instruction");
}
if (au != (1ul << argc)-1)
- nmra_problem("too many args for packet type");
+ nmra_problem(pec,"too many args for packet type");
}
-/**/
+/*
+ * arranges for the declarations of
+ * enco_nmra_WHATEVER
+ */
#ifndef NMRA_H
#define NMRA_H
--- /dev/null
+/*
+ * nmra retransmission
+ */
+
+#include "hostside.h"
+
+void retransmit_queue(RetransmitNode *rn) {
+}
+
+void retransmit_cancel(RetransmitNode *rn) {
+}
-/**/
+/*
+ * general serial i/o and system interface etc.
+ */
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
-#include "hostside.h"
+#include "common.h"
int serial_fudge_delay= 0;
int serial_fd= -1;
if (serial_fd<0) diee(device);
}
-void dump(const char *what, const Byte *data, int length) {
- if (!dump_stream) return;
- fprintf(dump_stream,"%-25s %3d ",what,length);
- while (length>0) {
- fprintf(dump_stream," %02x", *data);
- data++;
- length--;
- }
- fprintf(dump_stream,"\n");
-}
-
-void xmit_command(const Byte *command, int length) {
+void serial_transmit(const Byte *command, int length) {
int r;
assert(length <= COMMAND_ENCODED_MAX);
- dump("xmit_command",command,length);
-
while (length > 0) {
r= write(serial_fd, command,
serial_fudge_delay ? 1 : length);