3 * startup state machine
8 const char *const stastatelist[]= DEFINE_STASTATE_DATA;
9 StartupState sta_state;
11 static TimeoutEvent sta_toev;
12 static TimeoutEvent ping_toev;
16 static void sta_goto(StartupState new_state);
18 static void timedout_onward(TimeoutEvent *toev) {
19 assert(sta_state != Sta_Run);
20 if (sta_state == Sta_Settling) {
22 serial_transmit(&piob);
24 sta_goto(sta_state == Sta_Flush ? Sta_Ping : sta_state + 1);
27 static void timedout_ping(TimeoutEvent *toev) {
28 assert(sta_state >= Sta_Ping);
32 static void timefor_ping(TimeoutEvent *toev) {
33 enco_pic_ping(&piob, ping_seq);
34 serial_transmit(&piob);
35 ping_toev.callback= timedout_ping;
36 toev_start(&ping_toev);
39 static void initial_ping(void) {
43 ping_seq= (now.tv_sec & 0x1fU) << 5; /* bottom 5bi of secs: period 32s */
44 ping_seq |= (now.tv_usec >> 15); /* top 5bi of 20bi us: res.~2^15us */
45 ping_toev.duration= 300;
49 void sta_startup(void) { sta_goto(Sta_Flush); }
51 static void sta_goto(StartupState new_state) {
53 sta_toev.callback= timedout_onward;
54 sta_toev.duration= -1;
56 if (new_state < Sta_Ping) {
57 toev_stop(&ping_toev);
58 } else if (new_state == Sta_Ping) {
61 assert(sta_state >= Sta_Ping);
65 case Sta_Flush: sta_toev.duration= 300; break;
68 case Sta_Fault: break;
69 case Sta_Settling: sta_toev.duration= 750; break;
70 case Sta_Resolving: sta_toev.duration= 500; break;
74 if (new_state < Sta_Run)
75 choreographers_all_abandon();
76 if (new_state < Sta_Resolving)
81 case Sta_Flush: break;
82 case Sta_Off: if (sta_state > Sta_Ping) enco_pic_off(&piob); break;
84 case Sta_Fault: break;
85 case Sta_Settling: enco_pic_off(&piob); break;
92 if (resolve_complete() <0)
93 /* in this case, we get stuck - user has to power cycle the layout */
99 if (piob.l) serial_transmit(&piob);
101 toev_start(&sta_toev);
102 sta_state= new_state;
104 /* notify various people: */
105 oprintf(UPO, "stastate %s\n", stastatelist[sta_state]);
106 /* ... add others here. */
109 void serial_moredata(PicInsn *buf) {
110 const PicInsnInfo *pii;
111 int objnum, suppress;
114 /* Called when more data is received from PICs.
115 * On entry, buf->l is amount of data available.
116 * Does one of the following:
117 * - determines that there is no complete message; sets buf->l = 0
118 * - finds and handles one PicInsn message, sets buf->l = message length
119 * - handles some series of bytes structured some other way,
120 * sets buf->l to the numer of bytes handled.
124 if (sta_state == Sta_Flush) {
125 toev_start(&sta_toev);
126 ouhex("picioh in junk", buf->d, buf->l);
127 return; /* junk absolutely everything */
129 if (PICMSG_AAARGH_P(buf->d[0])) {
130 ouhex("picioh in aaargh", buf->d, buf->l);
131 die("PIC sent us AAARGH!");
133 if (PICMSG_HELLO_P(buf->d[0])) {
134 ouhex("picioh in hello", buf->d, 1);
139 if (sta_state == Sta_Off) {
140 ouhex("picioh in off", buf->d, 1);
145 assert(sta_state >= Sta_Ping);
146 /* So, we are expecting properly formed messages. */
148 for (ep= buf->d; ep < buf->d + buf->l; ep++)
152 if (buf->l == sizeof(buf->d)) {
153 ouhex("picioh in toolong", buf->d, buf->l);
154 die("PIC sent packet too long");
156 buf->l= 0; /* message not yet finished, so consume nothing */
161 buf->l= ep - buf->d + 1;
162 picinsn_decode(buf, pic_reply_infos, &pii, &objnum);
163 suppress= pii && pii->noiselevel > picio_send_noise;
164 if (!suppress && picio_send_noise >= 2)
165 ouhex("picioh in msg", buf->d, buf->l);
166 if (!pii) { oprintf(UPO, "picio in unknown\n"); return; }
168 oupicio("in",pii,objnum);
169 pii->input_fn(pii,buf,objnum);
172 void on_pic_pong(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
173 if (objnum != ping_seq)
174 die("PIC sent wrong ping response (0x%x, wanted 0x%x)", objnum, ping_seq);
176 ping_toev.duration= 1000;
177 ping_toev.callback= timefor_ping;
178 toev_start(&ping_toev);
180 if (sta_state == Sta_Ping)
181 sta_goto(Sta_Settling);
184 void on_pic_fixed(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
185 if (sta_state >= Sta_Resolving) die("PIC sent unexpected FIXED");
186 if (sta_state == Sta_Fault) sta_goto(Sta_Resolving);
189 void on_pic_fault(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
190 if (sta_state <= Sta_Ping) return;
191 if (sta_state == Sta_Fault) die("PIC sent two FAULTs");
195 void on_pic_wtimeout(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
196 if (sta_state <= Sta_Settling) return;
197 if (sta_state == Sta_Resolving) die("PIC sent WTIMEOUT in Resolving");
198 oprintf(UPO, "warning watchdog \"PIC watchdog timer triggered\"\n");
201 void on_pic_hello(const PicInsnInfo *pii, const PicInsn *pi, int objnum)
203 void on_pic_aaargh(const PicInsnInfo *pii, const PicInsn *pi, int objnum)
205 void on_pic_spurious(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
206 oprintf(UPO,"warning spurious %d \"spurious short circuit (fault)"
207 " detection interrupts\"", objnum);
210 void on_pic_detect1(const PicInsnInfo *pii, const PicInsn *pi, int segn) {
212 if (segn >= NUM_SEGMENTS) die("PIC sent detect @#%d out of range",segn);
214 seg= &segments[segn];
222 oprintf(UPO, "warning fixme ignored non-Run detection @%s\n",
223 info_segments[segn].pname);
225 case Sta_Resolving: seg->res_detect= 1; break;
226 case Sta_Run: safety_notify_detection(seg); break;
230 /*---------- fixme move these to where they want to go ----------*/
232 void on_pic_nmradone(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
233 if (!objnum) die("PIC sent NUL!");
234 if (sta_state <= Sta_Settling) return;
235 if (sta_state != Sta_Run) die("PIC sent NMRADONE in Resolving");
238 retransmit_something();
241 void on_pic_detect0(const PicInsnInfo *pii, const PicInsn *pi, int objnum) {
244 void choreographers_all_abandon(void) { }