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