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 */
154 case Sta_Crashed: abort();
156 if (piob.l) serial_transmit(&piob);
158 if (new_state >= Sta_Run && !disable_watchdog) watchdog_start();
159 else watchdog_stop();
161 toev_start(&sta_toev);
162 sta_state= new_state;
164 /* notify various people: */
165 ouprintf("stastate %s\n", stastatelist[sta_state]);
166 /* ... add others here. */
167 if (sta_state == Sta_Finalising) resolve_motioncheck();
170 void serial_moredata(PicInsn *buf) {
171 const PicInsnInfo *pii;
172 int obj, v, suppress;
175 /* Called when more data is received from PICs.
176 * On entry, buf->l is amount of data available.
177 * Does one of the following:
178 * - determines that there is no complete message; sets buf->l = 0
179 * - finds and handles one PicInsn message, sets buf->l = message length
180 * - handles some series of bytes structured some other way,
181 * sets buf->l to the numer of bytes handled.
185 if (sta_state == Sta_Flush) {
186 ouhex("picioh in junk", buf->d, buf->l);
187 toev_start(&sta_toev);
188 return; /* junk absolutely everything */
190 if (PICMSG_AAARGH_P(buf->d[0])) {
191 ouhex("picioh in aaargh", buf->d, buf->l);
192 die("PIC sent us AAARGH!");
194 if (PICMSG_HELLO_P(buf->d[0])) {
195 ouhex("picioh in hello", buf->d, 1);
196 if (sta_state != Sta_Manual)
201 if (sta_state == Sta_Off) {
202 ouhex("picioh in off", buf->d, 1);
207 assert(sta_state >= Sta_Manual);
208 /* So, we are expecting properly formed messages. */
210 for (ep= buf->d; ep < buf->d + buf->l; ep++)
214 if (buf->l == sizeof(buf->d)) {
215 ouhex("picioh in toolong", buf->d, buf->l);
216 die("PIC sent packet too long");
218 buf->l= 0; /* message not yet finished, so consume nothing */
223 buf->l= ep - buf->d + 1;
224 picinsn_decode(buf, pic_reply_infos, &pii, &obj, &v);
225 suppress= pii && pii->noiselevel > picio_send_noise;
227 if (!suppress && picio_send_noise >= 2)
228 ouhex_nosim("picioh in msg", buf->d, buf->l);
230 if (simlog_full || sta_state < Sta_Settling ||
231 !((pii->opcode==PICMSG_NMRADONE && obj==1) ||
232 (pii->opcode==PICMSG_PONG && obj==pong_seq)))
233 simlog_serial(buf->d, buf->l);
235 if (!pii) { ouprintf("picio in unknown\n"); return; }
237 oupicio("in",pii,obj,v,ouprintf_only);
238 pii->input_fn(pii,buf,obj);
241 void on_pic_nul(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
242 /* layout turned off, probably */
243 if (sta_state == Sta_Manual) return;
245 serial_transmit(&piob);
250 void on_pic_pong(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
251 if (sta_state == Sta_Manual)
254 if (objnum != pong_seq) {
255 if (objnum == (pong_seq^PING_PONG_PATTERN))
256 die("PIC connection is looped back (ping %#05x bounced)", objnum);
257 die("PIC sent wrong ping response (%#05x, wanted %#05x)", objnum, pong_seq);
260 ping_toev.duration= 1000;
261 ping_toev.callback= timefor_ping;
262 ping_toev.pclass= toev_fast_pclass;
263 toev_start(&ping_toev);
265 if (sta_state == Sta_Ping)
266 sta_goto(Sta_Settling);
269 void on_pic_fault(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
270 if (sta_state <= Sta_Ping) return;
274 void on_pic_wtimeout(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
275 if (sta_state <= Sta_Settling) return;
276 check_rusage_check(1);
277 die("microcontrollers' watchdog timer triggered\n");
280 void on_pic_hello(const PicInsnInfo *pii, const PicInsn *pi, int objnum)
282 void on_pic_aaargh(const PicInsnInfo *pii, const PicInsn *pi, int objnum)
284 void on_pic_spurious(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
285 ouprintf("warning spurious %d : spurious short circuit (fault)"
286 " detection interrupts\n", objnum);
288 void on_pic_pointed(const PicInsnInfo *pii, const PicInsn *pi, int objnum) { }
289 void on_pic_retriable(const PicInsnInfo *pii, const PicInsn *pi, int objnum){}
291 static int coalescing_detects;
293 static void detect_report_now(Segment *seg) {
294 ouprintf_only("detect %s %d\n", seg->i->pname, seg->detect_actual);
295 seg->detect_reported= seg->detect_actual;
298 static SegmentNum on_pic_detect_prep(int detyn, int objnum) {
301 if (objnum >= info_segmentmaplen ||
302 (segn= info_segmentmap[objnum]) < 0)
303 die("PIC sent detect%d @#%#x not in map",detyn,objnum);
305 Segment *seg= &segments[segn];
306 seg->detect_actual= detyn;
308 if (!(picio_send_noise <= 1 &&
311 if (cmdi.out.total >= 1024) coalescing_detects= 1;
313 if (coalescing_detects &&
315 seg->detect_reported) {
316 assert(seg->detect_flaps < INT_MAX);
319 detect_report_now(seg);
326 void cmdi_output_bufferempty(OutBufferChain *obc) {
329 if (!coalescing_detects) return;
330 coalescing_detects= 0;
333 if (seg->detect_flaps) {
334 ouprintf_only("detect-flaps %s %d\n", segi->pname, seg->detect_flaps);
335 seg->detect_flaps= 0;
337 if (seg->detect_actual != seg->detect_reported) {
338 detect_report_now(seg);
343 void on_pic_detect1(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
348 segn= on_pic_detect_prep(1,objnum);
349 seg= &segments[segn];
350 pname= info_segments[segn].pname;
363 if (!seg->res_detect) {
364 ouprintf("resolution new-detection-in-finalising @%s\n", pname);
365 sta_goto(Sta_Settling);
369 safety_notify_detection(seg);
371 case Sta_Crashed: abort();
375 void on_pic_detect0(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
376 on_pic_detect_prep(0,objnum);
379 void choreographers_all_abandon(void) { }