chiark / gitweb /
theoretically can tell trains to go
authorian <ian>
Sun, 13 Apr 2008 21:48:36 +0000 (21:48 +0000)
committerian <ian>
Sun, 13 Apr 2008 21:48:36 +0000 (21:48 +0000)
hostside/commands.c
hostside/common.h
hostside/errorcodes.h.gen
hostside/gui-plan.c
hostside/parseutils.c
hostside/realtime.c
hostside/realtime.h
hostside/safety.c
hostside/safety.h
hostside/speed.c

index f6a638c646dacb8f866491069a834daffc907848..0f7987c5f09f9f6b53cbd1a23831f3efd9bb3db1 100644 (file)
@@ -33,10 +33,6 @@ 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];
 }
@@ -46,7 +42,7 @@ void nmra_problem(NmraParseEncodeCaller *pec, const char *problem) {
   longjmp(pec->jb, 1);
 }
 
-static int cmd_nmra_command(ParseState *ps, PicInsn *pi) {
+static ErrorCode cmd_nmra_command(ParseState *ps, PicInsn *pi) {
   int hex;
   const char *cmdarg;
   int lcmdarg;
@@ -66,43 +62,41 @@ static int cmd_nmra_command(ParseState *ps, PicInsn *pi) {
   if (hex) {
     ps->remain++;
     nmra.l= NMRA_PACKET_MAX - checksum;
-    if (!ps_needhextoend(ps, nmra.d, &nmra.l))
-      return 0;
+    MUSTECR( ps_needhextoend(ps, nmra.d, &nmra.l) );
   } else {
-    if (!ps_needword(ps)) return 0;
+    MUSTECR( ps_needword(ps) );
     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;
-      }
+    while (ps_word(ps)>=0) {
+      if (argc >= NMRA_MAX_NARGS)
+       return badcmd(ps,"far too many nmra args");
 
       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; }
+        return badcmd(ps,"bad numeric argument for nmra");
     }
     if (setjmp(pec.jb))
-      return 0;
-  
+      return EC_BadCmd;
+
     nmra_parse_encode(&nmra, cmdarg,lcmdarg, argc, &pec);
   }
   if (checksum)
     nmra_addchecksum(&nmra);
 
   nmra_encodeforpic(&nmra, pi);
-  return 1;
+  return 0;
 }
   
