chiark / gitweb /
cmd_pic wip
[trains.git] / hostside / commands.c
1 /**/
2
3 #include <setjmp.h>
4 #include <stdlib.h>
5 #include <errno.h>
6 #include <assert.h>
7 #include <string.h>
8
9 #include "hostside.h"
10
11 #define NMRA_MAX_NARGS 10
12
13 typedef struct ManualRetransmitNode ManualRetransmitNode;
14 struct ManualRetransmitNode {
15   ManualRetransmitNode *back, *next;
16   char *name;
17   int lname;
18   RetransmitNode rn;
19 };
20
21 #define bogus_volatile /*empty*/
22 #ifdef __GNUC__
23 #if __GNUC__ == 2
24 #undef bogus_volatile
25 #define bogus_volatile volatile
26 #endif
27 #endif
28
29 struct NmraParseEncodeCaller {
30   ParseState *ps;
31   unsigned long arg[NMRA_MAX_NARGS];
32   jmp_buf jb;
33 };
34
35 unsigned long nmra_argnumber(NmraParseEncodeCaller *pec, int argi) {
36   return pec->arg[argi];
37 }
38
39 void nmra_problem(NmraParseEncodeCaller *pec, const char *problem) {
40   badcmd(pec->ps,problem);
41   longjmp(pec->jb, 1);
42 }
43
44 static int cmd_nmra_command(ParseState *ps, RetransmitNode *rn) {
45   int hex;
46   const char *cmdarg;
47   int lcmdarg;
48   bogus_volatile int argc, checksum;
49   NmraParseEncodeCaller pec;
50   Nmra nmra;
51   char *ep;
52
53   assert(ps->remain);
54   switch (ps->remain[0]) {
55   case '_':  ps->remain++; return ps_needhextoend(ps, rn->d, &rn->l);
56   case '=':  hex=1;  checksum=1;  break;
57   case ':':  hex=1;  checksum=0;  break;
58   default:   hex=0;  checksum=1;  break;
59   }
60
61   if (hex) {
62     ps->remain++;
63     nmra.l= NMRA_PACKET_MAX - checksum;
64     if (!ps_needhextoend(ps, nmra.d, &nmra.l))
65       return 0;
66   } else {
67     if (!ps_needword(ps)) return 0;
68     cmdarg= ps->thisword;
69     lcmdarg= ps->lthisword;
70     pec.ps= ps;
71     argc= 0;
72
73     while (ps_word(ps)) {
74       if (argc >= NMRA_MAX_NARGS) {
75         badcmd(ps,"far too many nmra args");
76         return 0;
77       }
78
79       errno=0; pec.arg[argc++]= strtoul(ps->thisword, &ep, 0);
80       if (errno || ep != ps->thisword + ps->lthisword)
81         { badcmd(ps,"bad numeric argument for nmra"); return 0; }
82     }
83     if (setjmp(pec.jb))
84       return 0;
85   
86     nmra_parse_encode(&nmra, cmdarg,lcmdarg, argc, &pec);
87   }
88   if (checksum)
89     nmra_addchecksum(&nmra);
90
91   nmra_encodeforpic(&nmra, rn->d, &rn->l);
92   return 1;
93 }
94   
95 static void cmd_nmra(ParseState *ps, const CmdInfo *ci) {
96   static struct { ManualRetransmitNode *head, *tail; } mrns;
97   
98   ManualRetransmitNode *mrn;
99   RetransmitNode *rn, rn_buf;
100   
101   if (ps->remain && ps->remain[0]=='*') {
102     const char *mrname;
103     int lmrname;
104
105     ps_word(ps);
106     mrname= ps->thisword+1;
107     lmrname= ps->lthisword-1;
108
109     for (mrn= mrns.head;
110          !(mrn->lname == lmrname &&
111            !memcmp(mrn->name, mrname, lmrname));
112          mrn= mrn->next);
113     if (mrn) {
114       retransmit_cancel(&mrn->rn);
115     } else {
116       mrn= mmalloc(sizeof(*mrn));
117       mrn->name= mmalloc(lmrname);
118       memcpy(mrn->name, mrname, lmrname);
119       mrn->lname= lmrname;
120     }
121   } else {
122     mrn= 0;
123   }
124
125   if (!ps->remain) {
126     if (!mrn) {
127       badcmd(ps,"nmra must have slot to cancel or data to send");
128       return;
129     }
130     free(mrn->name);
131     free(mrn);
132     return;
133   }
134
135   rn= mrn ? &mrn->rn : &rn_buf;
136   rn->l= sizeof(rn->d);
137   
138   if (!cmd_nmra_command(ps, rn)) {
139     if (mrn) { free(mrn->name); free(mrn); }
140     return;
141   }
142
143   if (mrn)
144     retransmit_queue(&mrn->rn);
145   else
146     serial_transmit(rn->d, rn->l);
147 }
148
149 static void cmd_noop(ParseState *ps, const CmdInfo *ci) {
150   oprintf(&ps->cl->ch,"noop successful\n");
151 }
152
153 typedef struct PicCmdInfo PicCmdInfo;
154 struct PicCmdInfo {
155   const char *name;
156   Byte opcode;
157   int argbits;
158 };
159
160 static void cmd_pic(ParseState *ps, const CmdInfo *ci) {
161   if (!ps_needword(ps)) return;
162 }
163
164 const CmdInfo toplevel_cmds[]= {
165   { "pic",        cmd_pic         },
166   { "nmra",       cmd_nmra,       },
167   { "noop",       cmd_noop        },
168   { 0 }
169 };