2 * main program for realtime control
7 const char *progname= "realtime";
9 /*---------- global variables ----------*/
13 static const char *device= "/dev/ttya0";
15 /*---------- general event handling ----------*/
17 static void comms_error(const char *ch, const char *e1,
18 const char *e2 /* may be 0 */) {
19 if (!e1 && !e2) e1= "end of file";
20 die("communications error: %s: %s%s%s", ch, e1, e2?": ":"", e2?e2:"");
23 static void *read_exception(oop_source *evts, int fd,
24 oop_event evt, void *cl_v) {
29 ch= (fd==UPO->fd ? UPO->desc :
30 fd==serial_fd ? "serial port" :
33 r= read(fd, &bufc, 1);
34 if (r==-1) comms_error(ch, "read error", strerror(errno));
35 else if (r==0) comms_error(ch, "reports exception, reads EOF", 0);
36 else comms_error(ch, "reports exception, but readable", 0);
41 /*---------- logging etc. ----------*/
43 static char *transegn2suffixstring(Train *tra, Segment *seg) {
44 /* Either arg may be 0, in which case it's not included.
45 * Result string will be empty, or start with ": "
46 * Result string is from malloc.
49 const char *trapn, *segpn;
53 segpn= seg ? seg->i->pname : 0;
54 trapn= tra ? tra->pname : 0;
56 r= asprintf(&s, "%s%s%s%s%s",
57 segpn||trapn ? ":" : "",
62 if (r<0) diee("vasprintf failed in transegn2suffixstring");
66 void vlogmsg(ErrorCode ec, Train *tra, const SegmentInfo *segi,
67 const char *fmt, va_list al) {
68 oprintf(UPO, "message %s ", ec ? errorcodelist[ec] : "info");
70 if (segi || tra) oprintf(UPO, ":");
71 if (segi) oprintf(UPO, " @%s", segi->pname);
72 if (tra) oprintf(UPO, " %s", tra->pname);
76 void logmsg(ErrorCode ec, Train *tra, const SegmentInfo *segi,
77 const char *fmt,...) {
80 vlogmsg(ec,tra,segi,fmt,al);
84 void safety_vpanic(Train *tra, Segment *seg,const char *fmt,va_list al) {
89 serial_transmit(&piob);
91 if (vasprintf(&msg,fmt,al) < 0)
92 diee("vasprintf failed in safety_vpanic fmt=\"%s\"", fmt);
94 where= transegn2suffixstring(tra,seg);
95 die("fatal safety problem: %s%s", msg, where);
98 void safety_panic(Train *tra, Segment *seg, const char *fmt, ...) {
101 safety_panic(tra, seg, fmt, al);
104 ErrorCode safety_problem(Train *tra, Segment *seg, const char *fmt,...) {
107 vlogmsg(EC_Safety, tra, seg?seg->i:0, fmt, al);
112 /*---------- command channel handling (oop_read, obc) ----------*/
114 static void command_doline(ParseState *ps, CommandInput *cmdi) {
116 ci= some_needword_lookup(ps, toplevel_cmds, "command");
117 if (ci) ci->fn(ps,ci);
120 void oupicio(const char *dirn, const PicInsnInfo *pii, int objnum) {
122 oprintf(UPO, "picio %s %s\n", dirn, pii->name);
124 oprintf(UPO, "picio %s %s %u\n", dirn, pii->name, objnum);
127 void vbadcmd(ParseState *ps, const char *fmt, va_list al) {
131 static void obc_error(OutBufferChain *ch, const char *e1, const char *e2) {
132 comms_error(ch->desc, e1, e2);
135 void ouhex(const char *word, const Byte *command, int length) {
136 oprintf(UPO, "%s", word);
138 oprintf(UPO, " %02x", *command++);
144 void die_vprintf_hook(const char *fmt, va_list al) {
145 ovprintf(UPO, fmt, al);
148 void die_hook(void) {
150 e= obc_tryflush(UPO);
151 if (e) fprintf(stderr,"(unwritten command output: %s)\n",strerror(e));
154 /*---------- serial input (via oop) ----------*/
156 static PicInsn serial_buf;
158 static void *serial_readable(oop_source *evts, int fd,
159 oop_event evt, void *u0) {
162 r= read(serial_fd, &serial_buf.d, sizeof(serial_buf.d) - serial_buf.l);
163 if (r==0) die("serial port - eof");
165 if (errno == EWOULDBLOCK || errno == EINTR)
167 diee("serial port - read error");
171 buf_used= serial_buf.l;
175 serial_buf.l= buf_used;
176 serial_moredata(&serial_buf);
177 if (!serial_buf.l) break;
178 buf_used -= serial_buf.l;
179 memmove(serial_buf.d, serial_buf.d + serial_buf.l, buf_used);
180 if (!buf_used) break;
182 serial_buf.l= buf_used;
186 /*---------- serial port output (not via liboop) ----------*/
188 void serial_transmit(const PicInsn *pi) {
189 const PicInsnInfo *pii;
192 if ((pi->d[0] & 0xf8) == 0x90) {
194 const SegmentInfo *segi;
197 oprintf(UPO,"picio out polarity <");
198 for (segn=0, segi=info_segments, delim="";
199 segn < info_nsegments;
201 if (!segi->invertible) continue;
202 if (!picinsn_polarity_testbit(pi,segi)) continue;
203 oprintf(UPO,"%s%s", delim, segi->pname);
208 picinsn_decode(pi, pic_command_infos, &pii, &objnum);
210 oprintf(UPO, "picio out unknown\n");
212 oupicio("out",pii,objnum);
215 ouhex("picioh out", pi->d, pi->l);
217 /* note that the serial port is still in nonblocking mode. if
218 * we ever buffer up far enough that the kernel wants to make us
219 * block, we should die! */
220 serial_transmit_now(pi->d, pi->l);
223 /*---------- initialisation ----------*/
225 int main(int argc, const char **argv) {
226 oop_source_sys *sys_events;
230 while ((arg=*++argv) && *arg=='-') {
233 case 's': device= arg; break;
234 default: badusage("unknown option");
240 sys_events= oop_sys_new(); if (!sys_events) diee("oop_sys_new");
241 events= oop_sys_source(sys_events); massert(events);
243 cmdi.out.desc= (char*)"command";
245 cmdi.out.error= obc_error;
246 cmdi.doline= command_doline;
251 r= oop_fd_nonblock(serial_fd, 1); if (r) diee("nonblock(serial_fd,1)");
253 events->on_fd(events, serial_fd, OOP_READ, serial_readable, 0);
254 events->on_fd(events, serial_fd, OOP_EXCEPTION, read_exception, 0);
257 oop_sys_run(sys_events);
261 DEFINE_ERRORCODELIST_DATA