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 0e3af3f..f7acaca 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@
| Streaming via UNIX domain socket |  Yes |  No |
| Debug logs without recompiling,
performance statistics log,
access to HTTP streaming parameters |  Yes |  No |
| Option to serve files
with a built-in HTTP server |  Yes |  Regular files only |
-| Signaling about the stream state to GPIO
on Raspberry Pi using [wiringPi](http://wiringpi.com) |  Yes |  No |
+| Signaling about the stream state to GPIO using [libgpiod](https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/about) |  Yes |  No |
| Access to webcam controls (focus, servos)
and settings such as brightness via HTTP |  No |  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 d7dff3c..d5c9964 100644
--- a/README.ru.md
+++ b/README.ru.md
@@ -19,7 +19,7 @@
| Стрим через UNIX domain socket |  Есть |  Нет |
| Дебаг-логи без перекомпиляции,
логгирование статистики производительности,
возможность получения параметров
трансляции по HTTP |  Есть |  Нет |
| Возможность сервить файлы встроенным
HTTP-сервером |  Есть |  Нет каталогов |
-| Вывод сигналов о состоянии стрима на GPIO
на Raspberry Pi с помощью [wiringPi](http://wiringpi.com) |  Есть |  Нет |
+| Вывод сигналов о состоянии стрима на GPIO
с помощью [libgpiod](https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/about) |  Есть |  Нет |
| Поддержка контролов веб-камер (фокус,
движение сервами) и всяких настроек,
типа яркости, через HTTP |  Нет |  Есть |
Сносочки:
@@ -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 c337818..6b51ba3 100644
--- a/src/http/server.c
+++ b/src/http/server.c
@@ -537,7 +537,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
}
@@ -711,7 +711,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;
}