Browse Source

Implement flash LED/V4L support, LED being copied partially from Megapixels

Kristian Vos 1 month ago
parent
commit
db0315f5ea
8 changed files with 156 additions and 4 deletions
  1. 1 1
      CMakeLists.txt
  2. 0 1
      config/pine64,pinephone-pro.conf
  3. 6 0
      include/libmegapixels.h
  4. 1 0
      meson.build
  5. 119 0
      src/flash.c
  6. 5 0
      src/flash.h
  7. 11 2
      src/parse.c
  8. 13 0
      src/pipeline.c

+ 1 - 1
CMakeLists.txt

@@ -7,7 +7,7 @@ set(LIBRARY_VERSION_STRING 0.1)
 set(CMAKE_C_STANDARD 23)
 set(CMAKE_C_VISIBILITY_PRESET hidden)
 
-add_library(megapixels SHARED include/libmegapixels.h src/findconfig.c src/parse.c src/mode.c src/pipeline.c src/log.c src/util.c src/convert.c src/aaa.c config.h)
+add_library(megapixels SHARED include/libmegapixels.h src/findconfig.c src/parse.c src/mode.c src/pipeline.c src/log.c src/util.c src/convert.c src/aaa.c src/flash.c config.h)
 set_target_properties(megapixels PROPERTIES
         VERSION ${LIBRARY_VERSION_STRING}
         SOVERSION ${LIBRARY_VERSION_MAJOR}

+ 0 - 1
config/pine64,pinephone-pro.conf

@@ -5,7 +5,6 @@ Model: "PinePhone Pro";
 Rear: {
     SensorDriver: "imx258";
     BridgeDriver: "rkisp1";
-    FlashPath: "/sys/class/leds/white:flash";
 
     Modes: (
         {

+ 6 - 0
include/libmegapixels.h

@@ -204,4 +204,10 @@ libmegapixels_aaa_set_matrix(libmegapixels_aaa_stats *stats, const float matrix1
 EXPORT void
 libmegapixels_aaa_software_statistics(libmegapixels_aaa_stats *stats, const unsigned int *frame, int width, int height);
 
+EXPORT void
+libmegapixels_flash_on(libmegapixels_camera *camera);
+
+EXPORT void
+libmegapixels_flash_off(libmegapixels_camera *camera);
+
 #endif

+ 1 - 0
meson.build

@@ -32,6 +32,7 @@ lib_src = [
     'src/parse.c',
     'src/pipeline.c',
     'src/aaa.c',
+    'src/flash.c',
 ]
 libmegapixels = shared_library('megapixels', lib_src,
     version: libmegapixels_so_version,

+ 119 - 0
src/flash.c

@@ -0,0 +1,119 @@
+#include <libmegapixels.h>
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/media.h>
+#include <linux/v4l2-subdev.h>
+
+#include "flash.h"
+#include "util.h"
+#include "log.h"
+
+// Copied from drivers/media/v4l2-core/v4l2-ctrls-defs.c, trimmed down
+const char
+*v4l2_ctrl_get_name(unsigned int id)
+{
+    switch (id) {
+    case V4L2_CID_FLASH_LED_MODE:		return "LED Mode";
+    case V4L2_CID_FLASH_STROBE_SOURCE:	return "Strobe Source";
+    case V4L2_CID_FLASH_STROBE:		    return "Strobe";
+    default:                            return "Unknown";
+    }
+}
+
+// Copied from drivers/media/v4l2-core/v4l2-ctrls-defs.c, trimmed down and slightly modified
+const char
+*v4l2_ctrl_get_menu_value(unsigned int id, signed int val)
+{
+    static const char * const flash_led_mode[] = {
+		"Off",
+		"Flash",
+		"Torch",
+		NULL,
+	};
+    static const char * const flash_strobe_source[] = {
+		"Software",
+		"External",
+		NULL,
+	};
+
+    switch (id) {
+    case V4L2_CID_FLASH_LED_MODE:
+		return flash_led_mode[val];
+    case V4L2_CID_FLASH_STROBE_SOURCE:
+		return flash_strobe_source[val];
+    default:
+        return "None/Unknown";
+    }
+}
+
+// Set a control value, but ignore if it fails
+void
+set_control(int flash_fd, unsigned int ctrl_id, signed int ctrl_val)
+{
+    struct v4l2_control ctrl;
+    ctrl.id = ctrl_id;
+    ctrl.value = ctrl_val;
+    int res = xioctl(flash_fd, VIDIOC_S_CTRL, &ctrl);
+    if (res == -1) {
+        log_debug(
+            "Failed to set %s to %s for flash.\n",
+            v4l2_ctrl_get_name(ctrl_id),
+            v4l2_ctrl_get_menu_value(ctrl_id, ctrl_val)
+        );
+    }
+}
+
+// Flash path is used for both the V4L path, and the LED path, and can be overwritten by a later stage, so memory is first freed
+void
+libmegapixels_flash_cleanup_flash_path(libmegapixels_camera *camera)
+{
+    if (camera->flash_path != NULL) {
+        free(camera->flash_path);
+        camera->flash_path = NULL;
+    }
+}
+
+// Given the LED path (e.g., /sys/class/leds/white:flash), it'll append /flash_strobe at the end
+char *
+libmegapixels_flash_get_led_path(const char *path)
+{
+    char *result = malloc(275);
+    if (result == NULL) {
+        return NULL;
+    }
+
+    snprintf(result, 275, "%s/flash_strobe", path);
+
+    return result;
+}
+
+// Turns on the LED/V4L flash/strobe
+void
+libmegapixels_flash_on(libmegapixels_camera *camera)
+{
+    if (camera->flash_type == LIBMEGAPIXELS_FLASH_LED) {
+        lseek(camera->flash_fd, 0, SEEK_SET);
+        dprintf(camera->flash_fd, "1\n");
+    } else if (camera->flash_type == LIBMEGAPIXELS_FLASH_V4L) {
+        // Mode must be flash, and strobe source must be software, for strobe to be possible
+        // Strobe source may not exist, which is fine, we ignore the result
+        set_control(camera->flash_fd, V4L2_CID_FLASH_LED_MODE, V4L2_FLASH_LED_MODE_FLASH);
+        set_control(camera->flash_fd, V4L2_CID_FLASH_STROBE_SOURCE, V4L2_FLASH_STROBE_SOURCE_SOFTWARE);
+
+        // Starts the flash strobe. It will automatically stop
+        set_control(camera->flash_fd, V4L2_CID_FLASH_STROBE, 1);
+    }
+}
+
+// Turns off the LED/V4L flash/strobe, where applicable
+void
+libmegapixels_flash_off(libmegapixels_camera *camera)
+{
+    // Neither LED nor V4L currently needs any action in here, but in the future those or a different method may need to turn flash off here
+    // For example, if flash strobe doesn't work, and we need to manually turn on/off torch mode
+}

+ 5 - 0
src/flash.h

@@ -0,0 +1,5 @@
+#include <libmegapixels.h>
+
+char *libmegapixels_flash_get_led_path(const char *path);
+
+void libmegapixels_flash_cleanup_flash_path(libmegapixels_camera *camera);

+ 11 - 2
src/parse.c

@@ -15,6 +15,7 @@
 #include "mode.h"
 #include "util.h"
 #include "log.h"
+#include "flash.h"
 
 char *
 find_path_for_devnode(struct media_v2_intf_devnode devnode)
@@ -265,14 +266,22 @@ load_camera(libmegapixels_devconfig *config, config_t *cfg, const char *name, in
 	config->cameras[config->count++] = camera;
 
 	if (config_setting_lookup_string(root, "FlashPath", &flashpath)) {
-		camera->flash_path = strdup(flashpath);
 		camera->flash_type = LIBMEGAPIXELS_FLASH_LED;
+		libmegapixels_flash_cleanup_flash_path(camera);
+		camera->flash_path = libmegapixels_flash_get_led_path(flashpath);
+
+		if (camera->flash_path == NULL) {
+			log_error("Failed to get LED flash path\n");
+			return -1;
+		}
 	}
+
+	// You do not need to set FlashDisplay in device config files, unless for some reason there's a V4L flash device that isn't meant to be there
 	int flashDisplay = 0;
 	if (config_setting_lookup_bool(root, "FlashDisplay", &flashDisplay)) {
 		if (flashDisplay) {
-			camera->flash_path = NULL;
 			camera->flash_type = LIBMEGAPIXELS_FLASH_SCREEN;
+			libmegapixels_flash_cleanup_flash_path(camera);
 		}
 	}
 

+ 13 - 0
src/pipeline.c

@@ -151,6 +151,15 @@ libmegapixels_open(libmegapixels_camera *camera)
 		}
 	}
 
+	// Flash path can be either the v4l device path, or the /sys/class/leds/... path
+	if (camera->flash_path) {
+		camera->flash_fd = open(camera->flash_path, O_RDWR);
+		if (camera->flash_fd < 0) {
+			log_error("Could not open %s: %s\n", camera->flash_path, strerror(errno));
+			return -1;
+		}
+	}
+
 	camera->video_fd = open(camera->video_path, O_RDWR);
 	if (camera->video_fd < 0) {
 		log_error("Could not open %s: %s\n", camera->video_path, strerror(errno));
@@ -195,6 +204,10 @@ libmegapixels_close(libmegapixels_camera *camera)
 		close(camera->video_fd);
 		camera->video_fd = 0;
 	}
+	if (camera->flash_fd != 0) {
+		close(camera->flash_fd);
+		camera->flash_fd = 0;
+	}
 
 	for (int i = 0; i < camera->num_handles; i++) {
 		if (camera->handles[i]->fd != 0) {