# HG changeset patch # User John Tsiombikas # Date 1457848563 -7200 # Node ID d3f2a2b19504d6d6ca6f668cda74a38a11b3e8fd # Parent a5755687dd7523f2f9c8394e4de67ea2caf5ac1b doorbell server under construction diff -r a5755687dd75 -r d3f2a2b19504 .hgignore --- a/.hgignore Tue Mar 08 03:26:01 2016 +0200 +++ b/.hgignore Sun Mar 13 07:56:03 2016 +0200 @@ -2,3 +2,5 @@ \.d$ \.swp$ spycam$ +doorbelld$ +\.ppm$ diff -r a5755687dd75 -r d3f2a2b19504 doorbelld/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doorbelld/Makefile Sun Mar 13 07:56:03 2016 +0200 @@ -0,0 +1,13 @@ +src = $(wildcard src/*.c) +obj = $(src:.c=.o) +bin = doorbelld + +CFLAGS = -pedantic -Wall -g +LDFLAGS = -lwcam -lpthread + +$(bin): $(obj) + $(CC) -o $@ $(obj) $(LDFLAGS) + +.PHONY: clean +clean: + rm -f $(obj) $(bin) diff -r a5755687dd75 -r d3f2a2b19504 doorbelld/src/dynarr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doorbelld/src/dynarr.c Sun Mar 13 07:56:03 2016 +0200 @@ -0,0 +1,128 @@ +/* dynarr - dynamic resizable C array data structure + * author: John Tsiombikas + * license: public domain + */ +#include +#include +#include +#include "dynarr.h" + +/* The array descriptor keeps auxilliary information needed to manipulate + * the dynamic array. It's allocated adjacent to the array buffer. + */ +struct arrdesc { + int nelem, szelem; + int max_elem; + int bufsz; /* not including the descriptor */ +}; + +#define DESC(x) ((struct arrdesc*)((char*)(x) - sizeof(struct arrdesc))) + +void *dynarr_alloc(int elem, int szelem) +{ + struct arrdesc *desc; + + if(!(desc = malloc(elem * szelem + sizeof *desc))) { + return 0; + } + desc->nelem = desc->max_elem = elem; + desc->szelem = szelem; + desc->bufsz = elem * szelem; + return (char*)desc + sizeof *desc; +} + +void dynarr_free(void *da) +{ + if(da) { + free(DESC(da)); + } +} + +void *dynarr_resize(void *da, int elem) +{ + int newsz; + void *tmp; + struct arrdesc *desc; + + if(!da) return 0; + desc = DESC(da); + + newsz = desc->szelem * elem; + + if(!(tmp = realloc(desc, newsz + sizeof *desc))) { + return 0; + } + desc = tmp; + + desc->nelem = desc->max_elem = elem; + desc->bufsz = newsz; + return (char*)desc + sizeof *desc; +} + +int dynarr_empty(void *da) +{ + return DESC(da)->nelem ? 0 : 1; +} + +int dynarr_size(void *da) +{ + return DESC(da)->nelem; +} + + +/* stack semantics */ +void *dynarr_push(void *da, void *item) +{ + struct arrdesc *desc; + int nelem; + + desc = DESC(da); + nelem = desc->nelem; + + if(nelem >= desc->max_elem) { + /* need to resize */ + struct arrdesc *tmp; + int newsz = desc->max_elem ? desc->max_elem * 2 : 1; + + if(!(tmp = dynarr_resize(da, newsz))) { + fprintf(stderr, "failed to resize\n"); + return da; + } + da = tmp; + desc = DESC(da); + desc->nelem = nelem; + } + + if(item) { + memcpy((char*)da + desc->nelem++ * desc->szelem, item, desc->szelem); + } + return da; +} + +void *dynarr_pop(void *da) +{ + struct arrdesc *desc; + int nelem; + + desc = DESC(da); + nelem = desc->nelem; + + if(!nelem) return da; + + if(nelem <= desc->max_elem / 3) { + /* reclaim space */ + struct arrdesc *tmp; + int newsz = desc->max_elem / 2; + + if(!(tmp = dynarr_resize(da, newsz))) { + fprintf(stderr, "failed to resize\n"); + return da; + } + da = tmp; + desc = DESC(da); + desc->nelem = nelem; + } + desc->nelem--; + + return da; +} diff -r a5755687dd75 -r d3f2a2b19504 doorbelld/src/dynarr.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doorbelld/src/dynarr.h Sun Mar 13 07:56:03 2016 +0200 @@ -0,0 +1,38 @@ +/* dynarr - dynamic resizable C array data structure + * author: John Tsiombikas + * license: public domain + */ +#ifndef DYNARR_H_ +#define DYNARR_H_ + +void *dynarr_alloc(int elem, int szelem); +void dynarr_free(void *da); +void *dynarr_resize(void *da, int elem); + +int dynarr_empty(void *da); +int dynarr_size(void *da); + +/* stack semantics */ +void *dynarr_push(void *da, void *item); +void *dynarr_pop(void *da); + + +/* usage example: + * ------------- + * int *arr = dynarr_alloc(0, sizeof *arr); + * + * int x = 10; + * arr = dynarr_push(arr, &x); + * x = 5; + * arr = dynarr_push(arr, &x); + * x = 42; + * arr = dynarr_push(arr, &x); + * + * for(i=0; i +#include +#include +#include +#include +#include +#include +#include "srv.h" + +void *frame_proc(void *arg); +int save_image(const char *fname, unsigned char *pixels, int xsz, int ysz); +void sighandler(int s); + +int fd; +int width = 640; +int height = 480; +int framerate = 30; +unsigned char *frame; +int done; +int frame_available; +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t condvar = PTHREAD_COND_INITIALIZER; + +int main(int argc, char **argv) +{ + char *devfile = "/dev/video0"; + pthread_t thread; + + if(argv[1]) { + devfile = argv[1]; + } + + signal(SIGINT, sighandler); + signal(SIGQUIT, sighandler); + signal(SIGSEGV, sighandler); + + if(srv_init(2828) == -1) { + return 1; + } + + if(!(frame = malloc(width * height * 4))) { + 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; + } + wcam_start(fd); + + if(pthread_create(&thread, 0, frame_proc, 0) == -1) { + fprintf(stderr, "failed to create frame processing thread\n"); + return 1; + } + + while(!done) { + int i, res; + int *sock = srv_sockets(); + int num_sockets = srv_num_sockets(); + int maxfd = srv_max_socket(); + fd_set rdset; + + if(fd > maxfd) maxfd = fd; + + FD_ZERO(&rdset); + FD_SET(fd, &rdset); + + for(i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include "srv.h" +#include "dynarr.h" + +static int lis_sock = -1, max_socket = -1; +static int *csock; + +int srv_init(int port) +{ + struct sockaddr_in addr; + + if(lis_sock != -1) { + fprintf(stderr, "%s: already running\n", __func__); + return -1; + } + + if((lis_sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) { + fprintf(stderr, "%s: failed to create listening socket\n", __func__); + return -1; + } + if(!(csock = dynarr_alloc(1, sizeof *csock))) { + fprintf(stderr, "%s: failed to allocate client socket array\n", __func__); + return -1; + } + csock[0] = lis_sock; + max_socket = lis_sock; + + fcntl(lis_sock, F_SETFD, fcntl(lis_sock, F_GETFD) | O_NONBLOCK); + + memset(&addr, 0, sizeof addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + if(bind(lis_sock, (struct sockaddr*)&addr, sizeof addr) == -1) { + fprintf(stderr, "%s: failed to bind port %d\n", __func__, port); + close(lis_sock); + lis_sock = -1; + return -1; + } + + return 0; +} + +void srv_shutdown(void) +{ + int i, sz = dynarr_size(csock); + for(i=0; i 0) { + printf("%s: got data: %s\n", __func__, buf); + } + if(sz < 0 && errno != EAGAIN) { + /* client closed connection probably */ + int i, num_clients = dynarr_size(csock); + printf("%s: removing client\n", __func__); + close(s); + for(i=0; i