From a0dee8b27ad5fa1ec612978667a6b4b5ac5ca458 Mon Sep 17 00:00:00 2001 From: ian Date: Tue, 11 Jan 2005 23:55:15 +0000 Subject: [PATCH] weirdo nmra stuff compiles but is broken in main.c still; checkin before radical fix --- hostside/Makefile | 6 +- hostside/encode.c | 135 ++++++++++++---------------------------- hostside/hostside.h | 18 +----- hostside/main.c | 133 ++++++++++++++++++++++++++++----------- hostside/nmra-packets.h | 77 ++++++++++++++++++----- hostside/nmra.h | 13 ++++ hostside/serialio.c | 7 ++- 7 files changed, 222 insertions(+), 167 deletions(-) create mode 100644 hostside/nmra.h diff --git a/hostside/Makefile b/hostside/Makefile index 7a975c2..462818a 100644 --- a/hostside/Makefile +++ b/hostside/Makefile @@ -2,14 +2,16 @@ TARGETS= hostside CFLAGS= -Wall -Werror -Wstrict-prototypes -Wmissing-prototypes \ - -Wpointer-arith -Wwrite-strings $(OPTIMISE) + -Wpointer-arith -Wwrite-strings -g $(OPTIMISE) OPTIMISE= -O2 all: $(TARGETS) -hostside: serialio.o nmra.o main.o +hostside: serialio.o nmra.o main.o encode.o $(CC) $(CFLAGS) -o $@ $+ +encode.o: nmra-packets.h +main.o: nmra-packets.h %.c: hostside.h clean: diff --git a/hostside/encode.c b/hostside/encode.c index eb417bc..8667f18 100644 --- a/hostside/encode.c +++ b/hostside/encode.c @@ -3,114 +3,57 @@ #include #include "hostside.h" +#include "nmra.h" -#define XCONST(d) const Byte c[2]= { d }; XMIT; +#define CONST(...) \ + static const Byte m[]= { __VA_ARGS__ }; \ + memcpy(c,m,sizeof(m)); \ + c+=sizeof(m) -static Byte *addr(int addr, Byte *ap) { +#define FUNCS(v) \ + nmra_errchk(cn, bitmap, !(bitmap & ~0x1fffu)); \ + *c++= (v) + +#define nmra_errchk(cn, v, truth) \ + if (!truth) nmra_errchk_fail(cn, v, #v, #truth); + +static void nmra_errchk_fail(const char *m, long v, + const char *vn, const char *truth) { + fprintf(stderr,"nmra encode %s: %s %ld (0x%lx) fails condition %s\n", + m, vn, (unsigned long)v, (unsigned long)v, truth); + exit(15); +} + +#define ADDR c= encode_addr(cn, addr, c); + +static Byte *encode_addr(const char *cn, int addr, Byte *ap) { /* encodes decoder address */ - assert(addr>0 && addr<=0x3ff); + nmra_errchk(cn, addr, addr>0 && addr<=0x3ff); if (addr < 0x3f) { /* Short addresses: S9.2 B l.41 which is the same as RP9.2.1 C l.65 * first sentence. */ - *--ap= addr; + *ap++= addr; } else { /* Long addresses: RP9.2.1 C l.65-69. */ - *--ap= addr; - *--ap= (addr >> 8) | 0xc0; + *ap++= addr; + *ap++= (addr >> 8) | 0xc0; } return ap; } -#define ADDR Byte *c= addr(addr, p->d); -#define ENCD p->l= c - p->d; assert(p->l <= sizeof(p->d)); - -void enco_nmra_speed28(Nmra *p, int addr, int speed, int reverse) { - /* Baseline Speed and Direction, S9.2 B (for short addresses - * only), which is also identical to Multi-Function Decoder - * Speed and Direction RP9.2.1 C l.215- (defined for both - * addresses), so actually the address format and instruction - * format are independent. - */ - int adj; - ADDR; - - assert(speed>=0 && speed<=28); - *c++= 0x40 | (reverse ? 0 : 0x20); - if (speed) { - adj= speed + 3; - *c |= adj & 1 ? 0x10 : 0; - *c |= adj >> 1; - } - c++; - ENCD; -} - -void enco_nmra_estop1(Nmra *p, int addr) { - /* Baseline Speed and direction Forwards E-Stop(I) S9.2 B table l.56 */ - ADDR; - *c++= 0x71; - ENCD; -} - -void enco_nmra_estop(void) { - /* Baseline Broadcast stop Forwards(I) Emergency S9.2 B l.98- */ - XCONST(0x00, 0x71); -} -void enco_nmra_reset(void) { - /* Baseline Decoder Reset S9.2 B l.77- */ - XCONST(0x00, 0x00); -} -void enco_nmra_idle(void) { - /* Baseline Idle S9.2 B l.87- */ - XCONST(0xff, 0x00); -} - -void enco_nmra_speed126(int addr, int speed, int reverse) { - /* Advanced Operations 128 Speed Step Control - * (actually speeds 0..126) RP9.2.1 C l.200- */ - CMD(2); - ADDR; - assert(speed>=0 && speed<=126); - c[0]= 0x3f; - c[1]= (speed ? speed + 1 : 0) | (reverse ? 0 : 0x80); - ENCD; -} - -void enco_nmra_funcs0to4(unsigned bitmap) { - /* Function Group One RP9.2.1 C l.234- */ - CMD(1); - ADDR; - FUNCS; - c[0]= 0x80 | ((bitmap >> 1) & 0x0f) | ((bitmap << 4 & 0x10)); - ENCD; -} -void enco_nmra_funcs5to9(unsigned bitmap) { - /* Function Group Two RP9.2.1 C l.246- */ - CMD(1); - ADDR; - FUNCS; - c[0]= 0xa0 | ((bitmap >> 5) & 0x0f); - ENCD; -} -void enco_nmra_funcs9to12(unsigned bitmap) { - /* Function Group Two RP9.2.1 C l.246- */ - CMD(1); - ADDR; - FUNCS; - c[0]= 0xb0 | ((bitmap >> 9) & 0x0f); - ENCD; -} +#define Aint(v) , int v +#define Abitmap(v) , unsigned v +#define Abyte(v) , Byte v +#define Anone -void enco_nmra_cv_write(int addr, int cv, Byte value) { - /* Configuration Variable Access Long Form RP9.2.1 C l.286- */ - int adj; - CMD(3); - ADDR; - assert(cv>=1 && cv<=1024); - adj= cv - 1; - c[0]= 0xec | (adj >> 8); - c[1]= adj; - c[2]= value; - ENCD; +#define NMRA(n,al,body) \ +void enco_nmra_##n(Nmra *p al) { \ + static const char cn[]= #n; \ + Byte *c= p->d; \ + (void)cn; \ + do { body } while(0); \ + p->l= c - p->d; \ + assert(p->l <= sizeof(p->d)); \ } +#include "nmra-packets.h" diff --git a/hostside/hostside.h b/hostside/hostside.h index 31a0775..26e1a0a 100644 --- a/hostside/hostside.h +++ b/hostside/hostside.h @@ -3,6 +3,8 @@ #ifndef HOSTSIDE_H #define HOSTSIDE_H +#include + typedef unsigned char Byte; #define COMMAND_ENCODED_MAX 16 @@ -18,22 +20,6 @@ void xmit_nmra_bytes(const Byte *without_csum, int length); void xmit_nmra(const Nmra*); void xmit_command(const Byte *command, int length); -void enco_nmra_speed28(Nmra *p, int train, int speed, int reverse); -void enco_nmra_speed126(Nmra *p, int addr, int speed, int reverse); - /* 0<=speed<=28 or <=126; reverse: 0 forwards, non-0 backwards */ -void enco_nmra_funcs0to4(Nmra *p, unsigned bitmap); -void enco_nmra_funcs5to8(Nmra *p, unsigned bitmap); -void enco_nmra_funcs9to12(Nmra *p, unsigned bitmap); - /* bit 0 is FL aka F0; bits 1-12 are F1-F12; do not call with bits - * outside 0-12 set; bits in 0-12 but not relevant for the relevant - * command are ignored. */ -void enco_nmra_cv_write(Nmra *p, int addr, int cv, Byte value); - -void enco_nmra_idle(Nmra *p); -void enco_nmra_reset(Nmra *p); -void enco_nmra_estop(Nmra *p); -void enco_nmra_estop1(Nmra *p); - extern FILE *dump_stream; void dump(const char *what, const Byte *data, int length); void sysfatal(const char *m); diff --git a/hostside/main.c b/hostside/main.c index 92d26d7..fb496eb 100644 --- a/hostside/main.c +++ b/hostside/main.c @@ -11,58 +11,121 @@ #include #include #include +#include #include #include "hostside.h" +#include "nmra.h" FILE *dump_stream= 0; -int main(int argc, const char **argv) { - int l, i; - char hbuf[3], *ep; - Byte buf[NMRA_PACKET_MAX + COMMAND_ENCODED_MAX]; +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; - int repeat_delay= -1, iterations= -1; - const char *serial_port, *data_string, *instruction; +static void badusage(const char *why) { + fprintf(stderr,"bad usage: %s\n",why); exit(8); +} + +static long argnumber(const char ***argv, long min, long max) { + long l; + const char *arg; + char *ep; - assert(argc>=4 && argc<=7); - serial_port= argv[1]; - data_string= argv[2]; - instruction= argv[3]; - if (argc>4) serial_fudge_delay= atoi(argv[4]); - if (argc>5) repeat_delay= atoi(argv[5]); - if (argc>6) iterations= atoi(argv[6]); + if (!(arg= *(*argv)++)) badusage("missing numeric arg value"); + l= strtoul(arg,&ep,0); if (*ep) badusage("bad numeric arg value"); + if (lmax) badusage("numeric arg value out of range"); + return l; +} - serial_open(serial_port); +static void pahex(const char **argv) { + const char *data_string; + char hbuf[3], *ep; + int i, l; + Byte *c; + + c= buf.nmra.d; - l= strlen(data_string); - assert(!(l&1)); - l >>= 1; - assert(l<=sizeof(buf)); - - for (i=0; i>= 1; + + for (i=0; i= buf.nmra.d + sizeof(buf.nmra.d)) badusage("too much hex"); + + hbuf[0]= data_string[i*2]; + hbuf[1]= data_string[i*2+1]; + hbuf[2]= 0; + *c++= strtoul(hbuf,&ep,16); + if (ep!=&hbuf[2]) badusage("bad hex in hex argument"); + } } + buf.nmra.l= c - buf.nmra.d; +} - for (;;) { +int main(int argc, const char **argv) { + void (*xmitter)(const Byte *d, int l); + const char *arg; - if (*instruction == 'd') { - dump_stream= stdout; - instruction++; + if (!*argv++) badusage("need argv[0]"); + + while ((arg=*argv++) && *arg=='-') { + arg++; + switch (*arg++) { + case 's': serial_port= arg; break; + case 'i': iterations= atoi(arg); break; + case 'f': serial_fudge_delay= atoi(arg); break; + case 'w': repeat_delay= atoi(arg); break; + case 'd': dump_stream= stdout; goto noarg; + default: badusage("uknown option"); + noarg: if (*arg) badusage("option with value where forbidden"); } + } + + if (!serial_port) { + if (!arg) badusage("need serial port as -s or arg"); + serial_port= arg; + arg= *argv++; + } + + if (!arg) badusage("need arg"); - switch (*instruction) { - case 'c': xmit_command(buf,l); break; - case 'r': xmit_nmra_raw(buf,l); break; - case 'n': xmit_nmra(buf,l); break; - default: abort(); + #define BARE(f) \ + if (!strcmp(arg,#f)) { \ + pahex(argv); \ + xmitter= xmit_##f; \ + } else + BARE(command) + BARE(nmra_raw) + BARE(nmra_bytes) + #undef BARE + { + #define Aint(x) , argnumber(&argv,INT_MIN,INT_MAX) + #define Abitmap(x) , argnumber(&argv,0,~0u) + #define Abyte(x) , argnumber(&argv,0,0xff) + #define Anone + #define NMRA(n,al,body) \ + if (!strcmp(arg,#n)) { \ + enco_nmra_##n(&buf.nmra al); \ + } else +#include "nmra-packets.h" + { + badusage("unknown instruction"); } - assert(!instruction[1]); + if (*argv) badusage("too many args for packet type"); + xmitter= xmit_nmra_bytes; + } + serial_open(serial_port); + + for (;;) { + xmitter(buf.nmra.d,buf.nmra.l); + if (repeat_delay < 0) break; if (iterations >= 0 && !iterations--) break; if (repeat_delay > 0) usleep(repeat_delay); diff --git a/hostside/nmra-packets.h b/hostside/nmra-packets.h index 42bf03f..e029aa1 100644 --- a/hostside/nmra-packets.h +++ b/hostside/nmra-packets.h @@ -1,9 +1,12 @@ - - +/* + * strange macros - do not use directly, usually + */ + NMRA(speed28, Aint(addr) Aint(speed) Aint(reverse), { + /* 0<=speed<=28 or <=126; reverse: 0 forwards, non-0 backwards */ int adj; - - assert(speed>=0 && speed<=28); + ADDR; + nmra_errchk(cn, speed, speed>=0 && speed<=28); *c++= 0x40 | (reverse ? 0 : 0x20); if (speed) { adj= speed + 3; @@ -12,18 +15,62 @@ NMRA(speed28, Aint(addr) Aint(speed) Aint(reverse), { } c++; }); +NMRA(estop1, Aint(addr), { + /* Baseline Speed and direction Forwards E-Stop(I) S9.2 B table l.56 */ + ADDR; + *c++= 0x71; +}); +NMRA(speed126, Aint(addr) Aint(speed) Aint(reverse), { + /* Advanced Operations 128 Speed Step Control + * (actually speeds 0..126) RP9.2.1 C l.200- */ + ADDR; + nmra_errchk(cn, speed, speed>=0 && speed<=126); + *c++= 0x3f; + *c++= (speed ? speed + 1 : 0) | (reverse ? 0 : 0x80); +}); -NMRA( - - +NMRA(estop, Anone, { + /* Baseline Broadcast stop Forwards(I) Emergency S9.2 B l.98- */ + CONST(0x00, 0x71); +}); +NMRA(reset, Anone, { + /* Baseline Decoder Reset S9.2 B l.77- */ + CONST(0x00, 0x00); +}); +NMRA(idle, Anone, { + /* Baseline Idle S9.2 B l.87- */ + CONST(0xff, 0x00); +}); - /* Baseline Speed and Direction, S9.2 B (for short addresses - * only), which is also identical to Multi-Function Decoder - * Speed and Direction RP9.2.1 C l.215- (defined for both - * addresses), so actually the address format and instruction - * format are independent. - */ +/* For functions: + * bit 0 is FL aka F0; bits 1-12 are F1-F12; do not call with bits + * outside 0-12 set; bits in 0-12 but not relevant for the relevant + * command are ignored. */ +NMRA(funcs0to4, Aint(addr) Abitmap(bitmap), { + /* Function Group One RP9.2.1 C l.234- */ + FUNCS(0x80 | ((bitmap >> 1) & 0x0f) | ((bitmap << 4 & 0x10))); +}); +NMRA(funcs5to9, Aint(addr) Abitmap(bitmap), { + /* Function Group Two RP9.2.1 C l.246- */ + FUNCS(0xa0 | ((bitmap >> 5) & 0x0f)); +}); +NMRA(funcs9to12, Aint(addr) Abitmap(bitmap), { + /* Function Group Two RP9.2.1 C l.246- */ + FUNCS(0xb0 | ((bitmap >> 9) & 0x0f)); +}); +NMRA(cvwrite, Aint(addr) Aint(cv) Abyte(value), { + /* Configuration Variable Access Long Form RP9.2.1 C l.286- */ + int adj; ADDR; + nmra_errchk(cn, cv, cv>=1 && cv<=1024); + adj= cv - 1; + *c++= 0xec | (adj >> 8); + *c++= adj; + *c++= value; +}); - ENCD; -} +#undef Aint +#undef Abitmap +#undef Abyte +#undef Anone +#undef NMRA diff --git a/hostside/nmra.h b/hostside/nmra.h new file mode 100644 index 0000000..f3ea6be --- /dev/null +++ b/hostside/nmra.h @@ -0,0 +1,13 @@ +/**/ + +#ifndef NMRA_H +#define NMRA_H + +#define Aint(v) , int v +#define Abitmap(v) , unsigned v +#define Abyte(v) , Byte v +#define Anone +#define NMRA(n,al,body) void enco_nmra_##n(Nmra *packet_r al) +#include "nmra-packets.h" + +#endif /*NMRA_H*/ diff --git a/hostside/serialio.c b/hostside/serialio.c index 0f4c6aa..fae0f97 100644 --- a/hostside/serialio.c +++ b/hostside/serialio.c @@ -25,13 +25,14 @@ void serial_open(const char *device) { } void dump(const char *what, const Byte *data, int length) { - printf("%-25s %3d ",what,length); + if (!dump_stream) return; + fprintf(dump_stream,"%-25s %3d ",what,length); while (length>0) { - printf(" %02x", *data); + fprintf(dump_stream," %02x", *data); data++; length--; } - printf("\n"); + fprintf(dump_stream,"\n"); } void xmit_command(const Byte *command, int length) { -- 2.30.2