# HG changeset patch
# User John Tsiombikas <nuclear@member.fsf.org>
# Date 1457922059 -7200
# Node ID 08ea0abdbb8aadaf4626cfb4f08ed9b2ee515caa
# Parent  73b16c2ae6bf9e7b071a5a1d23f880174e90f8d8
argument parsing

diff -r 73b16c2ae6bf -r 08ea0abdbb8a doorbelld/src/main.c
--- a/doorbelld/src/main.c	Sun Mar 13 07:56:26 2016 +0200
+++ b/doorbelld/src/main.c	Mon Mar 14 04:20:59 2016 +0200
@@ -10,8 +10,11 @@
 void *frame_proc(void *arg);
 int save_image(const char *fname, unsigned char *pixels, int xsz, int ysz);
 void sighandler(int s);
+int parse_args(int argc, char **argv);
 
-int fd;
+const char *devfile = "/dev/video0";
+int fd = -1;
+int port = 2828;
 int width = 640;
 int height = 480;
 int framerate = 30;
@@ -23,18 +26,17 @@
 
 int main(int argc, char **argv)
 {
-	char *devfile = "/dev/video0";
 	pthread_t thread;
 
-	if(argv[1]) {
-		devfile = argv[1];
+	if(parse_args(argc, argv) == -1) {
+		return 1;
 	}
 
 	signal(SIGINT, sighandler);
 	signal(SIGQUIT, sighandler);
 	signal(SIGSEGV, sighandler);
 
-	if(srv_init(2828) == -1) {
+	if(srv_init(port) == -1) {
 		return 1;
 	}
 
@@ -42,12 +44,28 @@
 		perror("failed to allocate frame");
 		return 1;
 	}
-
-	if((fd = wcam_open(devfile, width, height, framerate)) == -1) {
-		fprintf(stderr, "failed to open video device: %s\n", devfile);
-		return 1;
+	if(devfile) {
+		if((fd = wcam_open(devfile, width, height, framerate)) == -1) {
+			fprintf(stderr, "failed to open video device: %s\n", devfile);
+			return 1;
+		}
+		wcam_start(fd);
+	} else {
+		int i, j;
+		unsigned char *pptr = frame;
+		for(i=0; i<height; i++) {
+			for(j=0; j<width; j++) {
+				int p = (i ^ j) & 0xff;
+				pptr[0] = p;
+				pptr[1] = p << 1;
+				pptr[2] = p << 2;
+				pptr[3] = 255;
+				pptr += 4;
+			}
+		}
+		printf("serving test pattern\n");
+		save_image("output.ppm", frame, width, height);
 	}
-	wcam_start(fd);
 
 	if(pthread_create(&thread, 0, frame_proc, 0) == -1) {
 		fprintf(stderr, "failed to create frame processing thread\n");
@@ -61,22 +79,29 @@
 		int maxfd = srv_max_socket();
 		fd_set rdset;
 
-		if(fd > maxfd) maxfd = fd;
+		FD_ZERO(&rdset);
 
-		FD_ZERO(&rdset);
-		FD_SET(fd, &rdset);
+		if(fd != -1) {
+			if(fd > maxfd) maxfd = fd;
+			FD_SET(fd, &rdset);
+			printf("select on socket: %d (video)\n", fd);
+		}
 
 		for(i=0; i<num_sockets; i++) {
 			FD_SET(sock[i], &rdset);
+			printf("select on socket: %d\n", sock[i]);
 		}
 
-		while((res = select(maxfd + 1, &rdset, 0, 0, 0)) == -1 && errno == EINTR);
+		while((res = select(maxfd + 1, &rdset, 0, 0, 0)) == -1 &&
+				errno == EINTR && !done);
+		if(done) break;
 		if(res == -1) {
 			fprintf(stderr, "unexpected failure while waiting for I/O\n");
 			break;
 		}
+		printf("res: %d\n", res);
 
-		if(FD_ISSET(fd, &rdset)) {
+		if(fd != -1 && FD_ISSET(fd, &rdset)) {
 			wcam_wait(fd);
 			pthread_mutex_lock(&mutex);
 			frame_available = 1;
@@ -95,8 +120,10 @@
 	pthread_cond_signal(&condvar);
 	pthread_join(thread, 0);
 	free(frame);
-	wcam_stop(fd);
-	wcam_close(fd);
+	if(fd != -1) {
+		wcam_stop(fd);
+		wcam_close(fd);
+	}
 	return 0;
 }
 
@@ -112,8 +139,10 @@
 
 		if(done) break;
 
-		wcam_read_frame_rgb(fd, frame);
-		save_image("output.ppm", frame, width, height);
+		if(fd != -1) {
+			wcam_read_frame_rgb(fd, frame);
+			save_image("output.ppm", frame, width, height);
+		}
 	}
 	return 0;
 }
@@ -139,3 +168,57 @@
 {
 	done = 1;
 }
+
+void print_usage(const char *argv0)
+{
+	printf("Usage: %s [options]\n", argv0);
+	printf("options:\n");
+	printf(" -s,-size <WxH>\n");
+	printf(" -f,-fps <framerate>\n");
+	printf(" -d,-device <devfile>\n");
+	printf(" -p,-port <port>\n");
+	printf(" -novideo\n");
+	printf(" -h,-help\n");
+}
+
+int parse_args(int argc, char **argv)
+{
+	int i;
+
+	for(i=1; i<argc; i++) {
+		if(argv[i][0] == '-') {
+			if(strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "-size") == 0) {
+				if(sscanf(argv[++i], "%dx%d", &width, &height) != 2) {
+					fprintf(stderr, "invalid size specified: %s\n", argv[i - 1]);
+					return -1;
+				}
+			} else if(strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "-fps") == 0) {
+				framerate = atoi(argv[++i]);
+				if(framerate <= 0) {
+					fprintf(stderr, "invalid framerate specified: %s\n", argv[i - 1]);
+					return -1;
+				}
+			} else if(strcmp(argv[i], "-novideo") == 0) {
+				devfile = 0;
+			} else if(strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "-device") == 0) {
+				devfile = argv[++i];
+			} else if(strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "-port") == 0) {
+				port = atoi(argv[++i]);
+				if(port <= 0 || port >= 65535) {
+					fprintf(stderr, "invalid port specified: %s\n", argv[i - 1]);
+					return -1;
+				}
+			} else {
+				int help = strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help") == 0;
+				if(!help) fprintf(stderr, "unrecognized option: %s\n", argv[i]);
+				print_usage(argv[0]);
+				exit(help ? 0 : 1);
+			}
+		} else {
+			fprintf(stderr, "unexpected argument: %s\n", argv[i]);
+			print_usage(argv[0]);
+			return -1;
+		}
+	}
+	return 0;
+}
diff -r 73b16c2ae6bf -r 08ea0abdbb8a doorbelld/src/srv.c
--- a/doorbelld/src/srv.c	Sun Mar 13 07:56:26 2016 +0200
+++ b/doorbelld/src/srv.c	Mon Mar 14 04:20:59 2016 +0200
@@ -10,6 +10,8 @@
 #include "srv.h"
 #include "dynarr.h"
 
