/**/
-#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 }
};