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  }