From 338f492ac3f1211fe32afcca6e2486c6a6e640e1 Mon Sep 17 00:00:00 2001 From: Randy Mackay Date: Mon, 11 Sep 2023 15:37:16 +0900 Subject: [PATCH] Tools: add xacti-config application This allows configuring the Xacti cameras from the command line --- .../xacti-config/CX-GBXXXCtrl.cpp | 142 ++++++++++++++++++ .../xacti-config/CX-GBXXXCtrl.h | 40 +++++ Tools/cameras_gimbals/xacti-config/Makefile | 48 ++++++ Tools/cameras_gimbals/xacti-config/README | 23 +++ Tools/cameras_gimbals/xacti-config/main.cpp | 99 ++++++++++++ 5 files changed, 352 insertions(+) create mode 100644 Tools/cameras_gimbals/xacti-config/CX-GBXXXCtrl.cpp create mode 100644 Tools/cameras_gimbals/xacti-config/CX-GBXXXCtrl.h create mode 100644 Tools/cameras_gimbals/xacti-config/Makefile create mode 100644 Tools/cameras_gimbals/xacti-config/README create mode 100644 Tools/cameras_gimbals/xacti-config/main.cpp diff --git a/Tools/cameras_gimbals/xacti-config/CX-GBXXXCtrl.cpp b/Tools/cameras_gimbals/xacti-config/CX-GBXXXCtrl.cpp new file mode 100644 index 0000000000..88325f17f1 --- /dev/null +++ b/Tools/cameras_gimbals/xacti-config/CX-GBXXXCtrl.cpp @@ -0,0 +1,142 @@ +// ============================================================================= +/** + * @file CX-GBXXXCtrl.cpp + * @brief CX-GBXXX用コントロールクラス ヘッダ + * @copyright (c) 2022 Xacti Corporation + */ +// ============================================================================= + +#include "CX-GBXXXCtrl.h" +#include +#include +#include + +// ----------------------------------------------------------------------------- +/*! + * @brief CX_GBXXXCtrlコンストラクタ + */ +// ----------------------------------------------------------------------------- +CX_GBXXXCtrl::CX_GBXXXCtrl() + : m_ctx(NULL), m_dev(NULL), m_devh(NULL) +{ + uvc_error_t res = uvc_init(&m_ctx, NULL); + if (res < 0) + { + uvc_perror(res, "uvc_init"); + assert(res == 0); + } +} + +// ----------------------------------------------------------------------------- +/*! + * @brief CX_GBXXXCtrlデストラクタ + */ +// ----------------------------------------------------------------------------- +CX_GBXXXCtrl::~CX_GBXXXCtrl() +{ + uvc_exit(m_ctx); +} + +// ----------------------------------------------------------------------------- +/*! + * @brief カメラオープン + * + * @param [in] callback カメラシリアル番号(NULL: Don't Care) + * + * @return オープン成功可否 + */ +// ----------------------------------------------------------------------------- +bool CX_GBXXXCtrl::Open(const char *serial) +{ + uvc_error_t res; + if ((res = uvc_find_device( + m_ctx, &m_dev, + 0x296b, 0, serial)) < 0) + { + uvc_perror(res, "uvc_find_device"); // CX-GBXXX未接続 + return false; + } + + if ((res = uvc_open(m_dev, &m_devh)) < 0) + { + uvc_perror(res, "uvc_open"); + return false; + } + + return true; +} + +// ----------------------------------------------------------------------------- +/*! + * @brief カメラクローズ + */ +// ----------------------------------------------------------------------------- +void CX_GBXXXCtrl::Close() +{ + if (m_devh) + { + uvc_close(m_devh); + } + if (m_dev) + { + uvc_unref_device(m_dev); + } +} + +// ----------------------------------------------------------------------------- +/*! + * @brief カメラ情報設定 + * + * @param [in] unit_id ユニットID + * @param [in] cotrol_id コントロールID + * @param [in] data データバッファ + * @param [in] length データサイズ(バイト) + * + * @return 成功可否 + */ +// ----------------------------------------------------------------------------- +bool CX_GBXXXCtrl::SetCameraCtrl(uint8_t unit_id, uint8_t cotrol_id, void *data, int length) +{ + if (!m_devh) + { + uvc_perror(UVC_ERROR_INVALID_DEVICE, "SetCameraCtrl"); + return false; + } + + if (uvc_set_ctrl(m_devh, unit_id, cotrol_id, data, length) != length) + { + uvc_perror(UVC_ERROR_OTHER, "SetCameraCtrl"); + return false; + } + + return true; +} + +// ----------------------------------------------------------------------------- +/*! + * @brief カメラ情報取得 + * + * @param [in] unit_id ユニットID + * @param [in] cotrol_id コントロールID + * @param [out] data データバッファ + * @param [in] length データサイズ(バイト) + * + * @return 成功可否 + */ +// ----------------------------------------------------------------------------- +bool CX_GBXXXCtrl::GetCameraCtrl(uint8_t unit_id, uint8_t cotrol_id, void *data, int length) +{ + if (!m_devh) + { + uvc_perror(UVC_ERROR_INVALID_DEVICE, "GetCameraCtrl"); + return false; + } + + if (uvc_get_ctrl(m_devh, unit_id, cotrol_id, data, length, UVC_GET_CUR) != length) + { + uvc_perror(UVC_ERROR_OTHER, "GetCameraCtrl"); + return false; + } + + return true; +} diff --git a/Tools/cameras_gimbals/xacti-config/CX-GBXXXCtrl.h b/Tools/cameras_gimbals/xacti-config/CX-GBXXXCtrl.h new file mode 100644 index 0000000000..ee08e3a804 --- /dev/null +++ b/Tools/cameras_gimbals/xacti-config/CX-GBXXXCtrl.h @@ -0,0 +1,40 @@ +// ============================================================================= +/** + * @file CX-GBXXXCtrl.h + * @brief CX-GBXXX用コントロールクラス ヘッダ + * @copyright (c) 2022 Xacti Corporation + */ +// ============================================================================= + +#pragma once + +#include + +struct uvc_context; +typedef struct uvc_context uvc_context_t; +struct uvc_device; +typedef struct uvc_device uvc_device_t; +struct uvc_device_handle; +typedef struct uvc_device_handle uvc_device_handle_t; +struct uvc_frame; +typedef struct uvc_frame uvc_frame_t; + +/*! @brief CCX_GBXXX用コントロールクラス */ +class CX_GBXXXCtrl +{ +public: + CX_GBXXXCtrl(); + virtual ~CX_GBXXXCtrl(); + bool Open(const char *serial); + void Close(); + + //! カメラコマンド + bool SetCameraCtrl(uint8_t unit_id, uint8_t cotrol_id, void *data, int length); + bool GetCameraCtrl(uint8_t unit_id, uint8_t cotrol_id, void *data, int length); + +private: + + uvc_context_t *m_ctx; + uvc_device_t *m_dev; + uvc_device_handle_t *m_devh; +}; diff --git a/Tools/cameras_gimbals/xacti-config/Makefile b/Tools/cameras_gimbals/xacti-config/Makefile new file mode 100644 index 0000000000..1cca5c12cc --- /dev/null +++ b/Tools/cameras_gimbals/xacti-config/Makefile @@ -0,0 +1,48 @@ +################################################################################ +# Copyright (c) 2022, Xacti Corporation. All rights reserved. +# Modified by Randy Mackay +################################################################################ + +APP:= xacti-config +CC = g++ + +# Optimisation Options +# +CFLAGOPT = +CFLAGOPT += -O0 + +SRCS:= $(wildcard *.c) $(wildcard *.cpp) + +INCS:= $(wildcard *.h) + +PKGS:= x11 + +OBJS:= $(SRCS:.c=.o) +OBJS:= $(OBJS:.cpp=.o) + +CFLAGS+= -g +CFLAGS+= $(CFLAGOPT) + +LIBS+= -lm \ + -Wl,-rpath \ + -lpthread -pthread -luvc + +CFLAGS+= `pkg-config --cflags $(PKGS)` + +LIBS+= `pkg-config --libs $(PKGS)` + +all: $(APP) + +%.o: %.c $(INCS) Makefile + $(CC) -c -o $@ $(CFLAGS) $< +%.o: %.cpp $(INCS) Makefile + $(CC) -c -o $@ $(CFLAGS) $< + +$(APP): $(OBJS) Makefile + $(CC) -o $(APP) $(OBJS) $(LIBS) + +clean: + rm -rf $(OBJS) $(APP) + +exec: + ./$(APP) diff --git a/Tools/cameras_gimbals/xacti-config/README b/Tools/cameras_gimbals/xacti-config/README new file mode 100644 index 0000000000..364e6f16d5 --- /dev/null +++ b/Tools/cameras_gimbals/xacti-config/README @@ -0,0 +1,23 @@ +******************** + xacti-config + README +******************** + +Install Instructions + +- download this program to your Linux/Ubuntu PC +- sudo apt-get install libusb-1.0-0-dev +- sudo apt install libuvc-dev +- make + +Execution instructions + +- sudo xacti-config option [value] +- the following options are available + --dronecan enable (value=1) or disable (value=0) dronecan parsing + --format format SD card + --help display usage + --irpalette set IR pallete (0:white hot, 1:black hot, 2:rainbow, 3:rainHC, 4:ironbow, 5:lava, 6:arctic, 7:glowbow, 8:graded fire, 9:hottest) + --msc change to mass storage class mode (for downloading from SD card) + + diff --git a/Tools/cameras_gimbals/xacti-config/main.cpp b/Tools/cameras_gimbals/xacti-config/main.cpp new file mode 100644 index 0000000000..8977bf569c --- /dev/null +++ b/Tools/cameras_gimbals/xacti-config/main.cpp @@ -0,0 +1,99 @@ +#include +#include +#include +#include "CX-GBXXXCtrl.h" + +const char* this_app_str = "xacti-config"; + +// display help +void display_help() +{ + printf("Usage: sudo %s option [value]\n", this_app_str); + printf(" --dronecan\tenable (value=1) or disable (value=0) dronecan parsing\n"); + printf(" --format\tformat SD card\n"); + printf(" --help\t\tdisplay usage\n"); + printf(" --irpalette\t\tIR pallete (0:white hot, 1:black hot, 2:rainbow, 3:rainHC, 4:ironbow, 5:lava, 6:arctic, 7:glowbow, 8:graded fire, 9:hottest)\n"); + printf(" --msc\t\tchange to mass storage class mode (for downloading from SD card)\n"); +} + +int main(int argc, char **argv) +{ + // display help + if ((argc <= 1) || ((argc >= 2) && (strcmp(argv[1], "--help") == 0))) { + display_help(); + return 0; + } + + // open camera + CX_GBXXXCtrl camera_ctrl; + if (!camera_ctrl.Open(NULL)) { + printf("%s: failed to open camera\n", this_app_str); + return 1; + } + + // args_ok set to true when command line processed correctly + bool args_ok = false; + bool ret_ok = true; + + // enable DroneCAN + if ((argc >= 3) && (strcmp(argv[1], "--dronecan") == 0)) { + args_ok = true; + uint8_t enable = (strcmp(argv[2], "1") == 0); + ret_ok = camera_ctrl.SetCameraCtrl(0x07, 0x1e, &enable, sizeof(enable)); + const char* enable_or_disable_str = enable ? "enable" : "disable"; + if (ret_ok) { + printf("%s: %s DroneCAN\n", this_app_str, enable_or_disable_str); + } else { + printf("%s: failed to %s DroneCAN\n", this_app_str, enable_or_disable_str); + } + } + + // format SD card + if ((argc >= 2) && (strcmp(argv[1], "--format") == 0)) { + args_ok = true; + uint8_t format_sd = 0; + ret_ok = camera_ctrl.SetCameraCtrl(0x07, 0x15, &format_sd, sizeof(format_sd)); + if (ret_ok) { + printf("%s: formatted SD card\n", this_app_str); + } else { + printf("%s: failed format SD card\n", this_app_str); + } + } + + // IR palette + if ((argc >= 3) && (strcmp(argv[1], "--irpalette") == 0)) { + args_ok = true; + int palette_int = 0; + sscanf(argv[2], "%d", &palette_int); + uint8_t palette_uint8 = (uint8_t)palette_int; + ret_ok = camera_ctrl.SetCameraCtrl(0x07, 0x19, &palette_uint8, sizeof(palette_uint8)); + if (ret_ok) { + printf("%s: IR palette set to %d\n", this_app_str, (int)palette_uint8); + } else { + printf("%s: failed to set IR palette to %d\n", this_app_str, (int)palette_uint8); + } + } + + // change to Mass Storage Mode to allow downloading of images and videos + if ((argc >= 2) && (strcmp(argv[1], "--msc") == 0)) { + args_ok = true; + uint8_t msc_mode = 1; + ret_ok = camera_ctrl.SetCameraCtrl(0x06, 0x07, &msc_mode, sizeof(msc_mode)); + if (ret_ok) { + printf("%s: changed to mass storage mode\n", this_app_str); + } else { + printf("%s: failed to change to mass storage mode\n", this_app_str); + } + } + + // close camera + camera_ctrl.Close(); + + // display help if args could not be processed + if (!args_ok) { + display_help(); + } + + // return 0 if OK, 1 if not OK + return ret_ok ? 0 : 1; +}