+/* TODO convert this whole thing to multicast */
+
 static int lis_sock = -1, max_socket = -1;
 static int *csock;
 
@@ -45,6 +47,7 @@
 		lis_sock = -1;
 		return -1;
 	}
+	listen(lis_sock, 8);
 
 	return 0;
 }
@@ -84,16 +87,19 @@
 	if(s == lis_sock) {
 		/* incoming connection */
 		struct sockaddr_in addr;
-		int addr_size;
-
-		if((s = accept(lis_sock, (struct sockaddr*)&addr, (int*)&addr_size)) == -1) {
-			fprintf(stderr, "%s: failed to accept incoming connection\n", __func__);
+		socklen_t addr_size = sizeof addr;
+		if((s = accept(lis_sock, (struct sockaddr*)&addr, &addr_size)) == -1) {
+			fprintf(stderr, "%s: failed to accept incoming connection: %s\n", __func__, strerror(errno));
 			return -1;
 		}
 		printf("%s: incoming connection from %s:%d\n", __func__,
 				inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
 		csock = dynarr_push(csock, &s);
 		assert(csock);
+		if(s > max_socket) {
+			max_socket = s;
+		}
+		fcntl(s, F_SETFD, fcntl(s, F_GETFD) | O_NONBLOCK);
 		return 0;
 	}
 
@@ -101,23 +107,44 @@
 	while((sz = read(s, buf, sizeof buf - 1)) > 0) {
 		printf("%s: got data: %s\n", __func__, buf);
 	}
-	if(sz < 0 && errno != EAGAIN) {
+	if(sz <= 0 && errno != EAGAIN) {
 		/* client closed connection probably */
 		int i, num_clients = dynarr_size(csock);
 		printf("%s: removing client\n", __func__);
 		close(s);
+		max_socket = lis_sock;
 		for(i=0; i<num_clients; i++) {
 			if(csock[i] == s) {
 				csock[i] = csock[num_clients - 1];
-				csock = dynarr_pop(csock);
-				break;
+			}
+			if(csock[i] > max_socket) {
+				max_socket = csock[i];
 			}
 		}
-		assert(i < num_clients);
+
+		csock = dynarr_pop(csock);
+		--num_clients;
 	}
 	return 0;
 }
 
+struct video_block {
+	int frame;
+	int x, y;
+	int width, height;
+	char pixels[1];
+};
+#define VBLOCK_HEADER_SIZE	(offsetof(struct video_block, pixels))
+
 void srv_send_frame(unsigned char *frame, int xsz, int ysz)
 {
+	static unsigned char *buffer;
+	struct video_block *vblock;
+
+	/* for now just send a big block */
+	if(!buffer && !(buffer = malloc(xsz * ysz * 2) + VBLOCK_HEADER_SIZE)) {
+		fprintf(stderr, "failed to allocate frame send buffer\n");
+		return;
+	}
+	vblock = buffer;
 }