initial commit, eq circuit emulator
[eqemu] / src / dev.cc
1 /*
2 eqemu - electronic queue system emulator
3 Copyright (C) 2014  John Tsiombikas <nuclear@member.fsf.org>,
4                     Eleni-Maria Stea <eleni@mutantstargoat.com>
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include <stdio.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <signal.h>
23 #include <limits.h>
24 #include <string>
25 #include <unistd.h>
26 #include <sys/stat.h>
27 #include <sys/wait.h>
28 #include <fcntl.h>
29 #include <termios.h>
30 #include "dev.h"
31 #include "timer.h"
32
33 void post_redisplay();  // defined in main.cc
34
35 int customer, ticket;
36 static int report_inputs, cmd_echo;
37 static long last_ticket_msec = LONG_MIN;
38
39 static void runcmd(const char *cmd);
40
41 static int fd = -1;
42 static FILE *fp;
43 static std::string cur_line;
44
45 int start_dev(const char *devpath)
46 {
47         if((fd = open(devpath, O_RDWR | O_NONBLOCK)) == -1) {
48                 fprintf(stderr, "failed to open device: %s: %s\n", devpath, strerror(errno));
49                 return -1;
50         }
51         if(isatty(fd)) {
52                 struct termios term;
53
54                 if(tcgetattr(fd, &term) == -1) {
55                         perror("failed to retrieve terminal attributes");
56                         stop_dev();
57                         return -1;
58                 }
59                 term.c_cflag = CS8 | CLOCAL;
60                 term.c_iflag &= ~(IXON | IXOFF);
61                 term.c_lflag = 0;
62
63                 cfsetispeed(&term, B38400);
64                 cfsetospeed(&term, B38400);
65
66                 if(tcsetattr(fd, TCSANOW, &term) == -1) {
67                         perror("failed to set terminal attributes");
68                         stop_dev();
69                         return -1;
70                 }
71         }
72
73         if(!(fp = fdopen(fd, "r+"))) {
74                 perror("failed to attach an I/O stream to the device file\n");
75                 stop_dev();
76                 return -1;
77         }
78         setvbuf(fp, 0, _IONBF, 0);
79
80         return fd;
81 }
82
83 void stop_dev()
84 {
85         if(fp)
86                 fclose(fp);
87         else if(fd >= 0)
88                 close(fd);
89 }
90
91
92 void proc_dev_input()
93 {
94         int rdbytes;
95         char buf[256];
96         static bool skip_line;
97
98         while((rdbytes = read(fd, buf, sizeof buf - 1)) > 0) {
99                 buf[rdbytes] = 0;
100
101                 /* ignore our own crap */
102                 if(memcmp(buf, "OK,", 3) == 0 || memcmp(buf, "ERR,", 4) == 0) {
103                         skip_line = true;
104                 }
105
106                 for(int i=0; i<rdbytes; i++) {
107                         if(buf[i] == '\n' || buf[i] == '\r') {
108                                 if(!cur_line.empty()) {
109                                         runcmd(cur_line.c_str());
110                                         cur_line.clear();
111                                 }
112                                 skip_line = false;
113                         } else {
114                                 if(!skip_line) {
115                                         cur_line.push_back(buf[i]);
116                                 }
117                         }
118                 }
119         }
120 }
121
122 void issue_ticket()
123 {
124         ticket++;
125         last_ticket_msec = get_msec();
126         if(report_inputs) {
127                 fprintf(fp, "ticket: %d\n", ticket);
128         }
129
130         post_redisplay();
131 }
132
133 void next_customer()
134 {
135         if(customer < ticket) {
136                 customer++;
137                 last_ticket_msec = LONG_MIN;
138                 if(report_inputs) {
139                         fprintf(fp, "customer: %d\n", customer);
140                 }
141
142                 post_redisplay();
143         }
144 }
145
146 #define TICKET_SHOW_DUR         1000
147
148 int get_display_number()
149 {
150         if(get_msec() - last_ticket_msec < TICKET_SHOW_DUR) {
151                 return ticket;
152         }
153         return customer;
154 }
155
156 int get_led_state(int led)
157 {
158         int ledon = get_msec() - last_ticket_msec < TICKET_SHOW_DUR ? 0 : 1;
159         return led == ledon ? 1 : 0;
160 }
161
162 #define VERSTR \
163         "Queue system emulator v0.1"
164
165 static void runcmd(const char *cmd)
166 {
167         printf("DBG: runcmd(\"%s\")\n", cmd);
168
169         switch(cmd[0]) {
170         case 'e':
171                 cmd_echo = !cmd_echo;
172                 fprintf(fp, "OK,turning echo %s\n", cmd_echo ? "on" : "off");
173                 break;
174
175         case 'i':
176                 report_inputs = !report_inputs;
177                 fprintf(fp, "OK,turning input reports %s\n", report_inputs ? "on" : "off");
178                 break;
179
180         case 'v':
181                 fprintf(fp, "OK,%s\n", VERSTR);
182                 break;
183
184         case 'r':
185                 fprintf(fp, "OK,reseting queues\n");
186                 customer = 0;
187                 ticket = 0;
188                 last_ticket_msec = LONG_MIN;
189                 post_redisplay();
190                 break;
191
192         case 't':
193                 fprintf(fp, "OK,ticket: %d\r\n", ticket);
194                 break;
195
196         case 'c':
197                 fprintf(fp, "OK,customer: %d\r\n", customer);
198                 break;
199
200         case 'q':
201                 fprintf(fp, "OK,issuing queue ticket\n");
202                 issue_ticket();
203                 break;
204
205         case 'n':
206                 fprintf(fp, "OK,next customer\n");
207                 next_customer();
208                 break;
209
210         case 'h':
211                 fprintf(fp, "OK,commands: (e)cho, (v)ersion, (t)icket, (c)ustomer, "
212                                 "(n)ext, (q)ueue, (r)eset, (i)nput-reports, (h)elp.\n");
213                 break;
214
215         default:
216                 fprintf(fp, "ERR,unknown command: %s\n", cmd);
217         }
218 }