10 #include "auproto-pic.h"
12 #define NMRA_MAX_NARGS 10
14 typedef struct ManualRetransmitNode ManualRetransmitNode;
15 struct ManualRetransmitNode {
16 struct { ManualRetransmitNode *back, *next; } others;
19 RetransmitUrgentNode rn;
22 #define bogus_volatile /*empty*/
26 #define bogus_volatile volatile
31 static void cmd_ppc(Train *tra, Segment *seg, void *pu, const char *message) {
32 const CmdInfo *ci= pu;
33 ouprintf("ack %s SignallingPredictedProblem %s %s : %s\n",
34 ci->name, tra->pname, seg ? seg->i->pname : "-", message);
37 #define MUSTECRPREDICT(requester) do{ \
38 int mustecr__ec= (requester); \
39 if (mustecr__ec==EC_SignallingPredictedProblem) return EC_BadCmd; \
40 if (mustecr__ec) return mustecr__ec; \
42 #define CMDPPC cmd_ppc,(void*)ci
44 struct NmraParseEncodeCaller {
46 unsigned long arg[NMRA_MAX_NARGS];
50 typedef struct { const char *word; int backwards; int change; } DirectionInfo;
51 static const DirectionInfo directioninfos[]= {
52 { "forwards", 0, 0 }, /* first two must be `forwards' and `backwards' */
53 { "backwards", 1, 0 }, /* for the benefit of cmd_speed */
58 unsigned long nmra_argnumber(NmraParseEncodeCaller *pec, int argi) {
59 return pec->arg[argi];
62 void nmra_problem(NmraParseEncodeCaller *pec, const char *problem) {
63 badcmd(pec->ps,problem);
67 static ErrorCode cmd_nmra_command(ParseState *ps, PicInsn *pi) {
71 bogus_volatile int argc, checksum;
72 NmraParseEncodeCaller pec;
77 switch (ps->remain[0]) {
78 case '_': ps->remain++; return ps_needhextoend(ps, pi->d, &pi->l);
79 case '=': hex=1; checksum=1; break;
80 case ':': hex=1; checksum=0; break;
81 default: hex=0; checksum=1; break;
86 nmra.l= NMRA_PACKET_MAX - checksum;
87 MUSTECR( ps_needhextoend(ps, nmra.d, &nmra.l) );
89 MUSTECR( ps_needword(ps) );
91 lcmdarg= ps->lthisword;
95 while (ps_word(ps)>=0) {
96 if (argc >= NMRA_MAX_NARGS)
97 return badcmd(ps,"far too many nmra args");
99 errno=0; pec.arg[argc++]= strtoul(ps->thisword, &ep, 0);
100 if (errno || ep != ps->thisword + ps->lthisword)
101 return badcmd(ps,"bad numeric argument for nmra");
106 nmra_parse_encode(&nmra, cmdarg,lcmdarg, argc, &pec);
109 nmra_addchecksum(&nmra);
111 nmra_encodeforpic(&nmra, pi);
115 static int cmd_nmra(ParseState *ps, const CmdInfo *ci) {
116 static struct { ManualRetransmitNode *head, *tail; } mrns;
119 ManualRetransmitNode *mrn=0;
120 void (*retrans)(RetransmitUrgentNode *urg, Nmra *n)= 0;
124 if (ps->remain[0]=='*') retrans= retransmit_urgent_queue;
125 else if (ps->remain[0]=='%') retrans= retransmit_urgent_queue_relaxed;
132 mrname= ps->thisword+1;
133 lmrname= ps->lthisword-1;
137 !(mrn->lname == lmrname &&
138 !memcmp(mrn->name, mrname, lmrname));
139 mrn= mrn->others.next);
141 retransmit_urgent_cancel(&mrn->rn);
143 mrn= mmalloc(sizeof(*mrn));
144 mrn->name= mmalloc(lmrname);
145 memcpy(mrn->name, mrname, lmrname);
147 DLIST2_APPEND(mrns,mrn,others);
153 return badcmd(ps,"nmra must have slot to cancel or data to send");
155 DLIST2_REMOVE(mrns,mrn,others);
161 pi= retrans ? &mrn->rn.pi : &pi_buf;
163 ec= cmd_nmra_command(ps, pi);
165 if (retrans) { free(mrn->name); free(mrn); }
170 retrans(&mrn->rn, 0);
177 static int cmd_noop(ParseState *ps, const CmdInfo *ci) {
181 static int cmd_pic(ParseState *ps, const CmdInfo *ci) {
182 const PicInsnInfo *pii;
186 if (ps->remain && ps->remain[0]=='=') {
189 MUSTECR( ps_needhextoend(ps, pi.d, &pi.l) );
191 pii= some_needword_lookup(ps,pic_command_infos,"pic command");
192 if (!pii) return EC_BadCmd;
195 MUSTECR( ps_neednumber(ps, &obj, 0,
196 (1L << (pii->argsbits - pii->vbits)) - 1,
197 "pic object number") );
202 MUSTECR( ps_neednumber(ps, &v, 0, (1L << pii->vbits) - 1,
203 "pic command value") );
207 MUSTECR( ps_neednoargs(ps) );
208 enco_pic_pii(&pi, pii, obj, v);
210 serial_transmit(&pi);
214 static int ps_needsegment(ParseState *ps, Segment **seg_r,
215 const SegmentInfo **segi_r) {
216 const SegmentInfo *segi;
217 segi= some_needword_lookup_counted(ps,info_segments,info_nsegments,
219 if (!segi) return EC_BadCmd;
220 if (segi_r) *segi_r= segi;
221 if (seg_r) *seg_r= segments + (segi - info_segments);
225 static int ps_needsegmentperhaps(ParseState *ps, Segment **seg_r,
226 const SegmentInfo **segi_r) {
227 MUSTECR( ps_needword(ps) );
228 if (!thiswordstrcmp(ps,"-")) { *seg_r=0; *segi_r=0; return 0; }
230 return ps_needsegment(ps,seg_r,segi_r);
233 static int ps_needtrain(ParseState *ps, Train **tra_r) {
234 const Train *tra= some_needword_lookup_counted(ps,trains,n_trains,"train");
235 if (!tra) return EC_BadCmd;
240 static int cmd_route_movfeat(ParseState *ps, const CmdInfo *ci,
241 Segment *move, const SegmentInfo *movei,
246 if (ps->remain && CIXF_FORCE)
247 MUSTECR( ps_neednumber(ps,&ms,0,100000,"milliseconds") );
249 MUSTECR( ps_neednoargs(ps) );
251 if (ci->xarg & CIXF_FORCE) {
252 if (!(sta_state < Sta_Resolving || sta_state == Sta_Manual))
253 return badcmd(ps,"movpos queueing arrangements not ready");
255 MovPosChange *reservation= 0;
256 if (!move->moving && move->motion) {
257 reservation= move->motion;
260 MUSTECR( movpos_change(move,poscomb,ms,reservation) );
262 MUSTECRPREDICT( safety_movposchange(move, poscomb, ci->xarg & CIXF_U,
269 static int cmd_movfeat(ParseState *ps, const CmdInfo *ci) {
271 const SegmentInfo *movei;
272 const MovFeatInfo *mfi;
276 MUSTECR( ps_needsegment(ps,&move,&movei) );
277 mfi= some_needword_lookup_counted(ps, movei->movfeats, movei->n_movfeats,
278 "moveable feature name");
279 if (!mfi) return EC_BadCmd;
281 MUSTECR( ps_neednumber(ps,&pos_l,0,mfi->posns-1,"position number") );
284 target= movpos_change_intent(move->motion);
286 target= movpos_poscomb_actual(move);
289 if (movei->n_movfeats > 1)
290 ouprintf("info movfeat-collapsing-unknown %s :"
291 " will set previously-unknown, but not set,"
292 " feature(s) to position 0\n",
296 target= movposcomb_update_feature(target,mfi,pos_l);
298 return cmd_route_movfeat(ps,ci, move,movei,target);
301 static int cmd_route(ParseState *ps, const CmdInfo *ci) {
303 const SegmentInfo *movei;
307 MUSTECR( ps_needsegmentperhaps(ps,&move,&movei) );
308 MUSTECR( ps_needword(ps) );
309 if (CTYPE(isdigit,*ps->thisword)) {
310 if (!move) return badcmd(ps,"invalid movement specification");
312 MUSTECR( ps_neednumber(ps,&poscomb_l,0,movei->n_poscombs,
313 "position number") );
318 MUSTECR( ps_needsegment(ps,&move,&movei) );
319 MUSTECR( ps_needsegmentperhaps(ps,&fwd,0) );
320 MUSTECR( movpos_findcomb_bysegs(back,move,fwd,move->movposcomb,&poscomb) );
323 return cmd_route_movfeat(ps,ci, move,movei,poscomb);
326 static int cmd_speed(ParseState *ps, const CmdInfo *ci) {
329 const DirectionInfo *di= 0;
331 MUSTECR( ps_needtrain(ps,&tra) );
332 MUSTECR( ps_neednumber(ps,&speed,0,126,"speed step") );
334 di= some_needword_lookup_counted(ps,directioninfos,2,"direction");
335 if (!di) return EC_BadCmd;
337 MUSTECR( ps_neednoargs(ps) );
339 if (di && di->backwards != tra->backwards) {
340 ouprintf("ack %s CommandPreconditionsViolated direction\n", ci->name);
344 if (ci->xarg & CIXF_FORCE) {
345 actual_speed(tra,speed);
347 MUSTECRPREDICT( speedmanager_speedchange_request(tra,speed,CMDPPC) );
353 static int cmd_invert(ParseState *ps, const CmdInfo *ci) {
356 actual_inversions_start();
358 MUSTECR( ps_needsegment(ps,&seg,0) );
359 seg->seg_inverted ^= 1;
360 actual_inversions_segment(seg);
362 actual_inversions_done();
367 static int cmd_direction(ParseState *ps, const CmdInfo *ci) {
370 const DirectionInfo *di;
372 MUSTECR( ps_needtrain(ps,&tra) );
374 di= some_needword_lookup(ps,directioninfos,"direction");
375 if (!di) return EC_BadCmd;
377 backwards= di->change ? !tra->backwards : di->backwards;
379 MUSTECR( ps_neednoargs(ps) );
381 MUSTECRPREDICT( safety_setdirection(tra,backwards,CMDPPC) );
385 /*---------- general machinery and the command table ----------*/
387 void command_doline(ParseState *ps, CommandInput *cmdi_arg) {
391 simlog("command-in %s\n",ps->remain);
395 debug_count_event("command");
398 if (!cmdline[0]) return;
399 r= ps_word(ps); assert(!r);
400 current_cmd= some_lookup(ps,toplevel_cmds);
402 ouprintf("nak UnknownCommand\n");
405 ouprintf("executing %s\n",cmdline);
406 if (sta_state < Sta_Run && !(current_cmd->xarg & CIXF_ANYSTA)) {
407 ouprintf("ack %s InvalidState : layout not ready\n",current_cmd->name);
410 r= current_cmd->fn(ps,current_cmd);
412 case 0: ouprintf("ack %s ok\n",current_cmd->name); break;
413 case EC_BadCmd: break;
414 default: ouprintf("ack %s %s\n",current_cmd->name,errorcodelist[r]); break;
418 const CmdInfo toplevel_cmds[]= {
419 { "!pic", cmd_pic, CIXF_ANYSTA|CIXF_FORCE },
420 { "!nmra", cmd_nmra, CIXF_ANYSTA },
421 { "noop", cmd_noop, CIXF_ANYSTA },
422 { "route", cmd_route },
423 { "route+", cmd_route, 1 },
424 { "route++", cmd_route, 2 },
425 { "movfeat", cmd_movfeat },
426 { "movfeat+", cmd_movfeat, 1 },
427 { "movfeat++", cmd_movfeat, 2 },
428 { "!route", cmd_route, CIXF_ANYSTA|CIXF_FORCE },
429 { "!movfeat", cmd_movfeat, CIXF_ANYSTA|CIXF_FORCE },
430 //{ "autopoint", cmd_autopoint },
431 { "!invert", cmd_invert, CIXF_ANYSTA|CIXF_FORCE },
432 { "speed", cmd_speed },
433 { "!speed", cmd_speed, CIXF_ANYSTA|CIXF_FORCE },
434 { "direction", cmd_direction },