2 * main program for realtime control
5 #include <sys/resource.h>
9 const char *progname= "realtime";
11 /*---------- global variables ----------*/
14 int picio_send_noise= 1;
17 static const char *device= "/dev/railway";
18 static const char *logcopy_fn;
20 /*---------- general event handling ----------*/
22 static void comms_error(const char *ch, const char *e1,
23 const char *e2 /* may be 0 */) {
24 if (!e1 && !e2) e1= "end of file";
25 die("communications error: %s: %s%s%s", ch, e1, e2?": ":"", e2?e2:"");
28 static void *read_exception(oop_source *evts, int fd,
29 oop_event evt, void *cl_v) {
34 ch= (fd==cmdi.out.fd ? cmdi.out.desc :
35 fd==serial_fd ? "serial port" :
38 r= read(fd, &bufc, 1);
39 if (r==-1) comms_error(ch, "read error", strerror(errno));
40 else if (r==0) comms_error(ch, "reports exception, reads EOF", 0);
41 else comms_error(ch, "reports exception, but readable", 0);
46 /*---------- logging and output ----------*/
48 void safety_vpanic(Train *tra, Segment *seg,const char *fmt,va_list al) {
53 serial_transmit(&piob);
55 if (vasprintf(&msg,fmt,al) < 0)
56 diee("vasprintf failed in safety_vpanic fmt=\"%s\"", fmt);
58 die("fatal signalling problem: %s at %s: %s",
59 tra ? tra->pname : "?",
60 seg ? seg->i->pname : "?",
64 void safety_panic(Train *tra, Segment *seg, const char *fmt, ...) {
67 safety_vpanic(tra, seg, fmt, al);
70 void ouvprintf(const char *fmt, va_list al) {
71 ovprintf_ccb(&cmdi.out, simlog_ccb,0, fmt,al);
73 void ouprintf(const char *fmt, ...) {
80 void ouvprintf_only(const char *fmt, va_list al) {
81 ovprintf(&cmdi.out, fmt,al);
83 void ouprintf_only(const char *fmt, ...) {
86 ouvprintf_only(fmt,al);
90 /*---------- printing nmra data ----------*/
98 static void nmradec_init(NmraDecCtx *d, const PicInsn *pi) {
105 static void nmradec_getbits(NmraDecCtx *d, int *nbits_io, unsigned *bits_r) {
107 while (d->npending < use) {
108 if (d->i >= d->o) break;
109 d->datapending <<= 7;
110 d->datapending |= *d->i & 0x7f;
112 if (!(*d->i++ & 0x80)) break;
114 if (d->npending < use) use= d->npending;
116 *bits_r= (d->datapending >> d->npending) & ~(~0u << use);
120 static void nmra_decodeforpic(const PicInsn *pi,
121 void (*on_idle)(void *u, int),
122 void (*on_packet)(void *u, const Nmra*),
123 void (*on_error)(void *u, int reasonchar),
127 * ! - too little idle
132 int need_idle=7, got_idle=0;
138 nbits=1; nmradec_getbits(&d,&nbits,&got);
139 if (got) { got_idle++; continue; }
140 if (got_idle) on_idle(u,got_idle);
142 if (got_idle < need_idle) on_error(u,'!');
147 nbits=8; nmradec_getbits(&d,&nbits,&got);
150 if (nbits<8) on_error(u,'$');
152 nbits=1; nmradec_getbits(&d,&nbits,&got);
153 if (nbits<1) on_error(u,'$');
154 } while (nbits && !got);
156 if (csum) on_error(u,'#');
164 static void opn_idle(void *u, int idle) {
165 static const char dots[]= "......."; /* at least base/2 */
167 int largers= idle / base;
168 int units= idle % base;
170 ouprintf(" %.*s%.*s%.*s",
172 largers, ":::::::" /* enough */,
175 static void opn_error(void *u, int rc) { ouprintf(" %c",rc); }
176 static void opn_packet(void *u, const Nmra *n) {
178 const char *delim= " <";
179 for (i=0; i<n->l; i++) {
180 ouprintf("%s%02x",delim,n->d[i]);
186 static void oprint_nmradata(const PicInsn *pi) {
187 ouprintf("picio out nmradata");
188 nmra_decodeforpic(pi, opn_idle,opn_packet,opn_error, 0);
192 /*---------- command channel handling (oop_read, obc) ----------*/
194 int vbadcmd(ParseState *ps, const char *fmt, va_list al) {
195 ouprintf("ack %s BadCmd : ", current_cmd?current_cmd->name:"?");
201 void oupicio(const char *dirn, const PicInsnInfo *pii, int obj, int v,
202 void (*qprintf)(const char *fmt, ...)) {
204 qprintf("picio %s %s\n", dirn, pii->name);
205 else if (!pii->vbits)
206 qprintf("picio %s %s %#x\n", dirn, pii->name, obj);
208 qprintf("picio %s %s %#x %d\n", dirn, pii->name, obj, v);
211 static void obc_error(OutBufferChain *ch, const char *e1, const char *e2) {
212 if (!e1) { assert(!e2); die_hook(); exit(0); }
213 fprintf(stderr,"command communication error: %s%s%s\n",
214 e1, e2?": ":"", e2?e2:"");
219 static void qouhex(const char *word, const Byte *command, int length,
220 void (*qprintf)(const char *fmt, ...)) {
222 while (length--) qprintf(" %02x", *command++);
226 void ouhex(const char *word, const Byte *command, int length) {
227 qouhex(word,command,length, ouprintf);
229 void ouhex_nosim(const char *word, const Byte *command, int length) {
230 qouhex(word,command,length, ouprintf_only);
233 void die_vprintf_hook(const char *fmt, va_list al) {
234 static int recursing;
240 void die_hook(void) {
246 write(serial_fd,off.d,off.l);
247 e= events ? obc_tryflush(&cmdi.out) : 0;
248 if (e) fprintf(stderr,"(unwritten command output: %s)\n",strerror(e));
251 /*---------- serial input (via oop) ----------*/
255 static void *serial_readable(oop_source *evts, int fd,
256 oop_event evt, void *u0) {
259 r= read(serial_fd, serial_buf.d + serial_buf.l,
260 sizeof(serial_buf.d) - serial_buf.l);
262 if (r==0) die("serial port - eof");
264 if (errno == EWOULDBLOCK || errno == EINTR)
266 diee("serial port - read error");
270 buf_used= serial_buf.l + r;
271 serial_indata_process(buf_used);
275 void serial_indata_process(int buf_used) {
277 serial_buf.l= buf_used;
278 serial_moredata(&serial_buf);
279 if (!serial_buf.l) break;
280 buf_used -= serial_buf.l;
281 memmove(serial_buf.d, serial_buf.d + serial_buf.l, buf_used);
282 if (!buf_used) break;
284 serial_buf.l= buf_used;
287 /*---------- serial port output (not via liboop) ----------*/
289 void serial_transmit(const PicInsn *pi) {
290 const PicInsnInfo *pii;
291 int obj, v, suppress=0;
293 if ((pi->d[0] & 0xf8) == 0x90) {
297 ouprintf("picio out polarity <");
300 if (!segi->invertible) continue;
301 if (!picinsn_polarity_testbit(pi,segi)) continue;
302 ouprintf("%s%s", delim, segi->pname);
306 } else if (pi->d[0] == 0xff) {
307 if (picio_send_noise < 3)
312 picinsn_decode(pi, pic_command_infos, &pii, &obj, &v);
314 ouprintf("picio out unknown\n");
315 else if (pii->noiselevel > picio_send_noise)
318 oupicio("out",pii,obj,v,ouprintf);
321 if (!suppress && picio_send_noise >= 2)
322 ouhex("picioh out", pi->d, pi->l);
324 /* note that the serial port is still in nonblocking mode. if
325 * we ever buffer up far enough that the kernel wants to make us
326 * block, we should die! */
327 serial_transmit_now(pi->d, pi->l);
330 /*---------- reporting page faults etc. ----------*/
332 #define CHECK_RUSAGE_FIELDS(F) \
340 #define CRF_DECL(f) static long check_rusage_last_##f;
341 CHECK_RUSAGE_FIELDS(CRF_DECL)
343 static void getru(struct rusage *ru) {
344 int r= getrusage(RUSAGE_SELF, ru); if (r) diee("getrusage");
347 void check_rusage_baseline(void) {
349 ouprintf("info rusage : monitoring\n");
351 #define CRF_BASE(f) check_rusage_last_##f= ru.f;
352 CHECK_RUSAGE_FIELDS(CRF_BASE)
355 static void check_rusage_field(const char *f, long *last, long this, int alw) {
356 long diff= this - *last;
358 ouprintf(" %s+=%ld", f, diff);
363 void check_rusage_check(int always_report) {
366 #define CRF_CHANGED(f) || ru.f != check_rusage_last_##f
368 CHECK_RUSAGE_FIELDS(CRF_CHANGED)) {
369 ouprintf("info rusage :");
370 #define CRF_SHOW(f) \
371 check_rusage_field(STR(f), &check_rusage_last_##f, ru.f, always_report);
372 CHECK_RUSAGE_FIELDS(CRF_SHOW);
377 /*---------- debugging ----------*/
379 unsigned long eventcounter;
381 void debug_count_event(const char *what) {
382 DPRINTF(misc,event, "#0x%lx %s\n",eventcounter,what);
386 #define DEFDFLAGS_safety ~(DBIT_safety_predictplan|DBIT_safety_predictseg)
387 #define DEFDFLAGS_movpos ~(DBIT_movpos_eval|DBIT_movpos_intern|DBIT_movpos_meth|DBIT_movpos_fsq)
388 #define DEFDFLAGS_speed ~(DBIT_speed_query)
389 #define DEFDFLAGS_retransmit ~(DBIT_retransmit_message)
391 #define DEBUG_FLAGS_H_DEFINE
392 #include "realtime+dflags.h"
394 static int debug_simulate_exactly;
395 static int nononblock_stdin;
397 static void debug_user_set(const DebugSelectorAreaInfo *dsai,
398 int op, unsigned long bits) {
400 case '+': *dsai->dflags |= bits; break;
401 case '-': *dsai->dflags &= ~bits; break;
404 *dsai->userset |= bits;
407 static void debug_arg_spec(const char *arg) {
415 * -D<area>+<kind>[<kinds>...]
416 * -D<area>-<kind>[<kinds>...]
417 * where <kind> can be `*'
419 int wlen, l, alen, op=0;
420 const char *delim, *area;
421 const DebugSelectorAreaInfo *dsai=0;
422 const DebugSelectorKindInfo *dski;
425 if (!strcmp("=",arg)) { debug_simulate_exactly= 1; return; }
428 /* possibilities, arg points to | dsai op
432 * -D|<area>?... 0 undef
433 * -D<area>...?|<kind> <area> char `?'
434 * -D<area>...?|<kind>?... <area> 1st `?'
437 wlen= strcspn(arg,"+-");
440 if (!dsai) { /* -D|... */
441 if (!*delim) badusage("-D without any + - or =");
442 if (wlen) { /* -D|<area>?... */
445 } else { /* -D|?[<area>] */
448 if (!alen) { /* -D|? */
449 for (dsai=dsais; dsai->name; dsai++)
450 debug_user_set(dsai,*delim,~0UL);
454 /* -D|<area>?... or -D?<area> */
455 for (dsai=dsais; dsai->name; dsai++) {
456 l= strlen(dsai->name);
457 if (l==alen && !memcmp(dsai->name,area,l)) goto area_found;
459 badusage("unknown debug message area");
461 if (!wlen) { /* -D|?<area> */
462 debug_user_set(dsai,*delim,~0UL);
465 /* -D|<area>?<kind>... */
466 } else { /* -D<area>...?|<kind>[?...] */
467 if (wlen==1 && arg[0]=='*') {
471 for (dski=dsai->kinds; dski->name; dski++) {
472 l= strlen(dski->name);
473 if (l==wlen && !memcmp(dski->name,arg,l)) {
478 badusage("unknown debug message kind");
480 debug_user_set(dsai,op,bits);
481 if (!*delim) /* -D<area>...?|<kind> */
483 /* -D<area>...?|<kind>?<kind>... */
485 /* -D...?|<something>?<kind>... */
488 /* -D...?<something>?|<kind>... */
492 static void debug_setup(void) {
493 const DebugSelectorAreaInfo *dsai;
496 for (dsai=dsais; dsai->name; dsai++) {
497 def= (simulate && !debug_simulate_exactly) ? ~0UL : dsai->defdflags;
498 *dsai->dflags |= def & ~*dsai->userset;
502 /*---------- initialisation ----------*/
504 int main(int argc, const char **argv) {
505 oop_source_sys *sys_events;
509 persist_map_veryearly();
511 if (argv[0] && argv[1] && !strcmp(argv[1],PERSIST_CONVERT_OPTION))
512 /* do this before we call malloc so that MAP_FIXED is sure to work */
513 persist_entrails_run_converter();
515 while ((arg=*++argv) && *arg=='-' && arg[1]) {
517 while (arg && *arg) {
519 case 's': device= arg; arg=0; break;
520 case 'p': persist_fn= arg; arg=0; break;
521 case 'v': picio_send_noise= atoi(arg); arg=0; break;
522 case 'm': sta_state= Sta_Manual; break;
523 case 'V': simlog_full=1; break;
524 case 'B': nononblock_stdin=1; break;
525 case 'W': disable_watchdog=1; break;
526 case 'L': logcopy_fn= arg; arg=0; break;
527 case 'S': simulate= arg; arg=0; break;
528 case 'D': debug_arg_spec(arg); arg=0; break;
531 while ((c= *arg++)) {
533 case 'd': rtfeats_use |= RTFEAT_DEFAULTS; break;
534 case 'p': rtfeats_use |= RTFEAT_CPU; break;
535 case 'P': rtfeats_use |= RTFEAT_ALL(CPU); break;
536 case 'm': rtfeats_use |= RTFEAT_MEM; break;
537 case 'M': rtfeats_use |= RTFEAT_ALL(MEM); break;
538 case 'r': rtfeats_use |= RTFEAT_RUSAGE; break;
539 default: badusage("unknown -R suboption");
544 default: badusage("unknown option");
549 cmdi.out.desc= (char*)"command";
551 cmdi.out.error= obc_error;
552 cmdi.doline= command_doline;
553 cmdi.out.empty= cmdi_output_bufferempty;
558 sys_events= oop_sys_new(); if (!sys_events) diee("oop_sys_new");
559 events= oop_sys_source(sys_events); massert(events);
561 simlog_open(logcopy_fn);
563 if (nononblock_stdin) oop_fd_nonblock(0,0);
566 r= oop_fd_nonblock(serial_fd, 1); if (r) diee("nonblock(serial_fd,1)");
568 events->on_fd(events, serial_fd, OOP_READ, serial_readable, 0);
569 events->on_fd(events, serial_fd, OOP_EXCEPTION, read_exception, 0);
571 if (rtfeats_use & RTFEAT_DEFAULTS)
572 rtfeats_use |= RTFEAT_CPU | RTFEAT_MEM | RTFEAT_RUSAGE;
574 sim_initialise(logcopy_fn);
578 persist_entrails_interpret();
584 if (!simulate) oop_sys_run(sys_events);
590 DEFINE_ERRORCODELIST_DATA