diff --git a/Makefile b/Makefile index 477b810..eb74eb7 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ endif ifneq ($(call optbool,$(WITH_GPIO)),) -_LIBS += -lwiringPi +_LIBS += -lgpiod override CFLAGS += -DWITH_GPIO _SRCS += $(shell ls src/gpio/*.c) endif diff --git a/README.md b/README.md index fca35fb..47ff9bb 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ | Streaming via UNIX domain socket | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No | | Debug logs without recompiling,
performance statistics log,
access to HTTP streaming parameters | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No | | Option to serve files
with a built-in HTTP server | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | ![#ffaa00](https://placehold.it/15/ffaa00/000000?text=+) Regular files only | -| Signaling about the stream state to GPIO
on Raspberry Pi using [wiringPi](http://wiringpi.com) | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No | +| Signaling about the stream state to GPIO using [libgpiod](https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/about) | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No | | Access to webcam controls (focus, servos)
and settings such as brightness via HTTP | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) No | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Yes | Footnotes: @@ -36,10 +36,10 @@ If you're going to live-stream from your backyard webcam and need to control it, You'll need ```make```, ```gcc```, ```libevent``` with ```pthreads``` support, ```libjpeg8```/```libjpeg-turbo```, ```libuuid``` and ```libbsd``` (only for Linux). * Arch: `sudo pacman -S libevent libjpeg-turbo libutil-linux libbsd`. -* Raspbian: `sudo apt install libevent-dev libjpeg8-dev uuid-dev libbsd-dev`. Add `libraspberrypi-dev` for `WITH_OMX=1` and `wiringpi` for `WITH_GPIO=1`. +* Raspbian: `sudo apt install libevent-dev libjpeg8-dev uuid-dev libbsd-dev`. Add `libraspberrypi-dev` for `WITH_OMX=1` and `libgpiod` for `WITH_GPIO=1`. * Debian: `sudo apt install build-essential libevent-dev libjpeg62-turbo-dev uuid-dev libbsd-dev`. -On Raspberry Pi you can build the program with OpenMAX IL. To do this pass option ```WITH_OMX=1``` to ```make```. To enable GPIO support install [wiringPi](http://wiringpi.com) and pass option ```WITH_GPIO=1```. If the compiler reports about a missing function ```pthread_get_name_np()``` (or similar), add option ```WITH_PTHREAD_NP=0``` (it's enabled by default). For the similar error with ```setproctitle()``` add option ```WITH_SETPROCTITLE=0```. +On Raspberry Pi you can build the program with OpenMAX IL. To do this pass option ```WITH_OMX=1``` to ```make```. To enable GPIO support install [libgpiod](https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/about) and pass option ```WITH_GPIO=1```. If the compiler reports about a missing function ```pthread_get_name_np()``` (or similar), add option ```WITH_PTHREAD_NP=0``` (it's enabled by default). For the similar error with ```setproctitle()``` add option ```WITH_SETPROCTITLE=0```. ``` $ git clone --depth=1 https://github.com/pikvm/ustreamer @@ -48,7 +48,7 @@ $ make $ ./ustreamer --help ``` -AUR has a package for Arch Linux: https://aur.archlinux.org/packages/ustreamer. It should compile automatically with OpenMAX IL on Raspberry Pi, if the corresponding headers are present in ```/opt/vc/include```. Same with GPIO. +AUR has a package for Arch Linux: https://aur.archlinux.org/packages/ustreamer. It should compile automatically with OpenMAX IL on Raspberry Pi, if the corresponding headers are present in ```/opt/vc/include```. FreeBSD port: https://www.freshports.org/multimedia/ustreamer. ----- diff --git a/README.ru.md b/README.ru.md index 35f0919..b35e388 100644 --- a/README.ru.md +++ b/README.ru.md @@ -19,7 +19,7 @@ | Стрим через UNIX domain socket | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Есть | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) Нет | | Дебаг-логи без перекомпиляции,
логгирование статистики производительности,
возможность получения параметров
трансляции по HTTP | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Есть | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) Нет | | Возможность сервить файлы встроенным
HTTP-сервером | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Есть | ![#ffaa00](https://placehold.it/15/ffaa00/000000?text=+) Нет каталогов | -| Вывод сигналов о состоянии стрима на GPIO
на Raspberry Pi с помощью [wiringPi](http://wiringpi.com) | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Есть | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) Нет | +| Вывод сигналов о состоянии стрима на GPIO
с помощью [libgpiod](https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/about) | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Есть | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) Нет | | Поддержка контролов веб-камер (фокус,
движение сервами) и всяких настроек,
типа яркости, через HTTP | ![#f03c15](https://placehold.it/15/f03c15/000000?text=+) Нет | ![#00aa00](https://placehold.it/15/00aa00/000000?text=+) Есть | Сносочки: @@ -36,10 +36,10 @@ Для сборки вам понадобятся ```make```, ```gcc```, ```libevent``` с поддержкой ```pthreads```, ```libjpeg8```/```libjpeg-turbo```, ```libuuid``` и ```libbsd``` (только для Linux). * Arch: `sudo pacman -S libevent libjpeg-turbo libutil-linux libbsd`. -* Raspbian: `sudo apt install libevent-dev libjpeg8-dev uuid-dev libbsd-dev`. Добавьте `libraspberrypi-dev` для сборки с `WITH_OMX=1` и `wiringpi` для `WITH_GPIO=1`. +* Raspbian: `sudo apt install libevent-dev libjpeg8-dev uuid-dev libbsd-dev`. Добавьте `libraspberrypi-dev` для сборки с `WITH_OMX=1` и `libgpiod` для `WITH_GPIO=1`. * Debian: `sudo apt install build-essential libevent-dev libjpeg62-turbo-dev uuid-dev libbsd-dev`. -На Raspberry Pi программу можно собрать с поддержкой OpenMAX IL. Для этого передайте ```make``` параметр ```WITH_OMX=1```. Для включения сборки с поддержкой GPIO установите [wiringPi](http://wiringpi.com) и добавьте параметр ```WITH_GPIO=1```. Если при сборке компилятор ругается на отсутствие функции ```pthread_get_name_np()``` или другой подобной, добавьте параметр ```WITH_PTHREAD_NP=0``` (по умолчанию он включен). При аналогичной ошибке с функцией ```setproctitle()``` добавьте параметр ```WITH_SETPROCTITLE=0```. +На Raspberry Pi программу можно собрать с поддержкой OpenMAX IL. Для этого передайте ```make``` параметр ```WITH_OMX=1```. Для включения сборки с поддержкой GPIO установите [libgpiod](https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/about) и добавьте параметр ```WITH_GPIO=1```. Если при сборке компилятор ругается на отсутствие функции ```pthread_get_name_np()``` или другой подобной, добавьте параметр ```WITH_PTHREAD_NP=0``` (по умолчанию он включен). При аналогичной ошибке с функцией ```setproctitle()``` добавьте параметр ```WITH_SETPROCTITLE=0```. ``` $ git clone --depth=1 https://github.com/pikvm/ustreamer @@ -48,7 +48,7 @@ $ make $ ./ustreamer --help ``` -Для Arch Linux в AUR есть готовый пакет: https://aur.archlinux.org/packages/ustreamer. На Raspberry Pi програма автоматически собирается с поддержкой OpenMAX IL, если обнаружит нужные хедеры в ```/opt/vc/include```. То же самое и с GPIO. +Для Arch Linux в AUR есть готовый пакет: https://aur.archlinux.org/packages/ustreamer. На Raspberry Pi програма автоматически собирается с поддержкой OpenMAX IL, если обнаружит нужные хедеры в ```/opt/vc/include```. Порт для FreeBSD: https://www.freshports.org/multimedia/ustreamer. ----- diff --git a/pkg/arch/PKGBUILD b/pkg/arch/PKGBUILD index 86949c1..ed6b001 100644 --- a/pkg/arch/PKGBUILD +++ b/pkg/arch/PKGBUILD @@ -9,9 +9,8 @@ pkgdesc="Lightweight and fast MJPG-HTTP streamer" url="https://github.com/pikvm/ustreamer" license=(GPL) arch=(i686 x86_64 armv6h armv7h aarch64) -depends=(libjpeg libevent libutil-linux libbsd) +depends=(libjpeg libevent libutil-linux libbsd libgpiod) # optional: raspberrypi-firmware for OMX encoder -# optional: wiringpi for GPIO support makedepends=(gcc make) source=(${pkgname}::"git+https://github.com/pikvm/ustreamer#commit=v${pkgver}") md5sums=(SKIP) @@ -23,9 +22,8 @@ build() { cp -r $pkgname $pkgname-build cd $pkgname-build - local _options="" + local _options="WITH_GPIO=1" [ -e /opt/vc/include/IL/OMX_Core.h ] && _options="$_options WITH_OMX=1" - [ -e /usr/include/wiringPi.h ] && _options="$_options WITH_GPIO=1" make $_options CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS" $MAKEFLAGS } diff --git a/pkg/docker/Dockerfile.arm.cross b/pkg/docker/Dockerfile.arm.cross index 78f9489..b884058 100644 --- a/pkg/docker/Dockerfile.arm.cross +++ b/pkg/docker/Dockerfile.arm.cross @@ -8,7 +8,7 @@ RUN apt-get update \ libjpeg8-dev \ libbsd-dev \ libraspberrypi-dev \ - wiringpi \ + libgpiod-dev \ && rm -rf /var/lib/apt/lists/* WORKDIR /build/ustreamer/ @@ -27,7 +27,7 @@ RUN apt-get update \ libjpeg8 \ uuid \ libbsd0 \ - wiringpi \ + libgpiod2 \ && rm -rf /var/lib/apt/lists/* RUN ["cross-build-end"] diff --git a/pkg/docker/Dockerfile.arm.native b/pkg/docker/Dockerfile.arm.native index e2ab377..3772534 100644 --- a/pkg/docker/Dockerfile.arm.native +++ b/pkg/docker/Dockerfile.arm.native @@ -6,7 +6,7 @@ RUN apt-get update \ libjpeg8-dev \ libbsd-dev \ libraspberrypi-dev \ - wiringpi \ + libgpiod-dev \ && rm -rf /var/lib/apt/lists/* WORKDIR /build/ustreamer/ @@ -22,7 +22,7 @@ RUN apt-get update \ libjpeg8 \ uuid \ libbsd0 \ - wiringpi \ + libgpiod2 \ && rm -rf /var/lib/apt/lists/* WORKDIR /ustreamer diff --git a/pkg/docker/Dockerfile.x64.native b/pkg/docker/Dockerfile.x64.native index f170934..190c39f 100644 --- a/pkg/docker/Dockerfile.x64.native +++ b/pkg/docker/Dockerfile.x64.native @@ -10,11 +10,12 @@ RUN apt-get update \ libjpeg62-turbo-dev \ uuid-dev \ libbsd-dev \ + libgpiod-dev \ && rm -rf /var/lib/apt/lists/* WORKDIR /build/ustreamer/ COPY . . -RUN make -j5 +RUN make -j5 WITH_GPIO=1 FROM debian:buster-slim as run @@ -26,6 +27,7 @@ RUN apt-get update \ libjpeg62-turbo \ uuid \ libbsd0 \ + libgpiod2 \ && rm -rf /var/lib/apt/lists/* WORKDIR /ustreamer diff --git a/src/gpio/gpio.c b/src/gpio/gpio.c index b0cf06c..d73a87b 100644 --- a/src/gpio/gpio.c +++ b/src/gpio/gpio.c @@ -22,8 +22,121 @@ #include "gpio.h" +#include +#include +#include +#include -int gpio_pin_prog_running; -int gpio_pin_stream_online; -int gpio_pin_has_http_clients; -int gpio_pin_workers_busy_at; +#include +#include + +#include "../tools.h" +#include "../logging.h" +#include "../threading.h" + + +struct gpio_t gpio = { + .path = "/dev/gpiochip0", + .consumer_prefix = "ustreamer", + +# define MAKE_OUTPUT(_role) { \ + .pin = -1, \ + .role = _role, \ + .consumer = NULL, \ + .line = NULL, \ + .state = false \ + } + + .prog_running = MAKE_OUTPUT("prog-running"), + .stream_online = MAKE_OUTPUT("stream-online"), + .has_http_clients = MAKE_OUTPUT("has-http-clients"), + +# undef MAKE_OUTPUT + + // mutex uninitialized + .chip = NULL +}; + + +static void _gpio_output_init(struct gpio_output_t *output); +static void _gpio_output_destroy(struct gpio_output_t *output); + + +void gpio_init(void) { + assert(gpio.chip == NULL); + if ( + gpio.prog_running.pin >= 0 + || gpio.stream_online.pin >= 0 + || gpio.has_http_clients.pin >= 0 + ) { + A_MUTEX_INIT(&gpio.mutex); + LOG_INFO("GPIO: Using chip device: %s", gpio.path); + if ((gpio.chip = gpiod_chip_open(gpio.path)) != NULL) { + _gpio_output_init(&gpio.prog_running); + _gpio_output_init(&gpio.stream_online); + _gpio_output_init(&gpio.has_http_clients); + } else { + LOG_PERROR("GPIO: Can't initialize chip device %s", gpio.path); + } + } +} + +void gpio_destroy(void) { + _gpio_output_destroy(&gpio.prog_running); + _gpio_output_destroy(&gpio.stream_online); + _gpio_output_destroy(&gpio.has_http_clients); + if (gpio.chip) { + gpiod_chip_close(gpio.chip); + gpio.chip = NULL; + A_MUTEX_DESTROY(&gpio.mutex); + } +} + +int gpio_inner_set(struct gpio_output_t *output, bool state) { + int retval = 0; + + assert(gpio.chip); + assert(output->line); + assert(output->state != state); // Must be checked in macro for the performance + A_MUTEX_LOCK(&gpio.mutex); + + if (gpiod_line_set_value(output->line, (int)state) < 0) { \ + LOG_PERROR("GPIO: Can't write value %d to line %s (will be disabled)", state, output->consumer); \ + _gpio_output_destroy(output); + retval = -1; + } + + A_MUTEX_UNLOCK(&gpio.mutex); + return retval; +} + +static void _gpio_output_init(struct gpio_output_t *output) { + assert(gpio.chip); + assert(output->line == NULL); + + A_CALLOC(output->consumer, strlen(gpio.consumer_prefix) + strlen(output->role) + 16); + sprintf(output->consumer, "%s::%s", gpio.consumer_prefix, output->role); + + if (output->pin >= 0) { + if ((output->line = gpiod_chip_get_line(gpio.chip, output->pin)) != NULL) { + if (gpiod_line_request_output(output->line, output->consumer, 0) < 0) { + LOG_PERROR("GPIO: Can't request pin=%d as %s", output->pin, output->consumer); + _gpio_output_destroy(output); + } + } else { + LOG_PERROR("GPIO: Can't get pin=%d as %s", output->pin, output->consumer); + } + } +} + +static void _gpio_output_destroy(struct gpio_output_t *output) { + if (output->line) { + gpiod_line_release(output->line); + output->line = NULL; + } + if (output->consumer) { + free(output->consumer); + output->consumer = NULL; + } + output->state = false; +} diff --git a/src/gpio/gpio.h b/src/gpio/gpio.h index a7c6d1e..1965f1d 100644 --- a/src/gpio/gpio.h +++ b/src/gpio/gpio.h @@ -22,75 +22,62 @@ #pragma once -#include +#include -#include +#include +#include #include "../tools.h" #include "../logging.h" -extern int gpio_pin_prog_running; -extern int gpio_pin_stream_online; -extern int gpio_pin_has_http_clients; -extern int gpio_pin_workers_busy_at; +struct gpio_output_t { + int pin; + const char *role; + char *consumer; + struct gpiod_line *line; + bool state; +}; + +struct gpio_t { + char *path; + char *consumer_prefix; + + struct gpio_output_t prog_running; + struct gpio_output_t stream_online; + struct gpio_output_t has_http_clients; + + pthread_mutex_t mutex; + struct gpiod_chip *chip; +}; -#define GPIO_INIT { \ - gpio_pin_prog_running = -1; \ - gpio_pin_stream_online = -1; \ - gpio_pin_has_http_clients = -1; \ - gpio_pin_workers_busy_at = -1; \ - } +extern struct gpio_t gpio; -#define GPIO_INIT_PIN(_role, _offset) _gpio_init_pin(#_role, gpio_pin_##_role, _offset) -INLINE void _gpio_init_pin(const char *role, int base, unsigned offset) { - if (base >= 0) { - pinMode(base + offset, OUTPUT); - if (offset == 0) { - LOG_INFO("GPIO: Using pin %d as %s", base, role); - } else { - LOG_INFO("GPIO: Using pin %d+%u as %s", base, offset, role); - } - } -} +void gpio_init(void); +void gpio_destroy(void); +int gpio_inner_set(struct gpio_output_t *output, bool state); -#define GPIO_INIT_PINOUT { \ - if ( \ - gpio_pin_prog_running >= 0 \ - || gpio_pin_stream_online >= 0 \ - || gpio_pin_has_http_clients >= 0 \ - || gpio_pin_workers_busy_at >= 0 \ - ) { \ - LOG_INFO("GPIO: Using wiringPi"); \ - if (wiringPiSetupGpio() < 0) { \ - LOG_PERROR("GPIO: Can't initialize wiringPi"); \ - exit(1); \ - } else { \ - GPIO_INIT_PIN(prog_running, 0); \ - GPIO_INIT_PIN(stream_online, 0); \ - GPIO_INIT_PIN(has_http_clients, 0); \ - GPIO_INIT_PIN(workers_busy_at, 0); \ + +#define SET_STATE(_output, _state) { \ + if (_output.line && _output.state != _state) { \ + if (!gpio_inner_set(&_output, _state)) { \ + _output.state = _state; \ } \ } \ } -#define GPIO_SET_STATE(_role, _offset, _state) _gpio_set_state(#_role, gpio_pin_##_role, _offset, _state) - -INLINE void _gpio_set_state(const char *role, int base, unsigned offset, int state) { - if (base >= 0) { - if (offset == 0) { - LOG_DEBUG("GPIO: Writing %d to pin %d (%s)", state, base, role); - } else { - LOG_DEBUG("GPIO: Writing %d to pin %d+%u (%s)", state, base, offset, role); - } - digitalWrite(base + offset, state); - } +INLINE void gpio_set_prog_running(bool state) { + SET_STATE(gpio.prog_running, state); } -#define GPIO_SET_LOW(_role) GPIO_SET_STATE(_role, 0, LOW) -#define GPIO_SET_HIGH(_role) GPIO_SET_STATE(_role, 0, HIGH) +INLINE void gpio_set_stream_online(bool state) { + SET_STATE(gpio.stream_online, state); +} -#define GPIO_SET_LOW_AT(_role, _offset) GPIO_SET_STATE(_role, _offset, LOW) -#define GPIO_SET_HIGH_AT(_role, _offset) GPIO_SET_STATE(_role, _offset, HIGH) +INLINE void gpio_set_has_http_clients(bool state) { + SET_STATE(gpio.has_http_clients, state); +} + +#undef SET_STATE diff --git a/src/http/server.c b/src/http/server.c index d3910d0..c2637d8 100644 --- a/src/http/server.c +++ b/src/http/server.c @@ -550,7 +550,7 @@ static void _http_callback_stream(struct evhttp_request *request, void *v_server } # ifdef WITH_GPIO - GPIO_SET_HIGH(has_http_clients); + gpio_set_has_http_clients(true); # endif } @@ -724,7 +724,7 @@ static void _http_callback_stream_error(UNUSED struct bufferevent *buf_event, UN } # ifdef WITH_GPIO - GPIO_SET_LOW(has_http_clients); + gpio_set_has_http_clients(false); # endif } diff --git a/src/main.c b/src/main.c index ee97b2f..e0bc8ee 100644 --- a/src/main.c +++ b/src/main.c @@ -31,6 +31,7 @@ #endif #include +#include #include #include @@ -114,10 +115,6 @@ int main(int argc, char *argv[]) { A_THREAD_RENAME("main"); options = options_init(argc, argv); -# ifdef WITH_GPIO - GPIO_INIT; -# endif - dev = device_init(); encoder = encoder_init(); stream = stream_init(dev, encoder); @@ -125,7 +122,7 @@ int main(int argc, char *argv[]) { if ((exit_code = options_parse(options, dev, encoder, server)) == 0) { # ifdef WITH_GPIO - GPIO_INIT_PINOUT; + gpio_init(); # endif _install_signal_handlers(); @@ -140,7 +137,7 @@ int main(int argc, char *argv[]) { if ((exit_code = http_server_listen(server)) == 0) { # ifdef WITH_GPIO - GPIO_SET_HIGH(prog_running); + gpio_set_prog_running(true); # endif A_THREAD_CREATE(&stream_loop_tid, _stream_loop_thread, NULL); @@ -148,6 +145,11 @@ int main(int argc, char *argv[]) { A_THREAD_JOIN(server_loop_tid); A_THREAD_JOIN(stream_loop_tid); } + +# ifdef WITH_GPIO + gpio_set_prog_running(false); + gpio_destroy(); +# endif } http_server_destroy(server); @@ -155,10 +157,6 @@ int main(int argc, char *argv[]) { encoder_destroy(encoder); device_destroy(dev); -# ifdef WITH_GPIO - GPIO_SET_LOW(prog_running); -# endif - options_destroy(options); if (exit_code == 0) { LOG_INFO("Bye-bye"); diff --git a/src/options.c b/src/options.c index 2faa85c..c0f6c95 100644 --- a/src/options.c +++ b/src/options.c @@ -103,10 +103,11 @@ enum _OPT_VALUES { _O_SERVER_TIMEOUT, #ifdef WITH_GPIO + _O_GPIO_DEVICE, + _O_GPIO_CONSUMER_PREFIX, _O_GPIO_PROG_RUNNING, _O_GPIO_STREAM_ONLINE, _O_GPIO_HAS_HTTP_CLIENTS, - _O_GPIO_WORKERS_BUSY_AT, #endif #ifdef HAS_PDEATHSIG @@ -179,10 +180,11 @@ static const struct option _LONG_OPTS[] = { {"server-timeout", required_argument, NULL, _O_SERVER_TIMEOUT}, #ifdef WITH_GPIO + {"gpio-device", required_argument, NULL, _O_GPIO_DEVICE}, + {"gpio-consumer-prefix", required_argument, NULL, _O_GPIO_CONSUMER_PREFIX}, {"gpio-prog-running", required_argument, NULL, _O_GPIO_PROG_RUNNING}, {"gpio-stream-online", required_argument, NULL, _O_GPIO_STREAM_ONLINE}, {"gpio-has-http-clients", required_argument, NULL, _O_GPIO_HAS_HTTP_CLIENTS}, - {"gpio-workers-busy-at", required_argument, NULL, _O_GPIO_WORKERS_BUSY_AT}, #endif #ifdef HAS_PDEATHSIG @@ -400,10 +402,11 @@ int options_parse(struct options_t *options, struct device_t *dev, struct encode case _O_SERVER_TIMEOUT: OPT_NUMBER("--server-timeout", server->timeout, 1, 60, 0); # ifdef WITH_GPIO - case _O_GPIO_PROG_RUNNING: OPT_NUMBER("--gpio-prog-running", gpio_pin_prog_running, 0, 256, 0); - case _O_GPIO_STREAM_ONLINE: OPT_NUMBER("--gpio-stream-online", gpio_pin_stream_online, 0, 256, 0); - case _O_GPIO_HAS_HTTP_CLIENTS: OPT_NUMBER("--gpio-has-http-clients", gpio_pin_has_http_clients, 0, 256, 0); - case _O_GPIO_WORKERS_BUSY_AT: OPT_NUMBER("--gpio-workers-busy-at", gpio_pin_workers_busy_at, 0, 256, 0); + case _O_GPIO_DEVICE: OPT_SET(gpio.path, optarg); + case _O_GPIO_CONSUMER_PREFIX: OPT_SET(gpio.consumer_prefix, optarg); + case _O_GPIO_PROG_RUNNING: OPT_NUMBER("--gpio-prog-running", gpio.prog_running.pin, 0, 256, 0); + case _O_GPIO_STREAM_ONLINE: OPT_NUMBER("--gpio-stream-online", gpio.stream_online.pin, 0, 256, 0); + case _O_GPIO_HAS_HTTP_CLIENTS: OPT_NUMBER("--gpio-has-http-clients", gpio.has_http_clients.pin, 0, 256, 0); # endif # ifdef HAS_PDEATHSIG @@ -646,11 +649,11 @@ static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_s #ifdef WITH_GPIO printf("GPIO options:\n"); printf("═════════════\n"); + printf(" --gpio-device ───── Path to GPIO character device. Default: %s.\n\n", gpio.path); + printf(" --gpio-consumer-prefix ── Consumer prefix for GPIO outputs. Default: %s.\n\n", gpio.consumer_prefix); printf(" --gpio-prog-running ───── Set 1 on GPIO pin while uStreamer is running. Default: disabled.\n\n"); printf(" --gpio-stream-online ──── Set 1 while streaming. Default: disabled\n\n"); printf(" --gpio-has-http-clients ─ Set 1 while stream has at least one client. Default: disabled.\n\n"); - printf(" --gpio-workers-busy-at ── Set 1 on (pin + N) while worker with number N has a job.\n"); - printf(" The worker's numbering starts from 0. Default: disabled\n\n"); #endif #if (defined(HAS_PDEATHSIG) || defined(WITH_SETPROCTITLE)) printf("Process options:\n"); diff --git a/src/stream.c b/src/stream.c index 41e3ef6..4961849 100644 --- a/src/stream.c +++ b/src/stream.c @@ -185,7 +185,7 @@ void stream_loop(struct stream_t *stream) { } else if (selected == 0) { # ifdef WITH_GPIO - GPIO_SET_LOW(stream_online); + gpio_set_stream_online(false); # endif if (stream->dev->persistent) { @@ -207,7 +207,7 @@ void stream_loop(struct stream_t *stream) { LOG_DEBUG("Frame is ready"); # ifdef WITH_GPIO - GPIO_SET_HIGH(stream_online); + gpio_set_stream_online(true); # endif int buf_index; @@ -288,7 +288,7 @@ void stream_loop(struct stream_t *stream) { device_close(stream->dev); # ifdef WITH_GPIO - GPIO_SET_LOW(stream_online); + gpio_set_stream_online(false); # endif } } @@ -431,17 +431,9 @@ static void *_worker_thread(void *v_worker) { A_THREAD_RENAME("worker-%u", worker->number); LOG_DEBUG("Hello! I am a worker #%u ^_^", worker->number); -# ifdef WITH_GPIO - GPIO_INIT_PIN(workers_busy_at, worker->number); -# endif - while (!atomic_load(worker->proc_stop) && !atomic_load(worker->workers_stop)) { LOG_DEBUG("Worker %u waiting for a new job ...", worker->number); -# ifdef WITH_GPIO - GPIO_SET_LOW_AT(workers_busy_at, worker->number); -# endif - A_MUTEX_LOCK(&worker->has_job_mutex); A_COND_WAIT_TRUE(atomic_load(&worker->has_job), &worker->has_job_cond, &worker->has_job_mutex); A_MUTEX_UNLOCK(&worker->has_job_mutex); @@ -451,10 +443,6 @@ static void *_worker_thread(void *v_worker) { LOG_DEBUG("Worker %u compressing JPEG from buffer %u ...", worker->number, worker->buf_index); -# ifdef WITH_GPIO - GPIO_SET_HIGH_AT(workers_busy_at, worker->number); -# endif - worker->job_failed = (bool)encoder_compress_buffer(worker->encoder, worker->dev, worker->number, worker->buf_index); if (device_release_buffer(worker->dev, worker->buf_index) == 0) { @@ -483,9 +471,6 @@ static void *_worker_thread(void *v_worker) { } LOG_DEBUG("Bye-bye (worker %u)", worker->number); -# ifdef WITH_GPIO - GPIO_SET_LOW_AT(workers_busy_at, worker->number); -# endif return NULL; }