This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <poll.h> | |
| #include <fcntl.h> | |
| #include <sys/types.h> | |
| #include <sys/socket.h> | |
| #include <netdb.h> | |
| static void failp(char *s){ | |
| perror(s); | |
| exit(EXIT_FAILURE); | |
| } | |
| static void writestr(int fd, char *s){ | |
| size_t sz = strlen(s); | |
| if(write(fd, s, sz) != sz) | |
| failp("write"); | |
| } | |
| struct pollstate { | |
| int nfds; | |
| }; | |
| struct proc { | |
| struct self *self; | |
| struct pollstate (*poll_pre)(struct self *, long long time, struct pollfd *fds, int sz); | |
| void (*poll_post)(struct self *, long long time); | |
| }; | |
| struct s_watchkey { | |
| int fd; | |
| int ispressed; | |
| struct pollfd *pollfd; | |
| }; | |
| static struct s_watchkey watchkey(char *fn){ | |
| int fd = open(fn, O_RDONLY); | |
| if(fd < 0) | |
| failp("open"); | |
| return (struct s_watchkey){ fd }; | |
| } | |
| static struct pollstate watchkey_poll_pre(struct s_watchkey *s, long long time, struct pollfd *fds, int sz){ | |
| if(sz < 1){ | |
| fprintf(stderr, "sz < 1"); | |
| exit(EXIT_FAILURE); | |
| } | |
| *fds = (struct pollfd){ | |
| .fd = s->fd, | |
| .events = POLLPRI | |
| }; | |
| s->pollfd = fds; | |
| return (struct pollstate){ 1 }; | |
| } | |
| static void watchkey_poll_post(struct s_watchkey *s, long long time){ | |
| if(!(s->pollfd->revents & POLLPRI)) | |
| return; | |
| if(lseek(s->fd, 0, SEEK_SET)) | |
| failp("lseek"); | |
| char rb = 0; | |
| if(read(s->fd, &rb, 1) < 0) | |
| failp("read"); | |
| s->ispressed = rb == 'a'; | |
| } | |
| struct s_watchmpd { | |
| int fd; | |
| int linelen; | |
| struct pollfd *pollfd; | |
| char linebuf[128]; | |
| unsigned int playing:1, got_state:1, idle:1; | |
| int queue; | |
| }; | |
| static struct s_watchmpd watchmpd(void){ | |
| int fd = socket(AF_INET, SOCK_STREAM, 0); | |
| if(fd < 0) | |
| failp("socket"); | |
| struct addrinfo *addr; | |
| if(getaddrinfo("127.1", "6600", NULL, &addr)) | |
| failp("getaddrinfo"); | |
| if(connect(fd, addr->ai_addr, addr->ai_addrlen)) | |
| failp("connect"); | |
| return (struct s_watchmpd){ fd, .queue = 1 }; | |
| } | |
| static struct pollstate watchmpd_poll_pre(struct s_watchmpd *s, long long time, struct pollfd *fds, int sz){ | |
| if(sz < 1){ | |
| fprintf(stderr, "sz < 1"); | |
| exit(EXIT_FAILURE); | |
| } | |
| *fds = (struct pollfd){ | |
| .fd = s->fd, | |
| .events = POLLIN | |
| }; | |
| s->pollfd = fds; | |
| return (struct pollstate){ 1 }; | |
| } | |
| static void watchmpd_line(struct s_watchmpd *s){ | |
| static char ok_pre[] = "OK"; | |
| if(!strncmp(s->linebuf, ok_pre, sizeof ok_pre - 1) && (!s->linebuf[sizeof ok_pre - 1] || s->linebuf[sizeof ok_pre - 1] == ' ')){ | |
| if(--s->queue > 0) | |
| return; | |
| s->idle = 0; | |
| if(!s->got_state){ | |
| s->queue++; | |
| writestr(s->fd, "status\n"); | |
| }else{ | |
| s->got_state = 0; | |
| s->idle = 1; | |
| s->queue++; | |
| writestr(s->fd, "idle player\n"); | |
| } | |
| } | |
| static char state_pre[] = "state: "; | |
| if(!strncmp(s->linebuf, state_pre, sizeof state_pre - 1)){ | |
| s->playing = !strcmp(s->linebuf + (sizeof state_pre - 1), "play"); | |
| s->got_state = 1; | |
| } | |
| } | |
| static void watchmpd_poll_post(struct s_watchmpd *s, long long time){ | |
| if(!(s->pollfd->revents & POLLIN)) | |
| return; | |
| char buf[1024]; | |
| int rs = read(s->fd, &buf, sizeof buf); | |
| if(rs == 0){ | |
| close(s->fd); | |
| sleep(1); | |
| *s = watchmpd(); | |
| return; | |
| } | |
| if(rs < 0) | |
| failp("read"); | |
| for(int x = 0; x < rs; x++){ | |
| int c = buf[x]; | |
| if(c == '\n') | |
| c = 0; | |
| if(s->linelen < sizeof s->linebuf - 1) | |
| s->linebuf[s->linelen++] = c; | |
| if(c == 0){ | |
| watchmpd_line(s); | |
| s->linelen = 0; | |
| } | |
| } | |
| } | |
| int main(void){ | |
| struct s_watchkey s_watchkey = watchkey("/sys/devices/platform/gpio-switch/cam_launch/state"); | |
| struct s_watchmpd s_watchmpd = watchmpd(); | |
| struct pollfd pollfds[10]; | |
| struct proc procs[] = { | |
| { &s_watchkey, watchkey_poll_pre, watchkey_poll_post }, | |
| { &s_watchmpd, watchmpd_poll_pre, watchmpd_poll_post } | |
| }; | |
| long long time; | |
| for(;;){ | |
| int waspressed = s_watchkey.ispressed; | |
| int nfds = 0; | |
| int timer = -1; | |
| for(int x = 0; x < sizeof procs/sizeof *procs; x++){ | |
| struct pollstate ps = procs[x].poll_pre(procs[x].self, 0, pollfds + nfds, sizeof pollfds/sizeof *pollfds - nfds).nfds; | |
| nfds += ps.nfds; | |
| if(ps.timer >= 0 && (timer < 0 || timer > ps.timer)) | |
| timer = ps.timer; | |
| } | |
| int pollr = poll(pollfds, nfds, timer); | |
| if(pollr < 0) | |
| failp("poll"); | |
| else if(pollr == 0) | |
| time += timer; | |
| for(int x = 0; x < sizeof procs/sizeof *procs; x++) | |
| procs[x].poll_post(procs[x].self, 0); | |
| if(s_watchmpd.playing && !waspressed && s_watchkey.ispressed){ | |
| if(s_watchmpd.idle){ | |
| s_watchmpd.idle = 0; | |
| writestr(s_watchmpd.fd, "noidle\n"); | |
| } | |
| s_watchmpd.queue++; | |
| writestr(s_watchmpd.fd, "next\n"); | |
| } | |
| } | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment