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];
}
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;
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;
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;
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[]= {
{ "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 }
};
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) \
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;
};
MovFeatTooLate
MovFeatKindsCombination
BufferFull
+ BadCmd
+ NotFound
);
#include <X11/Xlib.h>
#include <X11/xpm.h>
+typedef int ErrorCode;
+
#include "common.h"
#include "../layout/plan-data-format.h"
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);
#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) {
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) {
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,
/*---------- 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) {
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",
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;
#include <stdlib.h>
#include <limits.h>
#include <stddef.h>
+#include <ctype.h>
#include <sys/types.h>
#include <sys/time.h>
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 ----------*/
#include "safety.h"
+#define CTYPE(isfoobar,ch) (isfoobar((unsigned char)(ch)))
#endif /*REALTIME_H*/
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;
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.
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);