|
@@ -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
|
|
|
+}
|