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 toev_start(&watchdog_toev);
55 serial_transmit(&watchdog_piob);
58 static void watchdog_start(void) {
59 watchdog_toev.callback= watchdog_transmit;
60 enco_pic_watchdog(&watchdog_piob, UNMARGIN_WATCHDOG_16);
64 static void watchdog_stop(void) {
65 if (!watchdog_toev.running) return;
66 toev_stop(&watchdog_toev);
67 enco_pic_watchdog(&watchdog_piob, 0);
68 serial_transmit(&watchdog_piob);
71 /*---------- main startup algorithm ----------*/
73 static void timedout_onward(TimeoutEvent *toev) {
74 assert(sta_state != Sta_Run);
75 if (sta_state == Sta_Settling) {
77 serial_transmit(&piob);
79 sta_goto(sta_state == Sta_Flush ? Sta_Ping : sta_state + 1);
82 static void sta_startup_manual(void) {
83 waggle_startup_manual();
85 ouprintf("stastate %s\n", stastatelist[sta_state]);
88 void sta_startup(void) {
89 if (sta_state == Sta_Manual) sta_startup_manual();
90 else sta_goto(Sta_Flush);
93 void sta_finalising_done(void) { sta_goto(Sta_Run); }
95 static void sta_goto(StartupState new_state) {
97 sta_toev.callback= timedout_onward;
98 sta_toev.duration= -1;
100 if (new_state < Sta_Ping) {
101 toev_stop(&ping_toev);
102 } else if (new_state == Sta_Ping) {
105 assert(sta_state >= Sta_Ping);
109 case Sta_Flush: sta_toev.duration= 300; break;
111 case Sta_Manual: abort();
112 case Sta_Ping: break;
113 case Sta_Settling: sta_toev.duration= 750; break;
114 case Sta_Resolving: sta_toev.duration= 500; break;
115 case Sta_Finalising: break;
117 case Sta_Crashed: abort();
120 if (new_state < Sta_Run)
121 choreographers_all_abandon();
122 if (new_state < Sta_Finalising) {
123 safety_abandon_run();
124 motions_all_abandon();
129 case Sta_Flush: break;
130 case Sta_Off: if (sta_state > Sta_Ping) enco_pic_off(&piob); break;
131 case Sta_Manual: abort();
132 case Sta_Ping: break;
133 case Sta_Settling: waggle_settle(); enco_pic_off(&piob); break;
137 adjuncts_start_xmit();
141 if (resolve_complete() <0)
142 /* in this case, we get stuck - user has to power cycle the layout */
144 /* resolve_motioncheck will move us to Run eventually, we hope */
151 case Sta_Crashed: abort();
153 if (piob.l) serial_transmit(&piob);
155 if (new_state >= Sta_Run && !disable_watchdog) watchdog_start();
156 else watchdog_stop();
158 toev_start(&sta_toev);
159 sta_state= new_state;
161 /* notify various people: */
162 ouprintf("stastate %s\n", stastatelist[sta_state]);
163 /* ... add others here. */
164 if (sta_state == Sta_Finalising) resolve_motioncheck();
167 void serial_moredata(PicInsn *buf) {
168 const PicInsnInfo *pii;
169 int obj, v, suppress;
172 /* Called when more data is received from PICs.
173 * On entry, buf->l is amount of data available.
174 * Does one of the following:
175 * - determines that there is no complete message; sets buf->l = 0
176 * - finds and handles one PicInsn message, sets buf->l = message length
177 * - handles some series of bytes structured some other way,
178 * sets buf->l to the numer of bytes handled.
182 if (sta_state == Sta_Flush) {
183 ouhex("picioh in junk", buf->d, buf->l);
184 toev_start(&sta_toev);
185 return; /* junk absolutely everything */
187 if (PICMSG_AAARGH_P(buf->d[0])) {
188 ouhex("picioh in aaargh", buf->d, buf->l);
189 die("PIC sent us AAARGH!");
191 if (PICMSG_HELLO_P(buf->d[0])) {
192 ouhex("picioh in hello", buf->d, 1);
193 if (sta_state != Sta_Manual)
198 if (sta_state == Sta_Off) {
199 ouhex("picioh in off", buf->d, 1);
204 assert(sta_state >= Sta_Manual);
205 /* So, we are expecting properly formed messages. */
207 for (ep= buf->d; ep < buf->d + buf->l; ep++)
211 if (buf->l == sizeof(buf->d)) {
212 ouhex("picioh in toolong", buf->d, buf->l);
213 die("PIC sent packet too long");
215 buf->l= 0; /* message not yet finished, so consume nothing */
220 buf->l= ep - buf->d + 1;
221 picinsn_decode(buf, pic_reply_infos, &pii, &obj, &v);
222 suppress= pii && pii->noiselevel > picio_send_noise;
224 if (!suppress && picio_send_noise >= 2)
225 ouhex_nosim("picioh in msg", buf->d, buf->l);
227 if (simlog_full || sta_state < Sta_Settling ||
228 !((pii->opcode==PICMSG_NMRADONE && obj==1) ||
229 (pii->opcode==PICMSG_PONG && obj==pong_seq)))
230 simlog_serial(buf->d, buf->l);
232 if (!pii) { ouprintf("picio in unknown\n"); return; }
234 oupicio("in",pii,obj,v,ouprintf_only);
235 pii->input_fn(pii,buf,obj);
238 void on_pic_nul(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
239 /* layout turned off, probably */
240 if (sta_state == Sta_Manual) return;
242 serial_transmit(&piob);
247 void on_pic_pong(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
248 if (sta_state == Sta_Manual)
251 if (objnum != pong_seq) {
252 if (objnum == (pong_seq^PING_PONG_PATTERN))
253 die("PIC connection is looped back (ping %#05x bounced)", objnum);
254 die("PIC sent wrong ping response (%#05x, wanted %#05x)", objnum, pong_seq);
257 ping_toev.duration= 1000;
258 ping_toev.callback= timefor_ping;
259 ping_toev.pclass= toev_fast_pclass;
260 toev_start(&ping_toev);
262 if (sta_state == Sta_Ping)
263 sta_goto(Sta_Settling);
266 void on_pic_fault(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
267 if (sta_state <= Sta_Ping) return;
271 void on_pic_wtimeout(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
272 if (sta_state <= Sta_Settling) return;
273 die("microcontrollers' watchdog timer triggered\n");
276 void on_pic_hello(const PicInsnInfo *pii, const PicInsn *pi, int objnum)
278 void on_pic_aaargh(const PicInsnInfo *pii, const PicInsn *pi, int objnum)
280 void on_pic_spurious(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
281 ouprintf("warning spurious %d : spurious short circuit (fault)"
282 " detection interrupts\n", objnum);
284 void on_pic_pointed(const PicInsnInfo *pii, const PicInsn *pi, int objnum) { }
285 void on_pic_retriable(const PicInsnInfo *pii, const PicInsn *pi, int objnum){}
287 static int coalescing_detects;
289 static void detect_report_now(Segment *seg) {
290 ouprintf_only("detect %s %d\n", seg->i->pname, seg->detect_actual);
291 seg->detect_reported= seg->detect_actual;
294 static SegmentNum on_pic_detect_prep(int detyn, int objnum) {
297 if (objnum >= info_segmentmaplen ||
298 (segn= info_segmentmap[objnum]) < 0)
299 die("PIC sent detect%d @#%#x not in map",detyn,objnum);
301 Segment *seg= &segments[segn];
302 seg->detect_actual= detyn;
304 if (!(picio_send_noise <= 1 &&
307 if (cmdi.out.total >= 1024) coalescing_detects= 1;
309 if (coalescing_detects &&
311 seg->detect_reported) {
312 assert(seg->detect_flaps < INT_MAX);
315 detect_report_now(seg);
322 void cmdi_output_bufferempty(OutBufferChain *obc) {
325 if (!coalescing_detects) return;
326 coalescing_detects= 0;
329 if (seg->detect_flaps) {
330 ouprintf_only("detect-flaps %s %d\n", segi->pname, seg->detect_flaps);
331 seg->detect_flaps= 0;
333 if (seg->detect_actual != seg->detect_reported) {
334 detect_report_now(seg);
339 void on_pic_detect1(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
344 segn= on_pic_detect_prep(1,objnum);
345 seg= &segments[segn];
346 pname= info_segments[segn].pname;
359 if (!seg->res_detect) {
360 ouprintf("resolution new-detection-in-finalising @%s\n", pname);
361 sta_goto(Sta_Settling);
365 safety_notify_detection(seg);
367 case Sta_Crashed: abort();
371 void on_pic_detect0(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
372 on_pic_detect_prep(0,objnum);
375 void choreographers_all_abandon(void) { }