chiark / gitweb /
fixes during movpos wip
[trains.git] / hostside / commands.c
index 57aaa99f57a172336e025141d1f315eef813b914..1c9953ae156a4f28ffbc0e17fe2d29f374d82014 100644 (file)
 /**/
 
-#include "hostside.h"
+#include <setjmp.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
 
-#if 0
-static void cmd_nmra_c(ParseState *ps, const CmdInfo *ci) {
+#include "realtime.h"
+#include "auproto-pic.h"
+
+#define NMRA_MAX_NARGS 10
+
+typedef struct ManualRetransmitNode ManualRetransmitNode;
+struct ManualRetransmitNode {
+  ManualRetransmitNode *back, *next;
+  char *name;
+  int lname;
+  RetransmitUrgentNode 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;
+};
+
+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];
+}
+
+void nmra_problem(NmraParseEncodeCaller *pec, const char *problem) {
+  badcmd(pec->ps,problem);
+  longjmp(pec->jb, 1);
+}
+
+static int cmd_nmra_command(ParseState *ps, PicInsn *pi) {
+  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, pi->d, &pi->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, pi);
+  return 1;
+}
+  
+static void 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;
+  
+  if (ps->remain) {
+    if (ps->remain[0]=='*') retrans= retransmit_urgent_queue;
+    else if (ps->remain[0]=='%') retrans= retransmit_urgent_queue_relaxed;
+  }
+  if (retrans) {
+    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_urgent_cancel(&mrn->rn);
+    } else {
+      mrn= mmalloc(sizeof(*mrn));
+      mrn->name= mmalloc(lmrname);
+      memcpy(mrn->name, mrname, lmrname);
+      mrn->lname= lmrname;
+    }
+  }
+
+  if (!ps->remain) {
+    if (!retrans) {
+      badcmd(ps,"nmra must have slot to cancel or data to send");
+      return;
+    }
+    free(mrn->name);
+    free(mrn);
+    ouack(ci);
+    return;
+  }
+
+  pi= retrans ? &mrn->rn.pi : &pi_buf;
+  
+  if (!cmd_nmra_command(ps, pi)) {
+    if (retrans) { free(mrn->name); free(mrn); }
+    return;
+  }
+
+  if (retrans)
+    retrans(&mrn->rn, 0);
+  else
+    serial_transmit(pi);
+  ouack(ci);
 }
-#endif
 
 static void cmd_noop(ParseState *ps, const CmdInfo *ci) {
-  oprintf(&ps->cl->ch,"noop successful\n");
+  ouack(ci);
+}
+
+static void cmd_pic(ParseState *ps, const CmdInfo *ci) {
+  const PicInsnInfo *pii;
+  PicInsn pi;
+  long arg;
+
+  if (ps->remain && ps->remain[0]=='=') {
+    ps->remain++;
+    pi.l= sizeof(pi.d);
+    if (!ps_needhextoend(ps, pi.d, &pi.l)) return;
+  } else {
+    pii= some_needword_lookup(ps,pic_command_infos,"pic command");
+    if (!pii) return;
+  
+    if (pii->argbits) {
+      if (!ps_neednumber(ps, &arg, 0, (1L << pii->argbits) - 1,
+                        "pic object number"))
+       return;
+    } else {
+      arg= 0;
+    }
+    if (!ps_neednoargs(ps))
+      return;
+    enco_pic_pii(&pi, pii, arg);
+  }
+  serial_transmit(&pi);
+  ouack(ci);
+}
+
+static void cmd_movfeat(ParseState *ps, const CmdInfo *ci) {
+  Segment *back, *move, *fwd;
+  long ms;
+  ErrorCode ec;
+  
+  if (!ps_needsegment(ps,&back,0) ||
+      !ps_needsegment(ps,&move,0) ||
+      !ps_needsegment(ps,&fwd,0)) return;
+  
+  ms= INT_MAX;
+  if (ps->remain)
+    if (!ps_neednumber(ps,&ms,0,INT_MAX,"milliseconds")) return;
+
+  if (!ps_neednoargs(ps)) return;
+
+  ec= movpos_change(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;
+  }
+
+  ouack(ci);  
 }
 
 const CmdInfo toplevel_cmds[]= {
-#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 */
-#endif
-  { "noop",        cmd_noop       },
+  { "pic",        cmd_pic         },
+  { "nmra",       cmd_nmra,       },
+  { "noop",       cmd_noop        },
+  { "movfeat",    cmd_movfeat     },
   { 0 }
 };