-static void cmd_nmra(ParseState *ps, const CmdInfo *ci) {
+static int cmd_nmra(ParseState *ps, const CmdInfo *ci) {
   static struct { ManualRetransmitNode *head, *tail; } mrns;
   
   PicInsn *pi, pi_buf;
   ManualRetransmitNode *mrn=0;
   void (*retrans)(RetransmitUrgentNode *urg, Nmra *n)= 0;
+  ErrorCode ec;
   
   if (ps->remain) {
     if (ps->remain[0]=='*') retrans= retransmit_urgent_queue;
@@ -132,34 +126,34 @@ static void cmd_nmra(ParseState *ps, const CmdInfo *ci) {
 
   if (!ps->remain) {
     if (!retrans) {
-      badcmd(ps,"nmra must have slot to cancel or data to send");
-      return;
+      return badcmd(ps,"nmra must have slot to cancel or data to send");
     }
     free(mrn->name);
     free(mrn);
-    ouack(ci);
-    return;
+    return 0;
   }
 
   pi= retrans ? &mrn->rn.pi : &pi_buf;
-  
-  if (!cmd_nmra_command(ps, pi)) {
+
+  ec= cmd_nmra_command(ps, pi);
+  if (ec) {
     if (retrans) { free(mrn->name); free(mrn); }
-    return;
+    return ec;
   }
 
   if (retrans)
     retrans(&mrn->rn, 0);
   else
     serial_transmit(pi);
-  ouack(ci);
+
+  return 0;
 }
 
-static void cmd_noop(ParseState *ps, const CmdInfo *ci) {
-  ouack(ci);
+static int cmd_noop(ParseState *ps, const CmdInfo *ci) {
+  return 0;
 }
 
-static void cmd_pic(ParseState *ps, const CmdInfo *ci) {
+static int cmd_pic(ParseState *ps, const CmdInfo *ci) {
   const PicInsnInfo *pii;
   PicInsn pi;
   long arg;
@@ -167,51 +161,116 @@ static void cmd_pic(ParseState *ps, const CmdInfo *ci) {
   if (ps->remain && ps->remain[0]=='=') {
     ps->remain++;
     pi.l= sizeof(pi.d);
-    if (!ps_needhextoend(ps, pi.d, &pi.l)) return;
+    MUSTECR( ps_needhextoend(ps, pi.d, &pi.l) );
   } else {
     pii= some_needword_lookup(ps,pic_command_infos,"pic command");
-    if (!pii) return;
+    if (!pii) return EC_BadCmd;
   
     if (pii->argbits) {
-      if (!ps_neednumber(ps, &arg, 0, (1L << pii->argbits) - 1,
-                        "pic object number"))
-       return;
+      MUSTECR( ps_neednumber(ps, &arg, 0, (1L << pii->argbits) - 1,
+                            "pic object number") );
     } else {
       arg= 0;
     }
-    if (!ps_neednoargs(ps))
-      return;
+    MUSTECR( ps_neednoargs(ps) );
     enco_pic_pii(&pi, pii, arg);
   }
   serial_transmit(&pi);
-  ouack(ci);
+  return 0;
+}
+
+static int ps_needsegment(ParseState *ps, Segment **seg_r,
+                         const SegmentInfo **segi_r) {
+  const SegmentInfo *segi;
+  segi= some_needword_lookup_counted(ps,info_segments,info_nsegments,
+                                    "segment");
+  if (!segi) return EC_BadCmd;
+  if (segi_r) *segi_r= segi;
+  if (seg_r) *seg_r= segments + (segi - info_segments);
+  return 0;
+}
+
+static int ps_needsegmentperhaps(ParseState *ps, Segment **seg_r,
+                                const SegmentInfo **segi_r) {
+  MUSTECR( ps_needword(ps) );
+  if (!thiswordstrcmp(ps,"-")) { *seg_r=0; *segi_r=0; return 0; }
+  ps_pushbackword(ps);
+  return ps_needsegment(ps,seg_r,segi_r);
+}
+
+static int ps_needtrain(ParseState *ps, Train **tra_r) {
+  const Train *tra= some_needword_lookup_counted(ps,trains,n_trains,"train");
+  if (!tra) return EC_BadCmd;
+  *tra_r= (Train*)tra;
+  return 0;
 }
 
-static void cmd_movfeat(ParseState *ps, const CmdInfo *ci) {
-  Segment *back, *move, *fwd;
+static int cmd_movfeat(ParseState *ps, const CmdInfo *ci) {
+  Segment *move, *back, *fwd;
+  const SegmentInfo *movei;
   long ms;
-  ErrorCode ec;
+  long poscomb;
   
-  if (!ps_needsegment(ps,&back,0) ||
-      !ps_needsegment(ps,&move,0) ||
-      !ps_needsegment(ps,&fwd,0)) return;
+  MUSTECR( ps_needsegmentperhaps(ps,&move,&movei) );
+  MUSTECR( ps_needword(ps) );
+  if (CTYPE(isdigit,*ps->thisword)) {
+    back= fwd= 0;
+    if (!move) badcmd(ps,"invalid movement specification");
+    ps_pushbackword(ps);
+    MUSTECR( ps_neednumber(ps,&poscomb,0,movei->n_poscombs,
+                          "position number") );
+  } else {
+    poscomb= -1;
+    back= move;
+    MUSTECR( ps_needsegment(ps,&move,&movei) );
+    MUSTECR( ps_needsegmentperhaps(ps,&fwd,0) );
+  }
   
   ms= INT_MAX;
   if (ps->remain)
-    if (!ps_neednumber(ps,&ms,0,INT_MAX,"milliseconds")) return;
+    MUSTECR( ps_neednumber(ps,&ms,0,INT_MAX,"milliseconds") );
 
-  if (!ps_neednoargs(ps)) return;
+  MUSTECR( ps_neednoargs(ps) );
 
-  ec= movpos_change_bysegs(back,move,fwd,ms,0);
-  if (ec) {
-    badcmd(ps,"movfeat %s %s %s %ld %s",
-          back->i->pname, move->i->pname, fwd->i->pname,
-          ms==INT_MAX ? -1L : ms,
-          errorcodelist[ec]);
-    return;
+  if (!ci->xarg)
+    MUSTECR( safety_checkmovposchange(move) );
+  
+  MUSTECR( movpos_change_bysegs(back,move,fwd,ms,0) );
+
+  return 0;
+}
+
+static int cmd_speed(ParseState *ps, const CmdInfo *ci) {
+  long speed, max;
+  int curvesz;
+  Train *tra;
+  
+  MUSTECR( ps_needtrain(ps,&tra) );
+  curvesz= tra->accel.curvesz;
+
+  switch (ci->xarg) {
+  case 0: max=INT_MAX; break;
+  case 1: max=1000;    break;
+  case 2: max=126;     break;
+  default: abort();
+  }
+
+  MUSTECR( ps_neednumber(ps,&speed,0,max,"speed step") );
+  MUSTECR( ps_neednoargs(ps) );
+
+  switch (ci->xarg) {
+  case 0:
+    break;
+  case 1:
+    speed= speed / 1000.0 * tra->accel.curve[curvesz-1].speed;
+    break;
+  case 2:
+    if (speed >= curvesz) speed= curvesz-1;
+    speed= tra->accel.curve[speed].speed;
+    break;
   }
 
-  ouack(ci);  
+  return safety_requestspeed(tra, speed);
 }
 
 const CmdInfo toplevel_cmds[]= {
@@ -219,5 +278,9 @@ const CmdInfo toplevel_cmds[]= {
   { "nmra",       cmd_nmra,       },
   { "noop",       cmd_noop        },
   { "movfeat",    cmd_movfeat     },
+  { "movfeat!",   cmd_movfeat, 1  },
+  { "speedmms",   cmd_speed,   1  },
+  { "speedpermil",cmd_speed,   2  },
+  { "speed126",   cmd_speed,   0  },
   { 0 }
 };
index 72b18da6259186434a56a729436bf75a44b43526..84532bbb0428c01e30aa80271e277fa04c0b3600 100644 (file)
@@ -44,20 +44,30 @@ struct ParseState {
   int lthisword;
 };
 
-void vbadcmd(ParseState *ps, const char *fmt, va_list al)
+int vbadcmd(ParseState *ps, const char *fmt, va_list al)
   __attribute__((format(printf,2,0)));
-void badcmd(ParseState *ps, const char *fmt, ...)
+int 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_word(ParseState *ps); /* returns 0 or -1, does not log */
+void ps_pushbackword(ParseState *ps);
+
+/* All of these return 0 or the return value from vbadcmd: */
 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_neednumber(ParseState *ps, long *r, long min,
+                       long max, const char *wh);
 int ps_neednoargs(ParseState *ps);
 
+#define MUSTECR(ps_something) do{              \
+    int mustecr__ec= (ps_something);   \
+    if (mustecr__ec) return mustecr__ec;       \
+  }while(0)
+  
+
 /*---------- macro for table lookups, with help from parseutils.c ----------*/
 
 #define some_lookup(ps, infos)                 \
@@ -83,7 +93,12 @@ const void *any_needword_lookup(ParseState *ps, const void *infos,
 
 struct CmdInfo {
   const char *name;
-  void (*fn)(ParseState *ps, const CmdInfo *ci);
+  int (*fn)(ParseState *ps, const CmdInfo *ci);
+    /* return values:
+     *   0: ok
+     *   return value from badcmd
+     *   some other error to report (if mainloop is expecting it)
+     */
   int xarg;
 };
 
index 5f44180962e67a501e53daf316fd0052d506dc24..49d802513c3357a417030e4b13a4da96ec85b272 100755 (executable)
@@ -7,6 +7,8 @@
        MovFeatTooLate
        MovFeatKindsCombination
        BufferFull
+       BadCmd
+       NotFound
        );
 
 
index 9e1f5922ba34ab74cb76076efef3bb9127f17695..6515cc0daa72476961f5bcb3d08acdbb1d6edda2 100644 (file)
@@ -15,6 +15,8 @@
 #include <X11/Xlib.h>
 #include <X11/xpm.h>
 
+typedef int ErrorCode;
+
 #include "common.h"
 #include "../layout/plan-data-format.h"
 
@@ -85,7 +87,7 @@ static void diexpm(const char *fn, const char *w, int xpmst) {
       diexpm(#f, (w), xpmcall_xpmst);          \
   }while(0)
 
-void vbadcmd(ParseState *ps, const char *fmt, va_list al) {
+int vbadcmd(ParseState *ps, const char *fmt, va_list al) {
   fprintf(stderr,"gui-plan: incorrect input: `%.*s': ",
          (int)badcmdreport_recsz, badcmdreport_data);
   vfprintf(stderr,fmt,al);
index c41bbd0bbe228ef954b68da127220eb6251b08cc..dc21275e61cb3fa71737a9a4853cd5e7c9c1e8f4 100644 (file)
 
 #include "common.h"
 
-void badcmd(ParseState *ps, const char *fmt, ...) {
+int badcmd(ParseState *ps, const char *fmt, ...) {
+  int r;
   va_list al;
   va_start(al,fmt);
-  vbadcmd(ps,fmt,al);
+  r= vbadcmd(ps,fmt,al);
   va_end(al);
+  return r;
 }
 
 int ps_word(ParseState *ps) {
   const char *space;
-  if (!ps->remain) return 0;
+  if (!ps->remain) return -1;
   space= strchr(ps->remain, ' ');
   ps->thisword= ps->remain;
   if (space) {
@@ -29,38 +31,37 @@ int ps_word(ParseState *ps) {
     ps->lthisword= strlen(ps->remain);
     ps->remain= 0;
   }
-  return 1;
+  return 0;
 }
 
 int ps_needword(ParseState *ps) {
-  if (!ps_word(ps)) { badcmd(ps,"too few args"); return 0; }
-  return 1;
+  if (ps_word(ps)<0) return badcmd(ps,"too few args");
+  return 0;
+}
+
+void ps_pushbackword(ParseState *ps) {
+  ps->remain= ps->thisword;
 }
 
-int ps_neednumber(ParseState *ps, long *r, long mi, long mx, const char *wh) {
+int ps_neednumber(ParseState *ps, long *r,
+                       long mi, long mx, const char *wh) {
   char *ep;
   long v;
   
-  if (!ps_needword(ps)) return 0;
+  MUSTECR( ps_needword(ps) );
   errno= 0; v= strtol(ps->thisword,&ep,0);
-  if (errno || ep != ps->thisword + ps->lthisword) {
-    badcmd(ps,"invalid number for %s",wh);
-    return 0;
-  }
-  if (v < mi || v > mx) {
-    badcmd(ps,"%s %ld out of range %ld..%ld",wh,v,mi,mx);
-    return 0;
-  }
+  if (errno || ep != ps->thisword + ps->lthisword)
+    return badcmd(ps,"invalid number for %s",wh);
+  if (v < mi || v > mx)
+    return badcmd(ps,"%s %ld out of range %ld..%ld",wh,v,mi,mx);
   *r= v;
-  return 1;
+  return 0;
 }
 
 int ps_neednoargs(ParseState *ps) {
-  if (ps->remain) {
-    badcmd(ps,"too many arguments");
-    return 0;
-  }
-  return 1;
+  if (ps->remain)
+    return badcmd(ps,"too many arguments");
+  return 0;
 }
  
 int ps_needhextoend(ParseState *ps, Byte *d, int *len_io) {
@@ -71,26 +72,24 @@ int ps_needhextoend(ParseState *ps, Byte *d, int *len_io) {
   d_end= d + *len_io;
   buf[2]= 0;
   
-  if (!ps->remain) { badcmd(ps,"need hex data block"); return 0; }
+  if (!ps->remain) return badcmd(ps,"need hex data block");
   for (;;) {
-    if (!ps_word(ps)) break;
+    if (ps_word(ps)<0) break;
     while (ps->lthisword > 0) {
-      if (ps->lthisword & 1) {
-       badcmd(ps,"hex data block with odd number of digits in part");
-       return 0;
-      }
+      if (ps->lthisword & 1)
+       return badcmd(ps,"hex data block with odd number of digits in part");
       buf[0]= ps->thisword[0];
       buf[1]= ps->thisword[1];
-      if (d >= d_end) { badcmd(ps,"hex data block too long"); return 0; }
+      if (d >= d_end) return badcmd(ps,"hex data block too long");
       *d++= strtoul(buf,&ep,16);
-      if (*ep) { badcmd(ps,"invalid digit in hex data block"); return 0; }
+      if (*ep) return badcmd(ps,"invalid digit in hex data block");
       ps->lthisword -= 2;
       ps->thisword += 2;
     }
   }
 
   *len_io= d - d_begin;
-  return 1;
+  return 0;
 }
 
 const void *any_lookup(ParseState *ps, const void *inf, int ninfsmax,
index bf8a011f8aa2274235b47ecbd2cc9aedd322edbc..125a3afe59fcd7c4c9cb101b9c59cf92964cc2fa 100644 (file)
@@ -214,10 +214,24 @@ static void oprint_nmradata(const PicInsn *pi) {
   
 /*---------- command channel handling (oop_read, obc) ----------*/
 
-static void command_doline(ParseState *ps, CommandInput *cmdi) {
-  const CmdInfo *ci;
+static const CmdInfo *ci;
+
+int vbadcmd(ParseState *ps, const char *fmt, va_list al) {
+  oprintf(UPO,"ack BadCmd %s: ", ci->name);
+  ovprintf(UPO,fmt,al);
+  return EC_BadCmd;
+}
+
+static void command_doline(ParseState *ps, CommandInput *cmdi_arg) {
+  int r;
+  
   ci= some_needword_lookup(ps, toplevel_cmds, "command");
-  if (ci) ci->fn(ps,ci);
+  r= ci->fn(ps,ci);
+  switch (r) {
+  case 0:  oprintf(UPO, "ack ok %s\n", ci->name);                    break;
+  case EC_BadCmd:                                                    break;
+  default: oprintf(UPO, "ack %s %s\n", errorcodelist[r], ci->name);  break;
+  }
 }
 
 void oupicio(const char *dirn, const PicInsnInfo *pii, int objnum) {
@@ -227,10 +241,6 @@ void oupicio(const char *dirn, const PicInsnInfo *pii, int objnum) {
     oprintf(UPO, "picio %s %s %#x\n", dirn, pii->name, objnum);
 }
 
-void vbadcmd(ParseState *ps, const char *fmt, va_list al) {
-  voerror(UPO,fmt,al);
-}
-
 static void obc_error(OutBufferChain *ch, const char *e1, const char *e2) {
   if (!e1) { assert(!e2); exit(0); }
   fprintf(stderr,"command communication error: %s%s%s\n",
@@ -257,17 +267,6 @@ void die_hook(void) {
   if (e) fprintf(stderr,"(unwritten command output: %s)\n",strerror(e));
 }
 
-int ps_needsegment(ParseState *ps, Segment **seg_r,
-                  const SegmentInfo **segi_r) {
-  const SegmentInfo *segi;
-  segi= some_needword_lookup_counted(ps,info_segments,info_nsegments,
-                                    "segment");
-  if (!segi) return 0;
-  if (segi_r) *segi_r= segi;
-  if (seg_r) *seg_r= segments + (segi - info_segments);
-  return 1;
-}
-
 /*---------- serial input (via oop) ----------*/
 
 static PicInsn serial_buf;
index 8bc4a3bd0fa09238cc9df3d7599ea59203191ee0..497e44d26d89a06f0407fbcb312aa0d23acc1b82 100644 (file)
@@ -16,6 +16,7 @@
 #include <stdlib.h>
 #include <limits.h>
 #include <stddef.h>
+#include <ctype.h>
 
 #include <sys/types.h>
 #include <sys/time.h>
@@ -138,8 +139,6 @@ void oupicio(const char *dirn, const PicInsnInfo *pii, int objnum);
 void ouhex(const char *word, const Byte *command, int length);
 
 void serial_transmit(const PicInsn *pi);
-int ps_needsegment(ParseState *ps, Segment **seg_r,
-                  const SegmentInfo **segi_r);
 
 /*---------- from actual.c ----------*/
 
@@ -163,5 +162,6 @@ void choreographers_all_abandon(void);
 
 #include "safety.h"
 
+#define CTYPE(isfoobar,ch) (isfoobar((unsigned char)(ch)))
 
 #endif /*REALTIME_H*/
index 7f18853a6c6c3bdf54759826cce578bd7471f18f..381f9fc4025add455e65d6236743ff87981deeb8 100644 (file)
@@ -266,6 +266,16 @@ void safety_emergencystop(Train *tra) {
   speedmanager_emergencystop(tra);
 }
 
+ErrorCode safety_checkmovposchange(Segment *seg) {
+  ErrorCode ec;
+  if (seg->owner) {
+    ec= safety_problem(seg->owner, seg, "must not unset route train is using");
+    logmsg(ec,seg->owner,seg->i,"countermanded point change");
+    return ec;
+  }
+  return 0;
+}
+
 ErrorCode safety_requestspeed(Train *tra, long newspeed) {
   long oldspeed;
   ErrorCode ec;
index a3b54f288bf528173a8f4ffdef7dd7bc4759f537..8796661eeae2235a7f79cbfb8773e579a0c20ae0 100644 (file)
@@ -127,6 +127,9 @@ void safety_setdirection(Train* tra, int sense_fixme_define_this_properly);
 void safety_notify_detection(Segment *seg);
   /* Called by startup.c when new train detection occurs in state Run. */
 
+ErrorCode safety_checkmovposchange(Segment *seg);
+  /* If this check success, caller may call movpos_change */
+
 /*========== movpos.c ==========*/
 /*
  * movpos.c manages the CDU and points and other moveable features.
index 8f5a88de91d01d148e3bed0828e48d7027478ccb..336d87b633bf41babf5833d5192735dfd812e5e8 100644 (file)
@@ -52,7 +52,7 @@ void speedmanager_emergencystop(Train *tra) {
   Nmra n;
   tra->estopping= 1;
   toev_stop(&tra->accel.more);
-  enco_nmra_estop1(&n, tra->addr);
+  enco_nmra_speed126(&n, tra->addr, 0, tra->backwards);
   retransmit_urgent_requeue(&tra->accel.rn, &n);
 
   toev_stop(&tra->accel.more);