chiark / gitweb /
giant reorg abolishes TrainNum most of the time; working on making it build
[trains.git] / hostside / startup.c
1 /*
2  * realtime
3  * startup state machine
4  */
5
6 #include "realtime.h"
7
8 StartupState sta_state;
9
10 static TimeoutEvent sta_toev;
11 static TimeoutEvent ping_toev;
12
13 static int ping_seq;
14 static PicInsn piob;
15 static void sta_goto(StartupState new_state);
16
17 static void timedout_onward(TimeoutEvent *toev) {
18   assert(sta_state != Sta_Run);
19   if (sta_state == Sta_Settling) {
20     enco_pic_off(&piob);
21     serial_transmit(&piob);
22   }
23   sta_goto(sta_state == Sta_Flush ? Sta_Ping : sta_state + 1);
24 }
25
26 static void timedout_ping(TimeoutEvent *toev) {
27   assert(sta_state >= Sta_Ping);
28   sta_goto(Sta_Off);
29 }
30
31 static void timefor_ping(TimeoutEvent *toev) {
32   enco_pic_ping(&piob, ping_seq);
33   serial_transmit(&piob);
34   ping_toev.callback= timedout_ping;
35   toev_start(&ping_toev);
36 }
37
38 static void initial_ping(void) {
39   struct timeval now;
40   
41   mgettimeofday(&now);
42   ping_seq= (now.tv_sec & 0x1fU) << 5; /* bottom 5bi of secs: period 32s */
43   ping_seq |= (now.tv_usec >> 15);      /* top 5bi of 20bi us: res.~2^15us */
44   ping_toev.duration=  300;
45   timefor_ping(0);
46 }
47
48 void sta_startup(void) { sta_goto(Sta_Flush); }
49
50 static void sta_goto(StartupState new_state) {
51   toev_stop(&sta_toev);
52   sta_toev.callback= timedout_onward;
53   sta_toev.duration= -1;
54
55   if (new_state < Sta_Ping) {
56     toev_stop(&ping_toev);
57   } else if (new_state == Sta_Ping) {
58     initial_ping();
59   } else {
60     assert(sta_state >= Sta_Ping);
61   }
62
63   switch (new_state) {
64   case Sta_Flush:      sta_toev.duration=   300;   break;
65   case Sta_Off:                                    break;
66   case Sta_Ping:                                   break;
67   case Sta_Fault:                                  break;
68   case Sta_Settling:   sta_toev.duration=   750;   break;
69   case Sta_Resolving:  sta_toev.duration=   500;   break;
70   case Sta_Run:                                    break;
71   }
72
73   piob.l= 0;
74   switch (new_state) {
75   case Sta_Flush:                                                  break;
76   case Sta_Off:   if (sta_state > Sta_Ping) enco_pic_off(&piob);   break;
77   case Sta_Ping:                                                   break;
78   case Sta_Fault:                                                  break;
79   case Sta_Settling:                        enco_pic_off(&piob);   break;
80   case Sta_Resolving:                       enco_pic_on(&piob);    break;
81   case Sta_Run:                                                    break;
82   }
83   if (piob.l) serial_transmit(&piob);
84
85   toev_start(&sta_toev);
86   sta_state= new_state;
87
88   /* notify various people: */
89   oprintf(UPO, "stastate %d\n", sta_state);
90   /* ... add others here. */
91 }   
92
93 void serial_moredata(PicInsn *buf) {
94   const PicInsnInfo *pii;
95   int objnum;
96   Byte *ep;
97
98   /* Called when more data is received from PICs.
99    * On entry, buf->l is amount of data available.
100    * Does one of the following:
101    *  - determines that there is no complete message; sets buf->l = 0
102    *  - finds and handles one PicInsn message, sets buf->l = message length
103    *  - handles some series of bytes structured some other way,
104    *       sets buf->l to the numer of bytes handled.
105    */
106   assert(buf->l > 0);
107   
108   if (sta_state == Sta_Flush) {
109     toev_start(&sta_toev);
110     ouhex("picioh in junk", buf->d, buf->l);
111     return; /* junk absolutely everything */
112   }
113   if (PICMSG_AAARGH_P(buf->d[0])) {
114     ouhex("picioh in aaargh", buf->d, buf->l);
115     die("PIC sent us AAARGH!");
116   }
117   if (PICMSG_HELLO_P(buf->d[0])) {
118     ouhex("picioh in hello", buf->d, 1);
119     abandon_run();
120     sta_goto(Sta_Flush);
121     buf->l= 1;
122     return;
123   }
124   if (sta_state == Sta_Off) {
125     ouhex("picioh in off", buf->d, 1);
126     buf->l= 1;
127     return;
128   }
129
130   assert(sta_state >= Sta_Ping);
131   /* So, we are expecting properly formed messages. */
132   
133   for (ep= buf->d; ep < buf->d + buf->l; ep++)
134     if (!(*ep & 0x80u))
135       goto found_end;
136
137   if (buf->l == sizeof(buf->d)) {
138     ouhex("picioh in toolong", buf->d, buf->l);
139     die("PIC sent packet too long");
140   }
141   buf->l= 0; /* message not yet finished, so consume nothing */
142   return;
143
144  found_end:
145   /* Aha! */
146   buf->l= ep - buf->d + 1;
147   ouhex("picioh in msg", buf->d, buf->l);
148   picinsn_decode(buf, pic_reply_infos, &pii, &objnum);
149   if (!pii) { oprintf(UPO, "picio in unknown\n"); return; }
150   oupicio("in",pii,objnum);
151   pii->input_fn(pii,buf,objnum);
152 }
153
154 void on_pic_pong(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
155   if (objnum != ping_seq)
156     die("PIC sent wrong ping response (0x%x, wanted 0x%x)", objnum, ping_seq);
157
158   ping_toev.duration= 1000;
159   ping_toev.callback= timefor_ping;
160   toev_start(&ping_toev);
161
162   if (sta_state == Sta_Ping)
163     sta_goto(Sta_Settling);
164 }
165
166 void on_pic_fixed(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
167   if (sta_state >= Sta_Resolving) die("PIC sent unexpected FIXED");
168   if (sta_state == Sta_Fault) sta_goto(Sta_Resolving);
169 }
170
171 void on_pic_fault(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
172   if (sta_state <= Sta_Ping) return;
173   if (sta_state == Sta_Fault) die("PIC sent two FAULTs");
174   sta_goto(Sta_Fault);
175 }
176
177 void on_pic_wtimeout(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
178   if (sta_state <= Sta_Settling) return;
179   if (sta_state == Sta_Resolving) die("PIC sent WTIMEOUT in Resolving");
180   oprintf(UPO, "warning watchdog \"PIC watchdog timer triggered\"\n");
181 }
182
183 void on_pic_hello(const PicInsnInfo *pii, const PicInsn *pi, int objnum)
184   { abort(); }
185 void on_pic_aaargh(const PicInsnInfo *pii, const PicInsn *pi, int objnum)
186   { abort(); }
187
188 void on_pic_detect1(const PicInsnInfo *pii, const PicInsn *pi, int segn) {
189   if (segn >= NUM_SEGMENTS) die("PIC sent detect @#%d out of range",segn);
190   if (sta_state < Sta_Run) {
191     oprintf(UPO, "warning fixme ignored non-Run detection @%s\n",
192             info_segments[segn].pname);
193     return;
194   }
195   safety_notify_detection(&segments[segn]);
196 }
197
198 /*---------- fixme move these to where they want to go ----------*/
199
200 void on_pic_nmradone(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
201   if (sta_state <= Sta_Settling) return;
202   if (sta_state != Sta_Run) die("PIC sent NMRADONE in Resolving");
203   
204   /* fixme transmit something else (move this to another file?) */
205 }
206
207 void on_pic_detect0(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
208 }
209
210 void abandon_run(void) {
211   /* fixme do something here */
212 }
213
214 const CmdInfo toplevel_cmds[]= {
215 #if 0
216   { "pic",        cmd_pic         },
217   { "nmra",       cmd_nmra,       },
218   { "noop",       cmd_noop        },
219 #endif
220   { 0 }
221 };