2 changed files with 608 additions and 0 deletions
-
241lightspi_v4.c
-
367lightspi_v5.c
@ -0,0 +1,241 @@ |
|||
|
|||
#include <stdlib.h> |
|||
#include <stdio.h> |
|||
#include <stdint.h> |
|||
#include <unistd.h> |
|||
#include <errno.h> |
|||
#include <string.h> |
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include <sys/mman.h> |
|||
#include <sys/socket.h> |
|||
#include <sys/un.h> |
|||
#include <netdb.h> |
|||
#include <pthread.h> |
|||
#include <signal.h> |
|||
#include <fcntl.h> |
|||
#include <time.h> |
|||
|
|||
int quit = 0; |
|||
|
|||
uint32_t *gpio; |
|||
|
|||
int enable = 0; |
|||
uint32_t interval = 20000000; |
|||
uint32_t width = 1500000; |
|||
|
|||
void do_pwm() |
|||
{ |
|||
struct timespec on = {0, width}, off = {0, interval - width}; |
|||
|
|||
while (!quit) |
|||
{ |
|||
if (enable) { gpio[7] = 1 << 18; } |
|||
nanosleep(&on, NULL); |
|||
gpio[10] = 1 << 18; |
|||
nanosleep(&off, NULL); |
|||
on.tv_nsec = width; |
|||
off.tv_nsec = interval - width; |
|||
} |
|||
|
|||
return; |
|||
} |
|||
|
|||
void do_quit() |
|||
{ |
|||
quit = 1; |
|||
} |
|||
|
|||
struct sock_params |
|||
{ |
|||
int sock; |
|||
struct sockaddr *addr; |
|||
socklen_t addrlen; |
|||
struct addrinfo *freeme; |
|||
}; |
|||
|
|||
int do_resolve(char *address, char *portstr, struct sock_params *params) |
|||
{ |
|||
if (strspn(address, "unix:") == 5) |
|||
{ |
|||
address += 5; |
|||
int sock = socket(AF_UNIX, SOCK_STREAM, 0); |
|||
if (sock == -1) |
|||
return errno; |
|||
struct sockaddr_un *addr = malloc(sizeof(struct sockaddr_un));; |
|||
addr->sun_family = AF_UNIX; // Polymorphism in C is pretty cool. |
|||
strncpy(addr->sun_path, address, sizeof(addr->sun_path) - 1); |
|||
addr->sun_path[sizeof(addr->sun_path) - 1] = 0; |
|||
params->sock = sock; |
|||
params->addr = (struct sockaddr*) addr; |
|||
params->addrlen = sizeof(struct sockaddr_un); |
|||
params->freeme = NULL; |
|||
} else |
|||
{ |
|||
struct addrinfo hints = |
|||
{ |
|||
.ai_flags = 0, |
|||
.ai_family = AF_UNSPEC, |
|||
.ai_socktype = SOCK_STREAM, |
|||
.ai_protocol = 0, |
|||
}; |
|||
struct addrinfo *ai; |
|||
unsigned short port = 7140; |
|||
int err; |
|||
if (portstr == NULL) |
|||
{ |
|||
if ((err = getaddrinfo(address, NULL, &hints, &ai))) |
|||
{ |
|||
return err; |
|||
} |
|||
((struct sockaddr_in*) ai->ai_addr)->sin_port = htons(port); |
|||
} else if (1 == sscanf(portstr, "%hu", &port)) |
|||
{ |
|||
if ((err = getaddrinfo(address, NULL, &hints, &ai))) |
|||
{ |
|||
return err; |
|||
} |
|||
((struct sockaddr_in*) ai->ai_addr)->sin_port = htons(port); |
|||
} else |
|||
{ |
|||
if ((err = getaddrinfo(address, portstr, &hints, &ai))) |
|||
{ |
|||
return err; |
|||
} |
|||
} |
|||
int sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
|||
if (sock == -1) |
|||
return errno; |
|||
params->sock = sock; |
|||
params->addr = ai->ai_addr; |
|||
params->addrlen = ai->ai_addrlen; |
|||
params->freeme = ai; |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
void do_unresolve(struct sock_params params) |
|||
{ |
|||
close(params.sock); |
|||
if (params.freeme == NULL) |
|||
free(params.addr); |
|||
freeaddrinfo(params.freeme); |
|||
} |
|||
|
|||
char *address, *portstr; |
|||
|
|||
void listener() |
|||
{ |
|||
struct sock_params params; |
|||
if (do_resolve(address, portstr, ¶ms)) |
|||
{ |
|||
perror("could not resolve bind address"); |
|||
goto exit; |
|||
} |
|||
|
|||
signal(SIGPIPE, SIG_IGN); |
|||
|
|||
int ec; |
|||
|
|||
ec = bind(params.sock, params.addr, params.addrlen); |
|||
if (ec) |
|||
{ |
|||
perror("could not bind"); |
|||
goto exit; |
|||
} |
|||
|
|||
ec = listen(params.sock, 1); |
|||
if (ec) |
|||
{ |
|||
perror("could not open listener"); |
|||
goto exit; |
|||
} |
|||
|
|||
while (!quit) |
|||
{ |
|||
int sockfd = accept(params.sock, NULL, NULL); |
|||
if (ec == -1) |
|||
{ |
|||
close(params.sock); |
|||
perror("could not open listener"); |
|||
goto exit; |
|||
} |
|||
|
|||
printf("accepted conn\n"); |
|||
|
|||
FILE *sockstream = fdopen(sockfd, "rw"); |
|||
|
|||
int pwm; |
|||
if (1 == fscanf(sockstream, "%i\n", &pwm)) |
|||
{ |
|||
if (pwm == 0) |
|||
{ |
|||
printf("disabling pwm\n"); |
|||
enable = 0; |
|||
} else if (pwm > 0 && pwm < 20000) |
|||
{ |
|||
printf("pwm at: %i\n", pwm); |
|||
enable = 1; |
|||
width = pwm * 1000; |
|||
} else |
|||
{ |
|||
printf("pwm out of range\n"); |
|||
} |
|||
} else |
|||
{ |
|||
printf("pwm not an integer\n"); |
|||
} |
|||
|
|||
fclose(sockstream); |
|||
} |
|||
|
|||
exit: |
|||
do_unresolve(params); |
|||
quit = 1; |
|||
return; |
|||
} |
|||
|
|||
int main(int argc, char **argv) |
|||
{ |
|||
if (argc != 3) |
|||
{ |
|||
fprintf(stderr, "incorrect usage\n"); |
|||
return 1; |
|||
} |
|||
|
|||
address = argv[1]; |
|||
portstr = argv[2]; |
|||
|
|||
int gpiofd = open("/dev/gpiomem", O_RDWR); |
|||
if (gpiofd == -1) |
|||
{ |
|||
perror("could not open memory file"); |
|||
return 1; |
|||
} |
|||
gpio = mmap(NULL, 12 * 4096, PROT_READ | PROT_WRITE, MAP_SHARED, gpiofd, 0); |
|||
if (gpio == MAP_FAILED) |
|||
{ |
|||
fprintf(stderr, "could not map gpio\n"); |
|||
return 1; |
|||
} |
|||
|
|||
gpio[1] = 1 << 24; |
|||
|
|||
signal(SIGINT, do_quit); |
|||
signal(SIGTERM, do_quit); |
|||
|
|||
pthread_t pwmthread; |
|||
pthread_create(&pwmthread, NULL, (void *(*)(void*)) do_pwm, NULL); |
|||
|
|||
pthread_t listenthread; |
|||
pthread_create(&listenthread, NULL, (void *(*)(void*)) listener, NULL); |
|||
|
|||
while (!quit) { pause(); } |
|||
|
|||
exit: |
|||
quit = 1; |
|||
pthread_join(pwmthread, NULL); |
|||
|
|||
munmap(gpio, 4096); |
|||
close(gpiofd); |
|||
} |
@ -0,0 +1,367 @@ |
|||
|
|||
#include <stdlib.h> |
|||
#include <stdio.h> |
|||
#include <stdint.h> |
|||
#include <unistd.h> |
|||
#include <errno.h> |
|||
#include <string.h> |
|||
#include <sys/types.h> |
|||
#include <sys/time.h> |
|||
#include <sys/stat.h> |
|||
#include <sys/mman.h> |
|||
#include <sys/socket.h> |
|||
#include <sys/un.h> |
|||
#include <netdb.h> |
|||
#include <pthread.h> |
|||
#include <signal.h> |
|||
#include <fcntl.h> |
|||
#include <time.h> |
|||
|
|||
int quit = 0; |
|||
|
|||
uint32_t *gpio; |
|||
|
|||
int enable = 0; |
|||
uint32_t interval = 20000000; |
|||
uint32_t width = 1500000; |
|||
struct timeval last_update = {0, 0}; |
|||
struct timespec max_idle_time = {10, 0}; |
|||
|
|||
double timespec_to_double(struct timespec t) |
|||
{ |
|||
return t.tv_sec + t.tv_nsec * 1e-9; |
|||
} |
|||
|
|||
double timeval_to_double(struct timeval t) |
|||
{ |
|||
return t.tv_sec + t.tv_usec * 1e-6; |
|||
} |
|||
|
|||
void do_pwm() |
|||
{ |
|||
struct timespec on = {0, width}, off = {0, interval - width}; |
|||
|
|||
while (!quit) |
|||
{ |
|||
if (enable) { gpio[7] = 1 << 18; } |
|||
nanosleep(&on, NULL); |
|||
gpio[10] = 1 << 18; |
|||
nanosleep(&off, NULL); |
|||
on.tv_nsec = width; |
|||
off.tv_nsec = interval - width; |
|||
} |
|||
|
|||
return; |
|||
} |
|||
|
|||
void do_quit() |
|||
{ |
|||
quit = 1; |
|||
} |
|||
|
|||
struct sock_params |
|||
{ |
|||
int sock; |
|||
struct sockaddr *addr; |
|||
socklen_t addrlen; |
|||
struct addrinfo *freeme; |
|||
}; |
|||
|
|||
int do_resolve(char *address, char *portstr, struct sock_params *params) |
|||
{ |
|||
if (strspn(address, "unix:") == 5) |
|||
{ |
|||
address += 5; |
|||
int sock = socket(AF_UNIX, SOCK_STREAM, 0); |
|||
if (sock == -1) |
|||
return errno; |
|||
struct sockaddr_un *addr = malloc(sizeof(struct sockaddr_un));; |
|||
addr->sun_family = AF_UNIX; // Polymorphism in C is pretty cool. |
|||
strncpy(addr->sun_path, address, sizeof(addr->sun_path) - 1); |
|||
addr->sun_path[sizeof(addr->sun_path) - 1] = 0; |
|||
params->sock = sock; |
|||
params->addr = (struct sockaddr*) addr; |
|||
params->addrlen = sizeof(struct sockaddr_un); |
|||
params->freeme = NULL; |
|||
} else |
|||
{ |
|||
struct addrinfo hints = |
|||
{ |
|||
.ai_flags = 0, |
|||
.ai_family = AF_UNSPEC, |
|||
.ai_socktype = SOCK_STREAM, |
|||
.ai_protocol = 0, |
|||
}; |
|||
struct addrinfo *ai; |
|||
unsigned short port = 7140; |
|||
int err; |
|||
if (portstr == NULL) |
|||
{ |
|||
if ((err = getaddrinfo(address, NULL, &hints, &ai))) |
|||
{ |
|||
return err; |
|||
} |
|||
((struct sockaddr_in*) ai->ai_addr)->sin_port = htons(port); |
|||
} else if (1 == sscanf(portstr, "%hu", &port)) |
|||
{ |
|||
if ((err = getaddrinfo(address, NULL, &hints, &ai))) |
|||
{ |
|||
return err; |
|||
} |
|||
((struct sockaddr_in*) ai->ai_addr)->sin_port = htons(port); |
|||
} else |
|||
{ |
|||
if ((err = getaddrinfo(address, portstr, &hints, &ai))) |
|||
{ |
|||
return err; |
|||
} |
|||
} |
|||
int sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
|||
if (sock == -1) |
|||
return errno; |
|||
params->sock = sock; |
|||
params->addr = ai->ai_addr; |
|||
params->addrlen = ai->ai_addrlen; |
|||
params->freeme = ai; |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
void do_unresolve(struct sock_params params) |
|||
{ |
|||
close(params.sock); |
|||
if (params.freeme == NULL) |
|||
free(params.addr); |
|||
freeaddrinfo(params.freeme); |
|||
} |
|||
|
|||
char *address, *portstr; |
|||
|
|||
struct llnode |
|||
{ |
|||
struct llnode *next; |
|||
struct llnode *prev; |
|||
struct llnode *next_done; |
|||
int done; |
|||
pthread_t *join; |
|||
}; |
|||
|
|||
struct llist |
|||
{ |
|||
struct llnode *head; |
|||
pthread_mutex_t lock; |
|||
}; |
|||
|
|||
struct conn_info |
|||
{ |
|||
int sockfd; |
|||
struct llnode *this; |
|||
struct llist *list; |
|||
}; |
|||
|
|||
void do_conn(struct conn_info *ci) |
|||
{ |
|||
int sockfd = ci->sockfd; |
|||
|
|||
printf("accepted conn\n"); |
|||
|
|||
FILE *sockstream = fdopen(sockfd, "rw"); |
|||
|
|||
int pwm; |
|||
if (1 == fscanf(sockstream, "%i", &pwm)) |
|||
{ |
|||
if (pwm == 0) |
|||
{ |
|||
printf("disabling pwm\n"); |
|||
enable = 0; |
|||
shutdown(sockfd, SHUT_RDWR); |
|||
} else if (pwm > 0 && pwm < 20000) |
|||
{ |
|||
gettimeofday(&last_update, NULL); |
|||
printf("pwm at: %i\n", pwm); |
|||
enable = 1; |
|||
width = pwm * 1000; |
|||
shutdown(sockfd, SHUT_RDWR); |
|||
struct timespec delay = max_idle_time, rem = {0, 0}; |
|||
while (delay.tv_nsec != 0 || delay.tv_sec != 0) |
|||
{ |
|||
nanosleep(&delay, &rem); |
|||
delay = rem; |
|||
} |
|||
|
|||
struct timeval tod; |
|||
gettimeofday(&tod, NULL); |
|||
if (timeval_to_double(tod) - timeval_to_double(last_update) + 0.1 >= timespec_to_double(max_idle_time)) |
|||
{ |
|||
enable = 0; |
|||
printf("disabling pwm due to idle timeout\n"); |
|||
} else |
|||
{ |
|||
printf("[debug] no timeout, not disabling\n"); |
|||
} |
|||
} else |
|||
{ |
|||
printf("pwm out of range\n"); |
|||
shutdown(sockfd, SHUT_RDWR); |
|||
} |
|||
} else |
|||
{ |
|||
printf("pwm not an integer\n"); |
|||
shutdown(sockfd, SHUT_RDWR); |
|||
} |
|||
|
|||
fclose(sockstream); |
|||
|
|||
struct llist *list = ci->list; |
|||
pthread_mutex_lock(&list->lock); |
|||
ci->this->next_done = list->head->next_done; |
|||
list->head->next_done = ci->this; |
|||
ci->this->done = 1; |
|||
pthread_mutex_unlock(&list->lock); |
|||
|
|||
free(ci); |
|||
} |
|||
|
|||
void node_unlink(struct llnode *node) |
|||
{ |
|||
node->next->prev = node->prev; |
|||
node->prev->next = node->next; |
|||
} |
|||
|
|||
void walk_and_destroy_done(struct llist *list) |
|||
{ |
|||
pthread_mutex_lock(&list->lock); |
|||
struct llnode *active = list->head->next_done; |
|||
list->head->next_done = NULL; |
|||
while (active != NULL) |
|||
{ |
|||
node_unlink(active); |
|||
pthread_join(*active->join, NULL); |
|||
struct llnode *next = active->next_done; |
|||
free(active->join); |
|||
free(active); |
|||
active = next; |
|||
} |
|||
pthread_mutex_unlock(&list->lock); |
|||
} |
|||
|
|||
void listener() |
|||
{ |
|||
struct sock_params params; |
|||
if (do_resolve(address, portstr, ¶ms)) |
|||
{ |
|||
perror("could not resolve bind address"); |
|||
goto exit; |
|||
} |
|||
|
|||
signal(SIGPIPE, SIG_IGN); |
|||
|
|||
struct llist list; |
|||
pthread_mutex_init(&list.lock, NULL); |
|||
struct llnode head = { &head, &head, NULL, 0, NULL }; |
|||
list.head = &head; |
|||
|
|||
int ec, one = 1; |
|||
setsockopt(params.sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)); |
|||
|
|||
ec = bind(params.sock, params.addr, params.addrlen); |
|||
if (ec) |
|||
{ |
|||
perror("could not bind"); |
|||
goto exit; |
|||
} |
|||
|
|||
ec = listen(params.sock, 1); |
|||
if (ec) |
|||
{ |
|||
perror("could not open listener"); |
|||
goto exit; |
|||
} |
|||
|
|||
struct linger linger = {0, 0}; |
|||
setsockopt(params.sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(struct linger)); |
|||
|
|||
while (!quit) |
|||
{ |
|||
walk_and_destroy_done(&list); |
|||
|
|||
int sockfd = accept(params.sock, NULL, NULL); |
|||
if (ec == -1) |
|||
{ |
|||
close(params.sock); |
|||
perror("could not open listener"); |
|||
goto exit; |
|||
} |
|||
|
|||
pthread_t *handler = malloc(sizeof(pthread_t)); |
|||
struct llnode *spnode = malloc(sizeof(struct llnode)); |
|||
struct conn_info *ci = malloc(sizeof(struct conn_info)); |
|||
spnode->next_done = NULL; |
|||
spnode->done = 0; |
|||
spnode->join = handler; |
|||
|
|||
pthread_mutex_lock(&list.lock); |
|||
spnode->next = head.next; |
|||
spnode->prev = &head; |
|||
head.next->prev = spnode; |
|||
head.next = spnode; |
|||
pthread_mutex_unlock(&list.lock); |
|||
|
|||
ci->sockfd = sockfd; |
|||
ci->list = &list; |
|||
ci->this = spnode; |
|||
|
|||
pthread_create(handler, NULL, (void *(*)(void*)) do_conn, ci); |
|||
} |
|||
|
|||
exit: |
|||
pthread_mutex_destroy(&list.lock); |
|||
do_unresolve(params); |
|||
quit = 1; |
|||
return; |
|||
} |
|||
|
|||
int main(int argc, char **argv) |
|||
{ |
|||
if (argc != 3) |
|||
{ |
|||
fprintf(stderr, "incorrect usage\n"); |
|||
return 1; |
|||
} |
|||
|
|||
address = argv[1]; |
|||
portstr = argv[2]; |
|||
|
|||
int gpiofd = open("/dev/gpiomem", O_RDWR); |
|||
if (gpiofd == -1) |
|||
{ |
|||
perror("could not open memory file"); |
|||
return 1; |
|||
} |
|||
gpio = mmap(NULL, 12 * 4096, PROT_READ | PROT_WRITE, MAP_SHARED, gpiofd, 0); |
|||
if (gpio == MAP_FAILED) |
|||
{ |
|||
fprintf(stderr, "could not map gpio\n"); |
|||
return 1; |
|||
} |
|||
|
|||
gpio[1] = 1 << 24; |
|||
|
|||
signal(SIGINT, do_quit); |
|||
signal(SIGTERM, do_quit); |
|||
|
|||
pthread_t pwmthread; |
|||
pthread_create(&pwmthread, NULL, (void *(*)(void*)) do_pwm, NULL); |
|||
|
|||
pthread_t listenthread; |
|||
pthread_create(&listenthread, NULL, (void *(*)(void*)) listener, NULL); |
|||
|
|||
while (!quit) { pause(); } |
|||
|
|||
exit: |
|||
quit = 1; |
|||
pthread_join(pwmthread, NULL); |
|||
|
|||
munmap(gpio, 4096); |
|||
close(gpiofd); |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue