chiark / gitweb /
wip
[trains.git] / hostside / realtime.c
1 /*
2  * main program for realtime control
3  */
4
5 #include "realtime.h"
6
7 const char *progname= "realtime";
8
9 /*---------- global variables ----------*/
10
11 CommandInput cmdi;
12
13 static const char *device;
14
15 /*---------- general event handling ----------*/
16
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:"");
21 }
22
23 static void *read_exception(oop_source *evts, int fd,
24                             oop_event evt, void *cl_v) {
25   const char *ch;
26   char bufc;
27   int r;
28
29   ch= (fd==UPO->fd ? UPO->desc :
30        fd==serial_fd ? "serial port" :
31        0);
32   
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);
37
38   return OOP_CONTINUE;
39 }
40
41 /*---------- command channel handling (oop_read, obc) ----------*/
42
43 static void command_doline(ParseState *ps, CommandInput *cmdi) {
44   const CmdInfo *ci;
45   ci= some_needword_lookup(ps, toplevel_cmds, "command");
46   if (ci) ci->fn(ps,ci);
47 }
48
49 void oupicio(const char *dirn, const PicInsnInfo *pii, int objnum) {
50   if (!pii->argbits)
51     oprintf(UPO, "picio %s %s\n", dirn, pii->name);
52   else
53     oprintf(UPO, "picio %s %s %u\n", dirn, pii->name, objnum);
54 }
55
56 void vbadcmd(ParseState *ps, const char *fmt, va_list al) {
57   voerror(UPO,fmt,al);
58 }
59
60 static void obc_error(OutBufferChain *ch, const char *e1, const char *e2) {
61   comms_error(ch->desc, e1, e2);
62 }
63
64 void ouhex(const char *word, const Byte *command, int length) {
65   oprintf(UPO, "%s", word);
66   while (length) {
67     oprintf(UPO, " %02x", *command++);
68     length--;
69   }
70   oprintf(UPO, "\n");
71 }
72
73 void die_hook() {
74   int e;
75   e= obc_tryflush(UPO);
76   if (e) fprintf(stderr,"(unwritten command output: %s)\n",strerror(e));
77 }
78
79 /*---------- serial input (via oop) ----------*/
80
81 static PicInsn serial_buf;
82
83 static void *serial_readable(oop_source *evts, int fd,
84                              oop_event evt, void *u0) {
85   int r, buf_used;
86
87   r= read(serial_fd, &serial_buf.d, sizeof(serial_buf.d) - serial_buf.l);
88   if (r==0) die("serial port - eof");
89   if (r==-1) {
90     if (errno == EWOULDBLOCK || errno == EINTR)
91       return OOP_CONTINUE;
92     diee("serial port - read error");
93   }
94   assert(r>0);
95
96   buf_used= serial_buf.l;
97   buf_used += r;
98
99   for (;;) {
100     serial_buf.l= buf_used;
101     serial_moredata(&serial_buf);
102     if (!serial_buf.l) break;
103     buf_used -= serial_buf.l;
104     memmove(serial_buf.d, serial_buf.d + serial_buf.l, buf_used);
105     if (!buf_used) break;
106   }
107   serial_buf.l= buf_used;
108   return OOP_CONTINUE;
109 }
110
111 /*---------- serial port output (not via liboop) ----------*/
112
113 void serial_transmit(const PicInsn *pi) {
114   const PicInsnInfo *pii;
115   int objnum;
116
117   fixme decode polarity
118   picinsn_decode(pi, pic_command_infos, &pii, &objnum);
119
120   if (!pii)
121     oprintf(UPO, "picio out unknown\n");
122   else
123     oupicio("out",pii,objnum);
124
125   ouhex("picioh out", pi->d, pi->l);
126
127   /* note that the serial port is still in nonblocking mode.  if
128    * we ever buffer up far enough that the kernel wants to make us
129    * block, we should die! */
130   serial_transmit_now(pi->d, pi->l);
131 }
132
133 /*---------- initialisation ----------*/
134
135 int main(int argc, const char **argv) {
136   oop_source_sys *sys_events;
137   int r;
138
139   device= argv[1];
140   if (!device) device= "/dev/ttya0";
141
142   sys_events= oop_sys_new();  if (!sys_events) diee("oop_sys_new");
143   events= oop_sys_source(sys_events);  massert(events);
144
145   cmdi.out.desc= (char*)"command";
146   cmdi.out.fd= 1;
147   cmdi.out.error= obc_error;
148   cmdi.doline= command_doline;
149
150   cmdin_new(&cmdi, 0);
151
152   serial_open(device);
153   r= oop_fd_nonblock(serial_fd, 1);  if (r) diee("nonblock(serial_fd,1)");
154
155   events->on_fd(events, serial_fd, OOP_READ, serial_readable, 0);
156   events->on_fd(events, serial_fd, OOP_EXCEPTION, read_exception, 0);
157
158   sta_startup();
159   oop_sys_run(sys_events);
160   abort();
161 }