From: ian Date: Sun, 13 Apr 2008 21:48:36 +0000 (+0000) Subject: theoretically can tell trains to go X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ijackson/git?a=commitdiff_plain;h=0fc4318a5549bc8a3616452369ef750e5ec6520c;p=trains.git theoretically can tell trains to go --- diff --git a/hostside/commands.c b/hostside/commands.c index f6a638c..0f7987c 100644 --- a/hostside/commands.c +++ b/hostside/commands.c @@ -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 } }; diff --git a/hostside/common.h b/hostside/common.h index 72b18da..84532bb 100644 --- a/hostside/common.h +++ b/hostside/common.h @@ -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; }; diff --git a/hostside/errorcodes.h.gen b/hostside/errorcodes.h.gen index 5f44180..49d8025 100755 --- a/hostside/errorcodes.h.gen +++ b/hostside/errorcodes.h.gen @@ -7,6 +7,8 @@ MovFeatTooLate MovFeatKindsCombination BufferFull + BadCmd + NotFound ); diff --git a/hostside/gui-plan.c b/hostside/gui-plan.c index 9e1f592..6515cc0 100644 --- a/hostside/gui-plan.c +++ b/hostside/gui-plan.c @@ -15,6 +15,8 @@ #include #include +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); diff --git a/hostside/parseutils.c b/hostside/parseutils.c index c41bbd0..dc21275 100644 --- a/hostside/parseutils.c +++ b/hostside/parseutils.c @@ -10,16 +10,18 @@ #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, diff --git a/hostside/realtime.c b/hostside/realtime.c index bf8a011..125a3af 100644 --- a/hostside/realtime.c +++ b/hostside/realtime.c @@ -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; diff --git a/hostside/realtime.h b/hostside/realtime.h index 8bc4a3b..497e44d 100644 --- a/hostside/realtime.h +++ b/hostside/realtime.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -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*/ diff --git a/hostside/safety.c b/hostside/safety.c index 7f18853..381f9fc 100644 --- a/hostside/safety.c +++ b/hostside/safety.c @@ -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; diff --git a/hostside/safety.h b/hostside/safety.h index a3b54f2..8796661 100644 --- a/hostside/safety.h +++ b/hostside/safety.h @@ -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. diff --git a/hostside/speed.c b/hostside/speed.c index 8f5a88d..336d87b 100644 --- a/hostside/speed.c +++ b/hostside/speed.c @@ -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);