chiark / gitweb /
weirdo nmra stuff compiles but is broken in main.c still; checkin before radical fix
authorian <ian>
Tue, 11 Jan 2005 23:55:15 +0000 (23:55 +0000)
committerian <ian>
Tue, 11 Jan 2005 23:55:15 +0000 (23:55 +0000)
hostside/Makefile
hostside/encode.c
hostside/hostside.h
hostside/main.c
hostside/nmra-packets.h
hostside/nmra.h [new file with mode: 0644]
hostside/serialio.c

index 7a975c2bc000b7bdb08eb264bf30fad90b541658..462818a37e9b7eb173541f054cb4aca4f3ae8788 100644 (file)
@@ -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:
index eb417bc7cd267f2983223787a847247daf5e0461..8667f1840295d2637a95bde365934ac53c5ba5ff 100644 (file)
 #include <assert.h>
 
 #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"
index 31a0775a6b8c3378fb502b6624cafb844f7630c0..26e1a0a3ef2fba30b9b6730635485b720b400724 100644 (file)
@@ -3,6 +3,8 @@
 #ifndef HOSTSIDE_H
 #define HOSTSIDE_H
 
+#include <stdio.h>
+
 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);
index 92d26d78711354f5c5c4121033139894e9252afb..fb496eb1fc7888b4fc639f1a6158d786a96e0f00 100644 (file)
 #include <string.h>
 #include <assert.h>
 #include <stdlib.h>
+#include <limits.h>
 #include <unistd.h>
 
 #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 (l<min || l>max) 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<l; i++) {
-    hbuf[0]= data_string[i*2];
-    hbuf[1]= data_string[i*2+1];
-    hbuf[2]= 0;
-    buf[i]= strtoul(hbuf,&ep,16);
-    assert(ep==&hbuf[2]);
+  while ((data_string= *argv++)) {
+    l= strlen(data_string);
+    if (l&1) badusage("hex argument odd length");
+    l >>= 1;
+  
+    for (i=0; i<l; i++) {
+      if (c >= 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);
index 42bf03fd785c8a16e14807ae6f0f1a3e8b912d29..e029aa1efd3136c9f96074ac9bbd5b8f43c66037 100644 (file)
@@ -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 (file)
index 0000000..f3ea6be
--- /dev/null
@@ -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*/
index 0f4c6aaebee0f51032b30a42c6a5cfcd8b90ad1c..fae0f9733654f8b535d5ac1986dcc0831a516aae 100644 (file)
@@ -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) {