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