doorbell
changeset 4:08ea0abdbb8a
argument parsing
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 14 Mar 2016 04:20:59 +0200 |
parents | 73b16c2ae6bf |
children | f21ae31ef0e7 |
files | doorbelld/src/main.c doorbelld/src/srv.c |
diffstat | 2 files changed, 137 insertions(+), 27 deletions(-) [+] |
line diff
1.1 --- a/doorbelld/src/main.c Sun Mar 13 07:56:26 2016 +0200 1.2 +++ b/doorbelld/src/main.c Mon Mar 14 04:20:59 2016 +0200 1.3 @@ -10,8 +10,11 @@ 1.4 void *frame_proc(void *arg); 1.5 int save_image(const char *fname, unsigned char *pixels, int xsz, int ysz); 1.6 void sighandler(int s); 1.7 +int parse_args(int argc, char **argv); 1.8 1.9 -int fd; 1.10 +const char *devfile = "/dev/video0"; 1.11 +int fd = -1; 1.12 +int port = 2828; 1.13 int width = 640; 1.14 int height = 480; 1.15 int framerate = 30; 1.16 @@ -23,18 +26,17 @@ 1.17 1.18 int main(int argc, char **argv) 1.19 { 1.20 - char *devfile = "/dev/video0"; 1.21 pthread_t thread; 1.22 1.23 - if(argv[1]) { 1.24 - devfile = argv[1]; 1.25 + if(parse_args(argc, argv) == -1) { 1.26 + return 1; 1.27 } 1.28 1.29 signal(SIGINT, sighandler); 1.30 signal(SIGQUIT, sighandler); 1.31 signal(SIGSEGV, sighandler); 1.32 1.33 - if(srv_init(2828) == -1) { 1.34 + if(srv_init(port) == -1) { 1.35 return 1; 1.36 } 1.37 1.38 @@ -42,12 +44,28 @@ 1.39 perror("failed to allocate frame"); 1.40 return 1; 1.41 } 1.42 - 1.43 - if((fd = wcam_open(devfile, width, height, framerate)) == -1) { 1.44 - fprintf(stderr, "failed to open video device: %s\n", devfile); 1.45 - return 1; 1.46 + if(devfile) { 1.47 + if((fd = wcam_open(devfile, width, height, framerate)) == -1) { 1.48 + fprintf(stderr, "failed to open video device: %s\n", devfile); 1.49 + return 1; 1.50 + } 1.51 + wcam_start(fd); 1.52 + } else { 1.53 + int i, j; 1.54 + unsigned char *pptr = frame; 1.55 + for(i=0; i<height; i++) { 1.56 + for(j=0; j<width; j++) { 1.57 + int p = (i ^ j) & 0xff; 1.58 + pptr[0] = p; 1.59 + pptr[1] = p << 1; 1.60 + pptr[2] = p << 2; 1.61 + pptr[3] = 255; 1.62 + pptr += 4; 1.63 + } 1.64 + } 1.65 + printf("serving test pattern\n"); 1.66 + save_image("output.ppm", frame, width, height); 1.67 } 1.68 - wcam_start(fd); 1.69 1.70 if(pthread_create(&thread, 0, frame_proc, 0) == -1) { 1.71 fprintf(stderr, "failed to create frame processing thread\n"); 1.72 @@ -61,22 +79,29 @@ 1.73 int maxfd = srv_max_socket(); 1.74 fd_set rdset; 1.75 1.76 - if(fd > maxfd) maxfd = fd; 1.77 + FD_ZERO(&rdset); 1.78 1.79 - FD_ZERO(&rdset); 1.80 - FD_SET(fd, &rdset); 1.81 + if(fd != -1) { 1.82 + if(fd > maxfd) maxfd = fd; 1.83 + FD_SET(fd, &rdset); 1.84 + printf("select on socket: %d (video)\n", fd); 1.85 + } 1.86 1.87 for(i=0; i<num_sockets; i++) { 1.88 FD_SET(sock[i], &rdset); 1.89 + printf("select on socket: %d\n", sock[i]); 1.90 } 1.91 1.92 - while((res = select(maxfd + 1, &rdset, 0, 0, 0)) == -1 && errno == EINTR); 1.93 + while((res = select(maxfd + 1, &rdset, 0, 0, 0)) == -1 && 1.94 + errno == EINTR && !done); 1.95 + if(done) break; 1.96 if(res == -1) { 1.97 fprintf(stderr, "unexpected failure while waiting for I/O\n"); 1.98 break; 1.99 } 1.100 + printf("res: %d\n", res); 1.101 1.102 - if(FD_ISSET(fd, &rdset)) { 1.103 + if(fd != -1 && FD_ISSET(fd, &rdset)) { 1.104 wcam_wait(fd); 1.105 pthread_mutex_lock(&mutex); 1.106 frame_available = 1; 1.107 @@ -95,8 +120,10 @@ 1.108 pthread_cond_signal(&condvar); 1.109 pthread_join(thread, 0); 1.110 free(frame); 1.111 - wcam_stop(fd); 1.112 - wcam_close(fd); 1.113 + if(fd != -1) { 1.114 + wcam_stop(fd); 1.115 + wcam_close(fd); 1.116 + } 1.117 return 0; 1.118 } 1.119 1.120 @@ -112,8 +139,10 @@ 1.121 1.122 if(done) break; 1.123 1.124 - wcam_read_frame_rgb(fd, frame); 1.125 - save_image("output.ppm", frame, width, height); 1.126 + if(fd != -1) { 1.127 + wcam_read_frame_rgb(fd, frame); 1.128 + save_image("output.ppm", frame, width, height); 1.129 + } 1.130 } 1.131 return 0; 1.132 } 1.133 @@ -139,3 +168,57 @@ 1.134 { 1.135 done = 1; 1.136 } 1.137 + 1.138 +void print_usage(const char *argv0) 1.139 +{ 1.140 + printf("Usage: %s [options]\n", argv0); 1.141 + printf("options:\n"); 1.142 + printf(" -s,-size <WxH>\n"); 1.143 + printf(" -f,-fps <framerate>\n"); 1.144 + printf(" -d,-device <devfile>\n"); 1.145 + printf(" -p,-port <port>\n"); 1.146 + printf(" -novideo\n"); 1.147 + printf(" -h,-help\n"); 1.148 +} 1.149 + 1.150 +int parse_args(int argc, char **argv) 1.151 +{ 1.152 + int i; 1.153 + 1.154 + for(i=1; i<argc; i++) { 1.155 + if(argv[i][0] == '-') { 1.156 + if(strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "-size") == 0) { 1.157 + if(sscanf(argv[++i], "%dx%d", &width, &height) != 2) { 1.158 + fprintf(stderr, "invalid size specified: %s\n", argv[i - 1]); 1.159 + return -1; 1.160 + } 1.161 + } else if(strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "-fps") == 0) { 1.162 + framerate = atoi(argv[++i]); 1.163 + if(framerate <= 0) { 1.164 + fprintf(stderr, "invalid framerate specified: %s\n", argv[i - 1]); 1.165 + return -1; 1.166 + } 1.167 + } else if(strcmp(argv[i], "-novideo") == 0) { 1.168 + devfile = 0; 1.169 + } else if(strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "-device") == 0) { 1.170 + devfile = argv[++i]; 1.171 + } else if(strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "-port") == 0) { 1.172 + port = atoi(argv[++i]); 1.173 + if(port <= 0 || port >= 65535) { 1.174 + fprintf(stderr, "invalid port specified: %s\n", argv[i - 1]); 1.175 + return -1; 1.176 + } 1.177 + } else { 1.178 + int help = strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help") == 0; 1.179 + if(!help) fprintf(stderr, "unrecognized option: %s\n", argv[i]); 1.180 + print_usage(argv[0]); 1.181 + exit(help ? 0 : 1); 1.182 + } 1.183 + } else { 1.184 + fprintf(stderr, "unexpected argument: %s\n", argv[i]); 1.185 + print_usage(argv[0]); 1.186 + return -1; 1.187 + } 1.188 + } 1.189 + return 0; 1.190 +}
2.1 --- a/doorbelld/src/srv.c Sun Mar 13 07:56:26 2016 +0200 2.2 +++ b/doorbelld/src/srv.c Mon Mar 14 04:20:59 2016 +0200 2.3 @@ -10,6 +10,8 @@ 2.4 #include "srv.h" 2.5 #include "dynarr.h" 2.6 2.7 +/* TODO convert this whole thing to multicast */ 2.8 + 2.9 static int lis_sock = -1, max_socket = -1; 2.10 static int *csock; 2.11 2.12 @@ -45,6 +47,7 @@ 2.13 lis_sock = -1; 2.14 return -1; 2.15 } 2.16 + listen(lis_sock, 8); 2.17 2.18 return 0; 2.19 } 2.20 @@ -84,16 +87,19 @@ 2.21 if(s == lis_sock) { 2.22 /* incoming connection */ 2.23 struct sockaddr_in addr; 2.24 - int addr_size; 2.25 - 2.26 - if((s = accept(lis_sock, (struct sockaddr*)&addr, (int*)&addr_size)) == -1) { 2.27 - fprintf(stderr, "%s: failed to accept incoming connection\n", __func__); 2.28 + socklen_t addr_size = sizeof addr; 2.29 + if((s = accept(lis_sock, (struct sockaddr*)&addr, &addr_size)) == -1) { 2.30 + fprintf(stderr, "%s: failed to accept incoming connection: %s\n", __func__, strerror(errno)); 2.31 return -1; 2.32 } 2.33 printf("%s: incoming connection from %s:%d\n", __func__, 2.34 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); 2.35 csock = dynarr_push(csock, &s); 2.36 assert(csock); 2.37 + if(s > max_socket) { 2.38 + max_socket = s; 2.39 + } 2.40 + fcntl(s, F_SETFD, fcntl(s, F_GETFD) | O_NONBLOCK); 2.41 return 0; 2.42 } 2.43 2.44 @@ -101,23 +107,44 @@ 2.45 while((sz = read(s, buf, sizeof buf - 1)) > 0) { 2.46 printf("%s: got data: %s\n", __func__, buf); 2.47 } 2.48 - if(sz < 0 && errno != EAGAIN) { 2.49 + if(sz <= 0 && errno != EAGAIN) { 2.50 /* client closed connection probably */ 2.51 int i, num_clients = dynarr_size(csock); 2.52 printf("%s: removing client\n", __func__); 2.53 close(s); 2.54 + max_socket = lis_sock; 2.55 for(i=0; i<num_clients; i++) { 2.56 if(csock[i] == s) { 2.57 csock[i] = csock[num_clients - 1]; 2.58 - csock = dynarr_pop(csock); 2.59 - break; 2.60 + } 2.61 + if(csock[i] > max_socket) { 2.62 + max_socket = csock[i]; 2.63 } 2.64 } 2.65 - assert(i < num_clients); 2.66 + 2.67 + csock = dynarr_pop(csock); 2.68 + --num_clients; 2.69 } 2.70 return 0; 2.71 } 2.72 2.73 +struct video_block { 2.74 + int frame; 2.75 + int x, y; 2.76 + int width, height; 2.77 + char pixels[1]; 2.78 +}; 2.79 +#define VBLOCK_HEADER_SIZE (offsetof(struct video_block, pixels)) 2.80 + 2.81 void srv_send_frame(unsigned char *frame, int xsz, int ysz) 2.82 { 2.83 + static unsigned char *buffer; 2.84 + struct video_block *vblock; 2.85 + 2.86 + /* for now just send a big block */ 2.87 + if(!buffer && !(buffer = malloc(xsz * ysz * 2) + VBLOCK_HEADER_SIZE)) { 2.88 + fprintf(stderr, "failed to allocate frame send buffer\n"); 2.89 + return; 2.90 + } 2.91 + vblock = buffer; 2.92 }