3 * startup state machine
8 const char *const stastatelist[]= DEFINE_STASTATE_DATA;
9 StartupState sta_state;
11 static TimeoutEvent sta_toev= { .pclass="startup", .pinst="sta" };
14 static void sta_goto(StartupState new_state);
16 /*---------- ping ----------*/
19 static TimeoutEvent ping_toev= { .pinst="ping" };
21 static void timedout_ping(TimeoutEvent *toev) {
22 assert(sta_state >= Sta_Ping);
26 static void timefor_ping(TimeoutEvent *toev) {
27 enco_pic_ping(&piob, pong_seq ^ PING_PONG_PATTERN);
28 serial_transmit(&piob);
29 ping_toev.callback= timedout_ping;
30 ping_toev.pclass= "startup";
31 toev_start(&ping_toev);
34 static void initial_ping(void) {
38 pong_seq= (now.tv_sec & 0x1fU) << 5; /* bottom 5bi of secs: period 32s */
39 pong_seq |= (now.tv_usec >> 15); /* top 5bi of 20bi us: res.~2^15us */
40 ping_toev.duration= 300;
44 /*---------- watchdog ----------*/
46 static TimeoutEvent watchdog_toev= {
47 .pclass=toev_fast_pclass,
49 .duration= UNMARGIN_WATCHDOG - MARGIN_WATCHDOG,
51 static PicInsn watchdog_piob;
53 static void watchdog_transmit(TimeoutEvent *toev) {
54 check_rusage_check(0);
55 toev_start(&watchdog_toev);
56 serial_transmit(&watchdog_piob);
59 static void watchdog_start(void) {
60 check_rusage_baseline();
61 watchdog_toev.callback= watchdog_transmit;
62 enco_pic_watchdog(&watchdog_piob, UNMARGIN_WATCHDOG_16);
66 static void watchdog_stop(void) {
67 if (!watchdog_toev.running) return;
68 toev_stop(&watchdog_toev);
69 enco_pic_watchdog(&watchdog_piob, 0);
70 serial_transmit(&watchdog_piob);
71 check_rusage_check(1);
74 /*---------- main startup algorithm ----------*/
76 static void timedout_onward(TimeoutEvent *toev) {
77 assert(sta_state != Sta_Run);
78 if (sta_state == Sta_Settling) {
80 serial_transmit(&piob);
82 sta_goto(sta_state == Sta_Flush ? Sta_Ping : sta_state + 1);
85 static void sta_startup_manual(void) {
86 waggle_startup_manual();
88 ouprintf("stastate %s\n", stastatelist[sta_state]);
91 void sta_startup(void) {
92 if (sta_state == Sta_Manual) sta_startup_manual();
93 else sta_goto(Sta_Flush);
96 void sta_finalising_done(void) { sta_goto(Sta_Run); }
98 static void sta_goto(StartupState new_state) {
100 sta_toev.callback= timedout_onward;
101 sta_toev.duration= -1;
103 if (new_state < Sta_Ping) {
104 toev_stop(&ping_toev);
105 } else if (new_state == Sta_Ping) {
108 assert(sta_state >= Sta_Ping);
112 case Sta_Flush: sta_toev.duration= 300; break;
114 case Sta_Manual: abort();
115 case Sta_Ping: break;
116 case Sta_Settling: sta_toev.duration= 750; break;
117 case Sta_Resolving: sta_toev.duration= 500; break;
118 case Sta_Finalising: break;
120 case Sta_Crashed: abort();
123 if (new_state < Sta_Run)
124 choreographers_all_abandon();
125 if (new_state < Sta_Finalising) {
126 safety_abandon_run();
127 motions_all_abandon();
132 case Sta_Flush: break;
133 case Sta_Off: if (sta_state > Sta_Ping) enco_pic_off(&piob); break;
134 case Sta_Manual: abort();
135 case Sta_Ping: break;
136 case Sta_Settling: waggle_settle(); enco_pic_off(&piob); break;
140 adjuncts_start_xmit();
144 if (resolve_complete() <0)
145 /* in this case, we get stuck - user has to power cycle the layout */
147 /* resolve_motioncheck will move us to Run eventually, we hope */
155 case Sta_Crashed: abort();
157 if (piob.l) serial_transmit(&piob);
159 if (new_state >= Sta_Run && !disable_watchdog) watchdog_start();
160 else watchdog_stop();
162 toev_start(&sta_toev);
163 sta_state= new_state;
165 /* notify various people: */
166 ouprintf("stastate %s\n", stastatelist[sta_state]);
167 /* ... add others here. */
168 if (sta_state == Sta_Finalising) resolve_motioncheck();
171 void serial_moredata(PicInsn *buf) {
172 const PicInsnInfo *pii;
173 int obj, v, suppress;
176 /* Called when more data is received from PICs.
177 * On entry, buf->l is amount of data available.
178 * Does one of the following:
179 * - determines that there is no complete message; sets buf->l = 0
180 * - finds and handles one PicInsn message, sets buf->l = message length
181 * - handles some series of bytes structured some other way,
182 * sets buf->l to the numer of bytes handled.
186 if (sta_state == Sta_Flush) {
187 ouhex("picioh in junk", buf->d, buf->l);
188 toev_start(&sta_toev);
189 return; /* junk absolutely everything */
191 if (PICMSG_AAARGH_P(buf->d[0])) {
192 ouhex("picioh in aaargh", buf->d, buf->l);
193 die("PIC sent us AAARGH!");
195 if (PICMSG_HELLO_P(buf->d[0])) {
196 ouhex("picioh in hello", buf->d, 1);
197 if (sta_state != Sta_Manual)
202 if (sta_state == Sta_Off) {
203 ouhex("picioh in off", buf->d, 1);
208 assert(sta_state >= Sta_Manual);
209 /* So, we are expecting properly formed messages. */
211 for (ep= buf->d; ep < buf->d + buf->l; ep++)
215 if (buf->l == sizeof(buf->d)) {
216 ouhex("picioh in toolong", buf->d, buf->l);
217 die("PIC sent packet too long");
219 buf->l= 0; /* message not yet finished, so consume nothing */
224 buf->l= ep - buf->d + 1;
225 picinsn_decode(buf, pic_reply_infos, &pii, &obj, &v);
226 suppress= pii && pii->noiselevel > picio_send_noise;
228 if (!suppress && picio_send_noise >= 2)
229 ouhex_nosim("picioh in msg", buf->d, buf->l);
231 if (simlog_full || sta_state < Sta_Settling ||
232 !((pii->opcode==PICMSG_NMRADONE && obj==1) ||
233 (pii->opcode==PICMSG_PONG && obj==pong_seq)))
234 simlog_serial(buf->d, buf->l);
236 if (!pii) { ouprintf("picio in unknown\n"); return; }
238 oupicio("in",pii,obj,v,ouprintf_only);
239 pii->input_fn(pii,buf,obj);
242 void on_pic_nul(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
243 /* layout turned off, probably */
244 if (sta_state == Sta_Manual) return;
246 serial_transmit(&piob);
251 void on_pic_pong(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
252 if (sta_state == Sta_Manual)
255 if (objnum != pong_seq) {
256 if (objnum == (pong_seq^PING_PONG_PATTERN))
257 die("PIC connection is looped back (ping %#05x bounced)", objnum);
258 die("PIC sent wrong ping response (%#05x, wanted %#05x)", objnum, pong_seq);
261 ping_toev.duration= 1000;
262 ping_toev.callback= timefor_ping;
263 ping_toev.pclass= toev_fast_pclass;
264 toev_start(&ping_toev);
266 if (sta_state == Sta_Ping)
267 sta_goto(Sta_Settling);
270 void on_pic_fault(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
271 if (sta_state <= Sta_Ping) return;
275 void on_pic_wtimeout(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
276 if (sta_state <= Sta_Settling) return;
277 check_rusage_check(1);
278 die("microcontrollers' watchdog timer triggered\n");
281 void on_pic_hello(const PicInsnInfo *pii, const PicInsn *pi, int objnum)
283 void on_pic_aaargh(const PicInsnInfo *pii, const PicInsn *pi, int objnum)
285 void on_pic_spurious(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
286 ouprintf("warning spurious %d : spurious short circuit (fault)"
287 " detection interrupts\n", objnum);
289 void on_pic_pointed(const PicInsnInfo *pii, const PicInsn *pi, int objnum) { }
290 void on_pic_retriable(const PicInsnInfo *pii, const PicInsn *pi, int objnum){}
292 static int coalescing_detects;
294 static void detect_report_now(Segment *seg) {
295 ouprintf_only("detect %s %d\n", seg->i->pname, seg->detect_actual);
296 seg->detect_reported= seg->detect_actual;
299 static SegmentNum on_pic_detect_prep(int detyn, int objnum) {
302 if (objnum >= info_segmentmaplen ||
303 (segn= info_segmentmap[objnum]) < 0)
304 die("PIC sent detect%d @#%#x not in map",detyn,objnum);
306 Segment *seg= &segments[segn];
307 seg->detect_actual= detyn;
309 if (!(picio_send_noise <= 1 &&
312 if (cmdi.out.total >= 1024) coalescing_detects= 1;
314 if (coalescing_detects &&
316 seg->detect_reported) {
317 assert(seg->detect_flaps < INT_MAX);
320 detect_report_now(seg);
327 void cmdi_output_bufferempty(OutBufferChain *obc) {
330 if (!coalescing_detects) return;
331 coalescing_detects= 0;
334 if (seg->detect_flaps) {
335 ouprintf_only("detect-flaps %s %d\n", segi->pname, seg->detect_flaps);
336 seg->detect_flaps= 0;
338 if (seg->detect_actual != seg->detect_reported) {
339 detect_report_now(seg);
344 void on_pic_detect1(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
349 segn= on_pic_detect_prep(1,objnum);
350 seg= &segments[segn];
351 pname= info_segments[segn].pname;
364 if (!seg->res_detect) {
365 ouprintf("resolution new-detection-in-finalising @%s\n", pname);
366 sta_goto(Sta_Settling);
370 safety_notify_detection(seg);
372 case Sta_Crashed: abort();
376 void on_pic_detect0(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
377 on_pic_detect_prep(0,objnum);
380 void choreographers_all_abandon(void) { }