summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames McKenzie <root@ka-ata-killa.panaceas.james.local>2022-11-27 08:06:02 +0000
committerJames McKenzie <root@ka-ata-killa.panaceas.james.local>2022-11-27 08:06:02 +0000
commit2ba3c5bbf6f8c182c92bfaaf120a8b07937f53f7 (patch)
tree248c3eb1dadff3a7a4d660e9b9ea5a930f3b4e31
downloadindi_mount_driver-2ba3c5bbf6f8c182c92bfaaf120a8b07937f53f7.tar.gz
indi_mount_driver-2ba3c5bbf6f8c182c92bfaaf120a8b07937f53f7.tar.bz2
indi_mount_driver-2ba3c5bbf6f8c182c92bfaaf120a8b07937f53f7.zip
first
-rw-r--r--.gitignore6
-rw-r--r--cmake_modules/CMakeCommon.cmake128
-rw-r--r--cmake_modules/CMakeParseArguments.cmake21
-rw-r--r--cmake_modules/FindAHPXC.cmake50
-rw-r--r--cmake_modules/FindAIOUSB.cmake61
-rw-r--r--cmake_modules/FindALTAIRCAM.cmake49
-rw-r--r--cmake_modules/FindALUT.cmake77
-rw-r--r--cmake_modules/FindAPOGEE.cmake53
-rw-r--r--cmake_modules/FindARAVIS.cmake43
-rw-r--r--cmake_modules/FindASI.cmake74
-rw-r--r--cmake_modules/FindATIK.cmake49
-rw-r--r--cmake_modules/FindCFITSIO.cmake65
-rw-r--r--cmake_modules/FindD2XX.cmake56
-rw-r--r--cmake_modules/FindDC1394.cmake50
-rw-r--r--cmake_modules/FindFFTW3.cmake52
-rw-r--r--cmake_modules/FindFFmpeg.cmake213
-rw-r--r--cmake_modules/FindFISHCAMP.cmake54
-rw-r--r--cmake_modules/FindFLI.cmake53
-rw-r--r--cmake_modules/FindFTDI.cmake54
-rw-r--r--cmake_modules/FindFTDI1.cmake56
-rw-r--r--cmake_modules/FindGLIB2.cmake218
-rw-r--r--cmake_modules/FindGMock.cmake184
-rw-r--r--cmake_modules/FindGPHOTO2.cmake66
-rw-r--r--cmake_modules/FindGPSD.cmake19
-rw-r--r--cmake_modules/FindGSL.cmake238
-rw-r--r--cmake_modules/FindINDI.cmake320
-rw-r--r--cmake_modules/FindINOVASDK.cmake50
-rw-r--r--cmake_modules/FindIconv.cmake81
-rw-r--r--cmake_modules/FindJPEG.cmake28
-rw-r--r--cmake_modules/FindLIMESUITE.cmake52
-rw-r--r--cmake_modules/FindLibRaw.cmake79
-rw-r--r--cmake_modules/FindMALLINCAM.cmake49
-rw-r--r--cmake_modules/FindMEADE.cmake47
-rw-r--r--cmake_modules/FindMICAM.cmake49
-rw-r--r--cmake_modules/FindMMAL.cmake45
-rw-r--r--cmake_modules/FindMODBUS.cmake56
-rw-r--r--cmake_modules/FindNNCAM.cmake49
-rw-r--r--cmake_modules/FindNUTClient.cmake50
-rw-r--r--cmake_modules/FindNova.cmake55
-rw-r--r--cmake_modules/FindOMEGONPROCAM.cmake50
-rw-r--r--cmake_modules/FindOggTheora.cmake47
-rw-r--r--cmake_modules/FindOpenAL.cmake100
-rw-r--r--cmake_modules/FindPENTAX.cmake86
-rw-r--r--cmake_modules/FindPLAYERONE.cmake56
-rw-r--r--cmake_modules/FindPackageHandleStandardArgs.cmake396
-rw-r--r--cmake_modules/FindPackageMessage.cmake57
-rw-r--r--cmake_modules/FindQHY.cmake50
-rw-r--r--cmake_modules/FindQSI.cmake50
-rw-r--r--cmake_modules/FindRT.cmake39
-rw-r--r--cmake_modules/FindSBIG.cmake50
-rw-r--r--cmake_modules/FindSTARSHOOTG.cmake49
-rw-r--r--cmake_modules/FindSV305.cmake52
-rw-r--r--cmake_modules/FindTIFFXX.cmake41
-rw-r--r--cmake_modules/FindTOUPCAM.cmake50
-rw-r--r--cmake_modules/FindUSB1.cmake83
-rw-r--r--cmake_modules/FindVorbis.cmake32
-rw-r--r--cmake_modules/InstallImported.cmake92
-rw-r--r--cmake_modules/UnityBuild.cmake158
-rw-r--r--indi-celestronaux/.gitignore1
-rw-r--r--indi-celestronaux/CMakeLists.txt33
-rw-r--r--indi-celestronaux/README.md102
-rw-r--r--indi-celestronaux/auxproto.cpp467
-rw-r--r--indi-celestronaux/auxproto.h169
-rw-r--r--indi-celestronaux/celestronaux.cpp2907
-rw-r--r--indi-celestronaux/celestronaux.h442
-rw-r--r--indi-celestronaux/config.h.cmake10
-rw-r--r--indi-celestronaux/indi-celestronaux.spec79
-rw-r--r--indi-celestronaux/indi_celestronaux.xml.cmake33
-rw-r--r--indi-celestronaux/simulator/nse_simulator.py259
-rw-r--r--indi-celestronaux/simulator/nse_telescope.py760
70 files changed, 9799 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2206af6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+indi-celestronaux/CMakeCache.txt
+indi-celestronaux/CMakeFiles/
+indi-celestronaux/Makefile
+indi-celestronaux/cmake_install.cmake
+indi-celestronaux/config.h
+indi-celestronaux/indi_celestronaux.xml
diff --git a/cmake_modules/CMakeCommon.cmake b/cmake_modules/CMakeCommon.cmake
new file mode 100644
index 0000000..b7be23d
--- /dev/null
+++ b/cmake_modules/CMakeCommon.cmake
@@ -0,0 +1,128 @@
+
+include(CheckCCompilerFlag)
+
+#IF (NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
+ #SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
+ #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+#ENDIF ()
+
+# C++14 Support
+if (NOT ANDROID)
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+endif(NOT ANDROID)
+
+# Position Independent Code
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+# Ccache support
+IF (ANDROID OR UNIX OR APPLE)
+ FIND_PROGRAM(CCACHE_FOUND ccache)
+ SET(CCACHE_SUPPORT OFF CACHE BOOL "Enable ccache support")
+ IF ((CCACHE_FOUND OR ANDROID) AND CCACHE_SUPPORT MATCHES ON)
+ SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
+ SET_PROPERTY(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
+ ENDIF ()
+ENDIF ()
+
+# Add security (hardening flags)
+IF (UNIX OR APPLE OR ANDROID)
+ # Older compilers are predefining _FORTIFY_SOURCE, so defining it causes a
+ # warning, which is then considered an error. Second issue is that for
+ # these compilers, _FORTIFY_SOURCE must be used while optimizing, else
+ # causes a warning, which also results in an error. And finally, CMake is
+ # not using optimization when testing for libraries, hence breaking the build.
+ CHECK_C_COMPILER_FLAG("-Werror -D_FORTIFY_SOURCE=2" COMPATIBLE_FORTIFY_SOURCE)
+ IF (${COMPATIBLE_FORTIFY_SOURCE})
+ SET(SEC_COMP_FLAGS "-D_FORTIFY_SOURCE=2")
+ ENDIF ()
+ SET(SEC_COMP_FLAGS "${SEC_COMP_FLAGS} -fstack-protector-all -fPIE")
+ # Make sure to add optimization flag. Some systems require this for _FORTIFY_SOURCE.
+ IF (NOT CMAKE_BUILD_TYPE MATCHES "MinSizeRel" AND NOT CMAKE_BUILD_TYPE MATCHES "Release" AND NOT CMAKE_BUILD_TYPE MATCHES "Debug")
+ SET(SEC_COMP_FLAGS "${SEC_COMP_FLAGS} -O1")
+ ENDIF ()
+ IF (NOT ANDROID AND NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND NOT APPLE AND NOT CYGWIN)
+ SET(SEC_COMP_FLAGS "${SEC_COMP_FLAGS} -Wa,--noexecstack")
+ ENDIF ()
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SEC_COMP_FLAGS}")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SEC_COMP_FLAGS}")
+ SET(SEC_LINK_FLAGS "")
+ IF (NOT APPLE AND NOT CYGWIN)
+ SET(SEC_LINK_FLAGS "${SEC_LINK_FLAGS} -Wl,-z,nodump -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now")
+ ENDIF ()
+ IF (NOT ANDROID AND NOT APPLE)
+ SET(SEC_LINK_FLAGS "${SEC_LINK_FLAGS} -pie")
+ ENDIF ()
+ SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SEC_LINK_FLAGS}")
+ SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${SEC_LINK_FLAGS}")
+ENDIF ()
+
+# Warning, debug and linker flags
+SET(FIX_WARNINGS OFF CACHE BOOL "Enable strict compilation mode to turn compiler warnings to errors")
+IF (UNIX OR APPLE)
+ SET(COMP_FLAGS "")
+ SET(LINKER_FLAGS "")
+ # Verbose warnings and turns all to errors
+ SET(COMP_FLAGS "${COMP_FLAGS} -Wall -Wextra")
+ IF (FIX_WARNINGS)
+ SET(COMP_FLAGS "${COMP_FLAGS} -Werror")
+ ENDIF ()
+ # Omit problematic warnings
+ IF ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+ SET(COMP_FLAGS "${COMP_FLAGS} -Wno-unused-but-set-variable")
+ ENDIF ()
+ IF ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 6.9.9)
+ SET(COMP_FLAGS "${COMP_FLAGS} -Wno-format-truncation")
+ ENDIF ()
+ IF ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
+ SET(COMP_FLAGS "${COMP_FLAGS} -Wno-nonnull -Wno-deprecated-declarations")
+ ENDIF ()
+
+ # Minimal debug info with Clang
+ IF ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ SET(COMP_FLAGS "${COMP_FLAGS} -gline-tables-only")
+ ELSE ()
+ SET(COMP_FLAGS "${COMP_FLAGS} -g")
+ ENDIF ()
+
+ # Note: The following flags are problematic on older systems with gcc 4.8
+ IF ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.9.9))
+ IF ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
+ SET(COMP_FLAGS "${COMP_FLAGS} -Wno-unused-command-line-argument")
+ ENDIF ()
+ FIND_PROGRAM(LDGOLD_FOUND ld.gold)
+ SET(LDGOLD_SUPPORT OFF CACHE BOOL "Enable ld.gold support")
+ # Optional ld.gold is 2x faster than normal ld
+ IF (LDGOLD_FOUND AND LDGOLD_SUPPORT MATCHES ON AND NOT APPLE AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES arm)
+ SET(LINKER_FLAGS "${LINKER_FLAGS} -fuse-ld=gold")
+ # Use Identical Code Folding
+ SET(COMP_FLAGS "${COMP_FLAGS} -ffunction-sections")
+ SET(LINKER_FLAGS "${LINKER_FLAGS} -Wl,--icf=safe")
+ # Compress the debug sections
+ # Note: Before valgrind 3.12.0, patch should be applied for valgrind (https://bugs.kde.org/show_bug.cgi?id=303877)
+ IF (NOT APPLE AND NOT ANDROID AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES arm AND NOT CMAKE_CXX_CLANG_TIDY)
+ SET(COMP_FLAGS "${COMP_FLAGS} -Wa,--compress-debug-sections")
+ SET(LINKER_FLAGS "${LINKER_FLAGS} -Wl,--compress-debug-sections=zlib")
+ ENDIF ()
+ ENDIF ()
+ ENDIF ()
+
+ # Apply the flags
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COMP_FLAGS}")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMP_FLAGS}")
+ SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
+ SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
+ENDIF ()
+
+# Sanitizer support
+SET(CLANG_SANITIZERS OFF CACHE BOOL "Clang's sanitizer support")
+IF (CLANG_SANITIZERS AND
+ ((UNIX AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") OR (APPLE AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")))
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address,undefined -fno-omit-frame-pointer")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,undefined -fno-omit-frame-pointer")
+ SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address,undefined -fno-omit-frame-pointer")
+ SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address,undefined -fno-omit-frame-pointer")
+ENDIF ()
+
+# Unity Build support
+include(UnityBuild)
diff --git a/cmake_modules/CMakeParseArguments.cmake b/cmake_modules/CMakeParseArguments.cmake
new file mode 100644
index 0000000..fc64ab9
--- /dev/null
+++ b/cmake_modules/CMakeParseArguments.cmake
@@ -0,0 +1,21 @@
+#.rst:
+# CMakeParseArguments
+# -------------------
+#
+# This module once implemented the :command:`cmake_parse_arguments` command
+# that is now implemented natively by CMake. It is now an empty placeholder
+# for compatibility with projects that include it to get the command from
+# CMake 3.4 and lower.
+
+#=============================================================================
+# Copyright 2010 Alexander Neundorf <neundorf@kde.org>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
diff --git a/cmake_modules/FindAHPXC.cmake b/cmake_modules/FindAHPXC.cmake
new file mode 100644
index 0000000..5da5692
--- /dev/null
+++ b/cmake_modules/FindAHPXC.cmake
@@ -0,0 +1,50 @@
+# - Try to find AHPXC Universal Library
+# Once done this will define
+#
+# AHPXC_FOUND - system has AHPXC
+# AHPXC_INCLUDE_DIR - the AHPXC include directory
+# AHPXC_LIBRARIES - Link these to use AHPXC
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (AHPXC_INCLUDE_DIR AND AHPXC_LIBRARIES)
+
+ # in cache already
+ set(AHPXC_FOUND TRUE)
+ message(STATUS "Found libahp_xc: ${AHPXC_LIBRARIES}")
+
+else (AHPXC_INCLUDE_DIR AND AHPXC_LIBRARIES)
+
+ find_path(AHPXC_INCLUDE_DIR ahp_xc.h
+ PATH_SUFFIXES ahp
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(AHPXC_LIBRARIES NAMES ahp_xc
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(AHPXC_INCLUDE_DIR AND AHPXC_LIBRARIES)
+ set(AHPXC_FOUND TRUE)
+ else (AHPXC_INCLUDE_DIR AND AHPXC_LIBRARIES)
+ set(AHPXC_FOUND FALSE)
+ endif(AHPXC_INCLUDE_DIR AND AHPXC_LIBRARIES)
+
+
+ if (AHPXC_FOUND)
+ if (NOT AHPXC_FIND_QUIETLY)
+ message(STATUS "Found AHP XC: ${AHPXC_LIBRARIES}")
+ endif (NOT AHPXC_FIND_QUIETLY)
+ else (AHPXC_FOUND)
+ if (AHPXC_FIND_REQUIRED)
+ message(FATAL_ERROR "AHP XC not found. Please install libahp_xc http://www.indilib.org")
+ endif (AHPXC_FIND_REQUIRED)
+ endif (AHPXC_FOUND)
+
+ mark_as_advanced(AHPXC_INCLUDE_DIR AHPXC_LIBRARIES)
+
+endif (AHPXC_INCLUDE_DIR AND AHPXC_LIBRARIES)
diff --git a/cmake_modules/FindAIOUSB.cmake b/cmake_modules/FindAIOUSB.cmake
new file mode 100644
index 0000000..4bc4469
--- /dev/null
+++ b/cmake_modules/FindAIOUSB.cmake
@@ -0,0 +1,61 @@
+# - Try to find libaiousb
+# Once done this will define
+#
+# AIOUSB_FOUND - system has AIOUSB
+# AIOUSB_INCLUDE_DIR - the AIOUSB include directory
+# AIOUSB_LIBRARIES - Link these to use AIOUSB (C)
+# AIOUSB_CPP_LIBRARIES - Link these to use AIOUSB (C++)
+
+# Copyright (c) 2006, Jasem Mutlaq <mutlaqja@ikarustech.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (AIOUSB_INCLUDE_DIR AND AIOUSB_LIBRARIES AND AIOUSB_CPP_LIBRARIES)
+
+ # in cache already
+ set(AIOUSB_FOUND TRUE)
+ message(STATUS "Found libaiusb: ${AIOUSB_LIBRARIES}")
+ message(STATUS "Found libaiusbcpp: ${AIOUSB_CPP_LIBRARIES}")
+
+else (AIOUSB_INCLUDE_DIR AND AIOUSB_LIBRARIES AND AIOUSB_CPP_LIBRARIES)
+
+ find_path(AIOUSB_INCLUDE_DIR aiousb.h
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(AIOUSB_LIBRARIES NAMES aiousb
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ find_library(AIOUSB_CPP_LIBRARIES NAMES aiousbcpp
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(AIOUSB_INCLUDE_DIR AND AIOUSB_LIBRARIES AND AIOUSB_CPP_LIBRARIES)
+ set(AIOUSB_FOUND TRUE)
+ else (AIOUSB_INCLUDE_DIR AND AIOUSB_LIBRARIES AND AIOUSB_CPP_LIBRARIES)
+ set(AIOUSB_FOUND FALSE)
+ endif(AIOUSB_INCLUDE_DIR AND AIOUSB_LIBRARIES AND AIOUSB_CPP_LIBRARIES)
+
+ if (AIOUSB_FOUND)
+ if (NOT AIOUSB_FIND_QUIETLY)
+ message(STATUS "Found libaiousb: ${AIOUSB_LIBRARIES}")
+ message(STATUS "Found libaiusbcpp: ${AIOUSB_CPP_LIBRARIES}")
+ endif (NOT AIOUSB_FIND_QUIETLY)
+ else (AIOUSB_FOUND)
+ if (AIOUSB_FIND_REQUIRED)
+ message(FATAL_ERROR "libaiousb not found. Please install libaiousb. https://www.accesio.com")
+ endif (AIOUSB_FIND_REQUIRED)
+ endif (AIOUSB_FOUND)
+
+ mark_as_advanced(AIOUSB_INCLUDE_DIR AIOUSB_LIBRARIES AIOUSB_CPP_LIBRARIES)
+
+endif (AIOUSB_INCLUDE_DIR AND AIOUSB_LIBRARIES AND AIOUSB_CPP_LIBRARIES)
+
diff --git a/cmake_modules/FindALTAIRCAM.cmake b/cmake_modules/FindALTAIRCAM.cmake
new file mode 100644
index 0000000..bffa78e
--- /dev/null
+++ b/cmake_modules/FindALTAIRCAM.cmake
@@ -0,0 +1,49 @@
+# - Try to find Altair Camera Library
+# Once done this will define
+#
+# ALTAIRCAM_FOUND - system has Altair
+# ALTAIRCAM_INCLUDE_DIR - the Altair include directory
+# ALTAIRCAM_LIBRARIES - Link these to use Altair
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (ALTAIRCAM_INCLUDE_DIR AND ALTAIRCAM_LIBRARIES)
+
+ # in cache already
+ set(ALTAIRCAM_FOUND TRUE)
+ message(STATUS "Found libaltaircam: ${ALTAIRCAM_LIBRARIES}")
+
+else (ALTAIRCAM_INCLUDE_DIR AND ALTAIRCAM_LIBRARIES)
+
+ find_path(ALTAIRCAM_INCLUDE_DIR altaircam.h
+ PATH_SUFFIXES libaltaircam
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(ALTAIRCAM_LIBRARIES NAMES altaircam
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(ALTAIRCAM_INCLUDE_DIR AND ALTAIRCAM_LIBRARIES)
+ set(ALTAIRCAM_FOUND TRUE)
+ else (ALTAIRCAM_INCLUDE_DIR AND ALTAIRCAM_LIBRARIES)
+ set(ALTAIRCAM_FOUND FALSE)
+ endif(ALTAIRCAM_INCLUDE_DIR AND ALTAIRCAM_LIBRARIES)
+
+ if (ALTAIRCAM_FOUND)
+ if (NOT ALTAIRCAM_FIND_QUIETLY)
+ message(STATUS "Found Altaircam: ${ALTAIRCAM_LIBRARIES}")
+ endif (NOT ALTAIRCAM_FIND_QUIETLY)
+ else (ALTAIRCAM_FOUND)
+ if (ALTAIRCAM_FIND_REQUIRED)
+ message(FATAL_ERROR "Altaircam not found. Please install Altaircam Library http://www.indilib.org")
+ endif (ALTAIRCAM_FIND_REQUIRED)
+ endif (ALTAIRCAM_FOUND)
+
+ mark_as_advanced(ALTAIRCAM_INCLUDE_DIR ALTAIRCAM_LIBRARIES)
+
+endif (ALTAIRCAM_INCLUDE_DIR AND ALTAIRCAM_LIBRARIES)
diff --git a/cmake_modules/FindALUT.cmake b/cmake_modules/FindALUT.cmake
new file mode 100644
index 0000000..44aa2b0
--- /dev/null
+++ b/cmake_modules/FindALUT.cmake
@@ -0,0 +1,77 @@
+# - Locate ALUT
+# This module defines
+# ALUT_LIBRARY
+# ALUT_FOUND, if false, do not try to link to OpenAL
+# ALUT_INCLUDE_DIR, where to find the headers
+#
+# $OPENALDIR is an environment variable that would
+# correspond to the ./configure --prefix=$OPENALDIR
+# used in building OpenAL.
+#
+# Created by Bryan Donlan, based on the FindOpenAL.cmake module by Eric Wang.
+
+FIND_PATH(ALUT_INCLUDE_DIR alut.h
+ $ENV{OPENALDIR}/include
+ ~/Library/Frameworks/OpenAL.framework/Headers
+ /Library/Frameworks/OpenAL.framework/Headers
+ /System/Library/Frameworks/OpenAL.framework/Headers # Tiger
+ /usr/local/include/AL
+ /usr/local/include/OpenAL
+ /usr/local/include
+ /usr/include/AL
+ /usr/include/OpenAL
+ /usr/include
+ /sw/include/AL # Fink
+ /sw/include/OpenAL
+ /sw/include
+ /opt/local/include/AL # DarwinPorts
+ /opt/local/include/OpenAL
+ /opt/local/include
+ /opt/csw/include/AL # Blastwave
+ /opt/csw/include/OpenAL
+ /opt/csw/include
+ /opt/include/AL
+ /opt/include/OpenAL
+ /opt/include
+ )
+# I'm not sure if I should do a special casing for Apple. It is
+# unlikely that other Unix systems will find the framework path.
+# But if they do ([Next|Open|GNU]Step?),
+# do they want the -framework option also?
+IF(${ALUT_INCLUDE_DIR} MATCHES ".framework")
+ STRING(REGEX REPLACE "(.*)/.*\\.framework/.*" "\\1" ALUT_FRAMEWORK_PATH_TMP ${ALUT_INCLUDE_DIR})
+ IF("${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/Library/Frameworks"
+ OR "${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/System/Library/Frameworks"
+ )
+ # String is in default search path, don't need to use -F
+ SET (ALUT_LIBRARY "-framework OpenAL" CACHE STRING "OpenAL framework for OSX")
+ ELSE("${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/Library/Frameworks"
+ OR "${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/System/Library/Frameworks"
+ )
+ # String is not /Library/Frameworks, need to use -F
+ SET(ALUT_LIBRARY "-F${ALUT_FRAMEWORK_PATH_TMP} -framework OpenAL" CACHE STRING "OpenAL framework for OSX")
+ ENDIF("${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/Library/Frameworks"
+ OR "${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/System/Library/Frameworks"
+ )
+ # Clear the temp variable so nobody can see it
+ SET(ALUT_FRAMEWORK_PATH_TMP "" CACHE INTERNAL "")
+
+ELSE(${ALUT_INCLUDE_DIR} MATCHES ".framework")
+ FIND_LIBRARY(ALUT_LIBRARY
+ NAMES alut
+ PATHS
+ $ENV{OPENALDIR}/lib
+ $ENV{OPENALDIR}/libs
+ /usr/local/lib
+ /usr/lib
+ /sw/lib
+ /opt/local/lib
+ /opt/csw/lib
+ /opt/lib
+ )
+ENDIF(${ALUT_INCLUDE_DIR} MATCHES ".framework")
+
+SET(ALUT_FOUND "NO")
+IF(ALUT_LIBRARY)
+ SET(ALUT_FOUND "YES")
+ENDIF(ALUT_LIBRARY)
diff --git a/cmake_modules/FindAPOGEE.cmake b/cmake_modules/FindAPOGEE.cmake
new file mode 100644
index 0000000..081fb7e
--- /dev/null
+++ b/cmake_modules/FindAPOGEE.cmake
@@ -0,0 +1,53 @@
+# - Try to find Apogee Instruments Library
+# Once done this will define
+#
+# APOGEE_FOUND - system has APOGEE
+# APOGEE_INCLUDE_DIR - the APOGEE include directory
+# APOGEE_LIBRARY - Link these to use APOGEE
+
+# Copyright (c) 2008, Jasem Mutlaq <mutlaqja@ikarustech.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (APOGEE_INCLUDE_DIR AND APOGEE_LIBRARY)
+
+ # in cache already
+ set(APOGEE_FOUND TRUE)
+ message(STATUS "Found libapogee: ${APOGEE_LIBRARY}")
+
+else (APOGEE_INCLUDE_DIR AND APOGEE_LIBRARY)
+
+ find_path(APOGEE_INCLUDE_DIR ApogeeCam.h
+ PATH_SUFFIXES libapogee
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ # Find Apogee Library
+ find_library(APOGEE_LIBRARY NAMES apogee
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(APOGEE_INCLUDE_DIR AND APOGEE_LIBRARY)
+ set(APOGEE_FOUND TRUE)
+ else (APOGEE_INCLUDE_DIR AND APOGEE_LIBRARY)
+ set(APOGEE_FOUND FALSE)
+ endif(APOGEE_INCLUDE_DIR AND APOGEE_LIBRARY)
+
+ if (APOGEE_FOUND)
+ if (NOT APOGEE_FIND_QUIETLY)
+ message(STATUS "Found APOGEE: ${APOGEE_LIBRARY}")
+ endif (NOT APOGEE_FIND_QUIETLY)
+ else (APOGEE_FOUND)
+ if (APOGEE_FIND_REQUIRED)
+ message(FATAL_ERROR "libapogee not found. Cannot compile Apogee CCD Driver. Please install libapogee and try again. http://www.indilib.org")
+ endif (APOGEE_FIND_REQUIRED)
+ endif (APOGEE_FOUND)
+
+ mark_as_advanced(APOGEE_INCLUDE_DIR APOGEE_LIBRARY)
+
+endif (APOGEE_INCLUDE_DIR AND APOGEE_LIBRARY)
diff --git a/cmake_modules/FindARAVIS.cmake b/cmake_modules/FindARAVIS.cmake
new file mode 100644
index 0000000..5bd2d3c
--- /dev/null
+++ b/cmake_modules/FindARAVIS.cmake
@@ -0,0 +1,43 @@
+# - Find the native sqlite3 includes and library
+#
+# This module defines
+# ARV_INCLUDE_DIR, where to find libgphoto2 header files
+# ARV_LIBRARIES, the libraries to link against to use libgphoto2
+# ARV_FOUND, If false, do not try to use libgphoto2.
+# ARV_VERSION_STRING, e.g. 2.4.14
+# ARV_VERSION_MAJOR, e.g. 2
+# ARV_VERSION_MINOR, e.g. 4
+# ARV_VERSION_PATCH, e.g. 14
+#
+# also defined, but not for general use are
+# ARV_LIBRARY, where to find the sqlite3 library.
+
+
+#=============================================================================
+# Copyright 2010 henrik andersson
+#=============================================================================
+
+SET(ARV_FIND_REQUIRED ${Arv_FIND_REQUIRED})
+
+find_path(ARV_INCLUDE_DIR aravis-0.8/arv.h)
+mark_as_advanced(ARV_INCLUDE_DIR)
+
+set(ARV_NAMES ${ARV_NAMES} aravis-0.8)
+find_library(ARV_LIBRARY NAMES ${ARV_NAMES} )
+mark_as_advanced(ARV_LIBRARY)
+
+set(ARV_VERSION_MAJOR "0")
+set(ARV_VERSION_MINOR "8")
+set(ARV_VERSION_STRING "${ARV_VERSION_MAJOR}.${ARV_VERSION_MINOR}")
+
+# handle the QUIETLY and REQUIRED arguments and set ARV_FOUND to TRUE if
+# all listed variables are TRUE
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(ARV DEFAULT_MSG ARV_LIBRARY ARV_INCLUDE_DIR)
+
+IF(ARV_FOUND)
+ #SET(Arv_LIBRARIES ${ARV_LIBRARY})
+ SET(Arv_LIBRARIES "aravis-0.8")
+ SET(Arv_INCLUDE_DIRS "${ARV_INCLUDE_DIR}/aravis-0.8")
+ MESSAGE (STATUS "Found aravis: ${Arv_LIBRARIES} ${Arv_INCLUDE_DIRS}")
+ENDIF(ARV_FOUND)
diff --git a/cmake_modules/FindASI.cmake b/cmake_modules/FindASI.cmake
new file mode 100644
index 0000000..0df4577
--- /dev/null
+++ b/cmake_modules/FindASI.cmake
@@ -0,0 +1,74 @@
+# - Try to find ASI Library
+# Once done this will define
+#
+# ASI_FOUND - system has ASI
+# ASI_INCLUDE_DIR - the ASI include directory
+# ASI_LIBRARIES - Link these to use ASI
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (ASI_INCLUDE_DIR AND ASI_LIBRARIES)
+
+ # in cache already
+ set(ASI_FOUND TRUE)
+ message(STATUS "Found libasi: ${ASI_LIBRARIES}")
+
+else (ASI_INCLUDE_DIR AND ASI_LIBRARIES)
+
+ find_path(ASI_INCLUDE_DIR ASICamera2.h
+ PATH_SUFFIXES libasi
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(ASICAM_LIBRARIES NAMES ASICamera2
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ find_library(ASIEFW_LIBRARIES NAMES EFWFilter
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ find_library(ASIST4_LIBRARIES NAMES USB2ST4Conv
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ find_library(ASIEAF_LIBRARIES NAMES EAFFocuser
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+
+ if (ASICAM_LIBRARIES AND ASIEFW_LIBRARIES AND ASIST4_LIBRARIES AND ASIEAF_LIBRARIES)
+ set(ASI_LIBRARIES ${ASICAM_LIBRARIES} ${ASIEFW_LIBRARIES} ${ASIST4_LIBRARIES} ${ASIEAF_LIBRARIES})
+ endif (ASICAM_LIBRARIES AND ASIEFW_LIBRARIES AND ASIST4_LIBRARIES AND ASIEAF_LIBRARIES)
+
+
+ if(ASI_INCLUDE_DIR AND ASI_LIBRARIES)
+ set(ASI_FOUND TRUE)
+ else (ASI_INCLUDE_DIR AND ASI_LIBRARIES)
+ set(ASI_FOUND FALSE)
+ endif(ASI_INCLUDE_DIR AND ASI_LIBRARIES)
+
+
+ if (ASI_FOUND)
+ if (NOT ASI_FIND_QUIETLY)
+ message(STATUS "Found ASI: ${ASI_LIBRARIES}")
+ endif (NOT ASI_FIND_QUIETLY)
+ else (ASI_FOUND)
+ if (ASI_FIND_REQUIRED)
+ message(FATAL_ERROR "ASI not found. Please install libasi http://www.indilib.org")
+ endif (ASI_FIND_REQUIRED)
+ endif (ASI_FOUND)
+
+ mark_as_advanced(ASI_INCLUDE_DIR ASI_LIBRARIES)
+
+endif (ASI_INCLUDE_DIR AND ASI_LIBRARIES)
diff --git a/cmake_modules/FindATIK.cmake b/cmake_modules/FindATIK.cmake
new file mode 100644
index 0000000..d52f86e
--- /dev/null
+++ b/cmake_modules/FindATIK.cmake
@@ -0,0 +1,49 @@
+# - Try to find Atik Camera Library
+# Once done this will define
+#
+# ATIK_FOUND - system has ATIK
+# ATIK_INCLUDE_DIR - the ATIK include directory
+# ATIK_LIBRARIES - Link these to use ATIK
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (ATIK_INCLUDE_DIR AND ATIK_LIBRARIES)
+
+ # in cache already
+ set(ATIK_FOUND TRUE)
+ message(STATUS "Found libatik: ${ATIK_LIBRARIES}")
+
+else (ATIK_INCLUDE_DIR AND ATIK_LIBRARIES)
+
+ find_path(ATIK_INCLUDE_DIR AtikCameras.h
+ PATH_SUFFIXES libatik
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(ATIK_LIBRARIES NAMES atikcameras
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(ATIK_INCLUDE_DIR AND ATIK_LIBRARIES)
+ set(ATIK_FOUND TRUE)
+ else (ATIK_INCLUDE_DIR AND ATIK_LIBRARIES)
+ set(ATIK_FOUND FALSE)
+ endif(ATIK_INCLUDE_DIR AND ATIK_LIBRARIES)
+
+ if (ATIK_FOUND)
+ if (NOT ATIK_FIND_QUIETLY)
+ message(STATUS "Found Atik Library: ${ATIK_LIBRARIES}")
+ endif (NOT ATIK_FIND_QUIETLY)
+ else (ATIK_FOUND)
+ if (ATIK_FIND_REQUIRED)
+ message(FATAL_ERROR "Atik Library not found. Please install Atik Library http://www.indilib.org")
+ endif (ATIK_FIND_REQUIRED)
+ endif (ATIK_FOUND)
+
+ mark_as_advanced(ATIK_INCLUDE_DIR ATIK_LIBRARIES)
+
+endif (ATIK_INCLUDE_DIR AND ATIK_LIBRARIES)
diff --git a/cmake_modules/FindCFITSIO.cmake b/cmake_modules/FindCFITSIO.cmake
new file mode 100644
index 0000000..c994522
--- /dev/null
+++ b/cmake_modules/FindCFITSIO.cmake
@@ -0,0 +1,65 @@
+# - Try to find CFITSIO
+# Once done this will define
+#
+# CFITSIO_FOUND - system has CFITSIO
+# CFITSIO_INCLUDE_DIR - the CFITSIO include directory
+# CFITSIO_LIBRARIES - Link these to use CFITSIO
+# CFITSIO_VERSION_STRING - Human readable version number of cfitsio
+# CFITSIO_VERSION_MAJOR - Major version number of cfitsio
+# CFITSIO_VERSION_MINOR - Minor version number of cfitsio
+
+# Copyright (c) 2006, Jasem Mutlaq <mutlaqja@ikarustech.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES)
+
+ # in cache already
+ set(CFITSIO_FOUND TRUE)
+ message(STATUS "Found CFITSIO: ${CFITSIO_LIBRARIES}")
+
+
+else (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES)
+
+ # JM: Packages from different distributions have different suffixes
+ find_path(CFITSIO_INCLUDE_DIR fitsio.h
+ PATH_SUFFIXES libcfitsio3 libcfitsio0 cfitsio
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(CFITSIO_LIBRARIES NAMES cfitsio
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES)
+ set(CFITSIO_FOUND TRUE)
+ else (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES)
+ set(CFITSIO_FOUND FALSE)
+ endif(CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES)
+
+
+ if (CFITSIO_FOUND)
+
+ # Find the version of the cfitsio header
+ file(STRINGS ${CFITSIO_INCLUDE_DIR}/fitsio.h CFITSIO_VERSION_STRING LIMIT_COUNT 1 REGEX "CFITSIO_VERSION")
+ STRING(REGEX REPLACE "[^0-9.]" "" CFITSIO_VERSION_STRING ${CFITSIO_VERSION_STRING})
+ STRING(REGEX REPLACE "^([0-9]+)[.]([0-9]+)" "\\1" CFITSIO_VERSION_MAJOR ${CFITSIO_VERSION_STRING})
+ STRING(REGEX REPLACE "^([0-9]+)[.]([0-9]+)" "\\2" CFITSIO_VERSION_MINOR ${CFITSIO_VERSION_STRING})
+
+ if (NOT CFITSIO_FIND_QUIETLY)
+ message(STATUS "Found CFITSIO ${CFITSIO_VERSION_STRING}: ${CFITSIO_LIBRARIES}")
+ endif (NOT CFITSIO_FIND_QUIETLY)
+ else (CFITSIO_FOUND)
+ if (CFITSIO_FIND_REQUIRED)
+ message(STATUS "CFITSIO not found.")
+ endif (CFITSIO_FIND_REQUIRED)
+ endif (CFITSIO_FOUND)
+
+ mark_as_advanced(CFITSIO_INCLUDE_DIR CFITSIO_LIBRARIES)
+
+endif (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES)
diff --git a/cmake_modules/FindD2XX.cmake b/cmake_modules/FindD2XX.cmake
new file mode 100644
index 0000000..0dc9f80
--- /dev/null
+++ b/cmake_modules/FindD2XX.cmake
@@ -0,0 +1,56 @@
+# - Try to find D2XX
+# Once done this will define
+#
+# D2XX_FOUND - system has FTDI
+# D2XX_INCLUDE_DIR - the FTDI include directory
+# D2XX_LIBRARIES - Link these to use FTDI
+#
+# N.B. You must include the file as following:
+#
+#include <ftd2xx.h>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (D2XX_INCLUDE_DIR AND D2XX_LIBRARIES)
+
+ # in cache already
+ set(D2XX_FOUND TRUE)
+ message(STATUS "Found libfd2xx: ${D2XX_LIBRARIES}")
+
+else (D2XX_INCLUDE_DIR AND D2XX_LIBRARIES)
+
+ find_path(D2XX_INCLUDE_DIR ftd2xx.h
+ #PATH_SUFFIXES libD2XX
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ /usr/local/include
+ )
+
+ find_library(D2XX_LIBRARIES NAMES ftd2xx
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ /usr/local/lib
+ )
+
+ if(D2XX_INCLUDE_DIR AND D2XX_LIBRARIES)
+ set(D2XX_FOUND TRUE)
+ else (D2XX_INCLUDE_DIR AND D2XX_LIBRARIES)
+ set(D2XX_FOUND FALSE)
+ endif(D2XX_INCLUDE_DIR AND D2XX_LIBRARIES)
+
+
+ if (D2XX_FOUND)
+ if (NOT D2XX_FIND_QUIETLY)
+ message(STATUS "Found D2XX: ${D2XX_LIBRARIES}")
+ endif (NOT D2XX_FIND_QUIETLY)
+ else (D2XX_FOUND)
+ if (D2XX_FIND_REQUIRED)
+ message(FATAL_ERROR "D2XX not found. Please install libd2xx")
+ endif (D2XX_FIND_REQUIRED)
+ endif (D2XX_FOUND)
+
+ mark_as_advanced(D2XX_INCLUDE_DIR D2XX_LIBRARIES)
+
+endif (D2XX_INCLUDE_DIR AND D2XX_LIBRARIES)
diff --git a/cmake_modules/FindDC1394.cmake b/cmake_modules/FindDC1394.cmake
new file mode 100644
index 0000000..87d9609
--- /dev/null
+++ b/cmake_modules/FindDC1394.cmake
@@ -0,0 +1,50 @@
+# - Try to find dc1394 library (version 2) and include files
+# Once done this will define
+#
+# DC1394_FOUND - system has DC1394
+# DC1394_INCLUDE_DIR - the DC1394 include directory
+# DC1394_LIBRARIES - Link these to use DC1394
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (DC1394_INCLUDE_DIR AND DC1394_LIBRARIES)
+
+ # in cache already
+ set(DC1394_FOUND TRUE)
+ message(STATUS "Found libdc1394: ${DC1394_LIBRARIES}")
+
+else (DC1394_INCLUDE_DIR AND DC1394_LIBRARIES)
+
+ find_path(DC1394_INCLUDE_DIR control.h
+ PATH_SUFFIXES dc1394
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(DC1394_LIBRARIES NAMES dc1394
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(DC1394_INCLUDE_DIR AND DC1394_LIBRARIES)
+ set(DC1394_FOUND TRUE)
+ else (DC1394_INCLUDE_DIR AND DC1394_LIBRARIES)
+ set(DC1394_FOUND FALSE)
+ endif(DC1394_INCLUDE_DIR AND DC1394_LIBRARIES)
+
+
+ if (DC1394_FOUND)
+ if (NOT DC1394_FIND_QUIETLY)
+ message(STATUS "Found DC1394: ${DC1394_LIBRARIES}")
+ endif (NOT DC1394_FIND_QUIETLY)
+ else (DC1394_FOUND)
+ if (DC1394_FIND_REQUIRED)
+ message(FATAL_ERROR "DC1394 not found. Please install libdc1394 development package.")
+ endif (DC1394_FIND_REQUIRED)
+ endif (DC1394_FOUND)
+
+ mark_as_advanced(DC1394_INCLUDE_DIR DC1394_LIBRARIES)
+
+endif (DC1394_INCLUDE_DIR AND DC1394_LIBRARIES)
diff --git a/cmake_modules/FindFFTW3.cmake b/cmake_modules/FindFFTW3.cmake
new file mode 100644
index 0000000..289accc
--- /dev/null
+++ b/cmake_modules/FindFFTW3.cmake
@@ -0,0 +1,52 @@
+# - Try to find FFTW3
+# Once done this will define
+#
+# FFTW3_FOUND - system has FFTW3
+# FFTW3_INCLUDE_DIR - the FFTW3 include directory
+# FFTW3_LIBRARIES - Link these to use FFTW3
+# FFTW3_VERSION_STRING - Human readable version number of fftw3
+# FFTW3_VERSION_MAJOR - Major version number of fftw3
+# FFTW3_VERSION_MINOR - Minor version number of fftw3
+
+# Copyright (c) 2017, Ilia Platone, <info@iliaplatone.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (FFTW3_LIBRARIES)
+
+ # in cache already
+ set(FFTW3_FOUND TRUE)
+ message(STATUS "Found FFTW3: ${FFTW3_LIBRARIES}")
+
+
+else (FFTW3_LIBRARIES)
+
+ find_library(FFTW3_LIBRARIES NAMES fftw3
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ /usr/local/lib
+ )
+
+ if(FFTW3_LIBRARIES)
+ set(FFTW3_FOUND TRUE)
+ else (FFTW3_LIBRARIES)
+ set(FFTW3_FOUND FALSE)
+ endif(FFTW3_LIBRARIES)
+
+
+ if (FFTW3_FOUND)
+ if (NOT FFTW3_FIND_QUIETLY)
+ message(STATUS "Found FFTW3: ${FFTW3_LIBRARIES}")
+ endif (NOT FFTW3_FIND_QUIETLY)
+ else (FFTW3_FOUND)
+ if (FFTW3_FIND_REQUIRED)
+ message(FATAL_ERROR "FFTW3 not found. Please install libfftw3-dev")
+ endif (FFTW3_FIND_REQUIRED)
+ endif (FFTW3_FOUND)
+
+ mark_as_advanced(FFTW3_LIBRARIES)
+
+endif (FFTW3_LIBRARIES)
diff --git a/cmake_modules/FindFFmpeg.cmake b/cmake_modules/FindFFmpeg.cmake
new file mode 100644
index 0000000..6d4b72f
--- /dev/null
+++ b/cmake_modules/FindFFmpeg.cmake
@@ -0,0 +1,213 @@
+# - Try to find ffmpeg libraries (libavcodec, libavdevice, libavformat, libavutil, and libswscale)
+# Once done this will define
+#
+# FFMPEG_FOUND - system has ffmpeg or libav
+# FFMPEG_INCLUDE_DIR - the ffmpeg include directory
+# FFMPEG_LIBRARIES - Link these to use ffmpeg
+# FFMPEG_LIBAVCODEC
+# FFMPEG_LIBAVDEVICE
+# FFMPEG_LIBAVFORMAT
+# FFMPEG_LIBAVUTIL
+# FFMPEG_LIBSWSCALE
+#
+# Copyright (c) 2008 Andreas Schneider <mail@cynapses.org>
+# Modified for other libraries by Lasse Kärkkäinen <tronic>
+# Modified for Hedgewars by Stepik777
+# Modified for INDILIB by rlancaste
+#
+# Redistribution and use is allowed according to the terms of the New
+# BSD license.
+#
+
+macro(_FFMPEG_PACKAGE_check_version)
+ if(EXISTS "${PACKAGE_INCLUDE_DIR}/version.h")
+ file(READ "${PACKAGE_INCLUDE_DIR}/version.h" _FFMPEG_PACKAGE_version_header)
+
+ string(REGEX MATCH "#define ${PACKAGE_NAME}_VERSION_MAJOR[ \t]+([0-9]+)" _VERSION_MAJOR_match "${_FFMPEG_PACKAGE_version_header}")
+ set(FFMPEG_PACKAGE_VERSION_MAJOR "${CMAKE_MATCH_1}")
+ string(REGEX MATCH "#define ${PACKAGE_NAME}_VERSION_MINOR[ \t]+([0-9]+)" _VERSION_MINOR_match "${_FFMPEG_PACKAGE_version_header}")
+ set(FFMPEG_PACKAGE_VERSION_MINOR "${CMAKE_MATCH_1}")
+ string(REGEX MATCH "#define ${PACKAGE_NAME}_VERSION_MICRO[ \t]+([0-9]+)" _VERSION_MICRO_match "${_FFMPEG_PACKAGE_version_header}")
+ set(FFMPEG_PACKAGE_VERSION_MICRO "${CMAKE_MATCH_1}")
+
+ set(FFMPEG_PACKAGE_VERSION ${FFMPEG_PACKAGE_VERSION_MAJOR}.${FFMPEG_PACKAGE_VERSION_MINOR}.${FFMPEG_PACKAGE_VERSION_MICRO})
+ if(${FFMPEG_PACKAGE_VERSION} VERSION_LESS ${FFMPEG_PACKAGE_FIND_VERSION})
+ set(FFMPEG_PACKAGE_VERSION_OK FALSE)
+ else(${FFMPEG_PACKAGE_VERSION} VERSION_LESS ${FFMPEG_PACKAGE_FIND_VERSION})
+ set(FFMPEG_PACKAGE_VERSION_OK TRUE)
+ endif(${FFMPEG_PACKAGE_VERSION} VERSION_LESS ${FFMPEG_PACKAGE_FIND_VERSION})
+
+ if(NOT FFMPEG_PACKAGE_VERSION_OK)
+ message(STATUS "${PACKAGE_NAME} version ${FFMPEG_PACKAGE_VERSION} found in ${PACKAGE_INCLUDE_DIR}, "
+ "but at least version ${FFMPEG_PACKAGE_FIND_VERSION} is required")
+ else(NOT FFMPEG_PACKAGE_VERSION_OK)
+ mark_as_advanced(FFMPEG_PACKAGE_VERSION_MAJOR FFMPEG_PACKAGE_VERSION_MINOR FFMPEG_PACKAGE_VERSION_MICRO)
+ endif(NOT FFMPEG_PACKAGE_VERSION_OK)
+ else(EXISTS "${PACKAGE_INCLUDE_DIR}/version.h")
+ set(FFMPEG_PACKAGE_VERSION_OK FALSE)
+ message(STATUS "${PACKAGE_NAME}'s version.h file was not found in the include directory: ${PACKAGE_INCLUDE_DIR}, please install this program.")
+ endif(EXISTS "${PACKAGE_INCLUDE_DIR}/version.h")
+endmacro(_FFMPEG_PACKAGE_check_version)
+
+# required ffmpeg library versions, Requiring at least FFMPEG 3.2.11, Hypatia
+set(_avcodec_ver ">=57.64.101")
+set(_avdevice_ver ">=57.1.100")
+set(_avformat_ver ">=57.56.100")
+set(_avutil_ver ">=55.34.100")
+set(_swscale_ver ">=4.2.100")
+
+if (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
+
+ # in cache already
+ set(FFMPEG_FOUND TRUE)
+
+else (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
+# use pkg-config to get the directories and then use these values
+# in the FIND_PATH() and FIND_LIBRARY() calls
+
+find_path(FFMPEG_INCLUDE_DIR
+NAMES libavcodec/avcodec.h
+PATHS ${FFMPEG_INCLUDE_DIRS} ${CMAKE_INSTALL_PREFIX}/include /usr/include /usr/local/include /opt/local/include /sw/include
+PATH_SUFFIXES ffmpeg libav
+)
+
+find_package(PkgConfig)
+if (PKG_CONFIG_FOUND)
+
+ pkg_check_modules(AVCODEC libavcodec${_avcodec_ver})
+ pkg_check_modules(AVDEVICE libavdevice${_avdevice_ver})
+ pkg_check_modules(AVFORMAT libavformat${_avformat_ver})
+ pkg_check_modules(AVUTIL libavutil${_avutil_ver})
+ pkg_check_modules(SWSCALE libswscale${_swscale_ver})
+
+endif (PKG_CONFIG_FOUND)
+
+if (NOT PKG_CONFIG_FOUND OR
+ NOT FFMPEG_LIBAVCODEC OR
+ NOT FFMPEG_LIBAVDEVICE OR
+ NOT FFMPEG_LIBAVFORMAT OR
+ NOT FFMPEG_LIBAVUTIL OR
+ NOT FFMPEG_LIBSWSCALE)
+
+# LIBAVCODEC
+ set(PACKAGE_NAME "LIBAVCODEC")
+ set(PACKAGE_INCLUDE_DIR "${FFMPEG_INCLUDE_DIR}/libavcodec")
+ set(FFMPEG_PACKAGE_FIND_VERSION _avcodec_ver)
+
+ _FFMPEG_PACKAGE_check_version()
+
+ if(FFMPEG_PACKAGE_VERSION_OK)
+ set(AVCODEC_VERSION FFMPEG_PACKAGE_VERSION)
+ endif(FFMPEG_PACKAGE_VERSION_OK)
+
+# LIBAVDEVICE
+ set(PACKAGE_NAME "LIBAVDEVICE")
+ set(PACKAGE_INCLUDE_DIR "${FFMPEG_INCLUDE_DIR}/libavdevice")
+ set(FFMPEG_PACKAGE_FIND_VERSION _avdevice_ver)
+
+ _FFMPEG_PACKAGE_check_version()
+
+ if(FFMPEG_PACKAGE_VERSION_OK)
+ set(AVDEVICE_VERSION FFMPEG_PACKAGE_VERSION)
+ endif(FFMPEG_PACKAGE_VERSION_OK)
+
+# LIBAVFORMAT
+ set(PACKAGE_NAME "LIBAVFORMAT")
+ set(PACKAGE_INCLUDE_DIR "${FFMPEG_INCLUDE_DIR}/libavformat")
+ set(FFMPEG_PACKAGE_FIND_VERSION _avformat_ver)
+
+ _FFMPEG_PACKAGE_check_version()
+
+ if(FFMPEG_PACKAGE_VERSION_OK)
+ set(AVFORMAT_VERSION FFMPEG_PACKAGE_VERSION)
+ endif(FFMPEG_PACKAGE_VERSION_OK)
+
+# LIBAVUTIL
+ set(PACKAGE_NAME "LIBAVUTIL")
+ set(PACKAGE_INCLUDE_DIR "${FFMPEG_INCLUDE_DIR}/libavutil")
+ set(FFMPEG_PACKAGE_FIND_VERSION _avutil_ver)
+
+ _FFMPEG_PACKAGE_check_version()
+
+ if(FFMPEG_PACKAGE_VERSION_OK)
+ set(AVUTIL_VERSION FFMPEG_PACKAGE_VERSION)
+ endif(FFMPEG_PACKAGE_VERSION_OK)
+
+# LIBSWSCALE
+ set(PACKAGE_NAME "LIBSWSCALE")
+ set(PACKAGE_INCLUDE_DIR "${FFMPEG_INCLUDE_DIR}/libswscale")
+ set(FFMPEG_PACKAGE_FIND_VERSION _swscale_ver)
+
+ _FFMPEG_PACKAGE_check_version()
+
+ if(FFMPEG_PACKAGE_VERSION_OK)
+ set(SWSCALE_VERSION FFMPEG_PACKAGE_VERSION)
+ endif(FFMPEG_PACKAGE_VERSION_OK)
+
+endif ()
+
+find_library(FFMPEG_LIBAVCODEC
+NAMES avcodec libavcodec
+PATHS ${AVCODEC_LIBRARY_DIRS} ${CMAKE_INSTALL_PREFIX}/lib /usr/lib /usr/local/lib /opt/local/lib /sw/lib
+)
+
+find_library(FFMPEG_LIBAVDEVICE
+NAMES avdevice libavdevice
+PATHS ${AVDEVICE_LIBRARY_DIRS} ${CMAKE_INSTALL_PREFIX}/lib /usr/lib /usr/local/lib /opt/local/lib /sw/lib
+)
+
+find_library(FFMPEG_LIBAVFORMAT
+NAMES avformat libavformat
+PATHS ${AVFORMAT_LIBRARY_DIRS} ${CMAKE_INSTALL_PREFIX}/lib /usr/lib /usr/local/lib /opt/local/lib /sw/lib
+)
+
+find_library(FFMPEG_LIBAVUTIL
+NAMES avutil libavutil
+PATHS ${AVUTIL_LIBRARY_DIRS} ${CMAKE_INSTALL_PREFIX}/lib /usr/lib /usr/local/lib /opt/local/lib /sw/lib
+)
+
+find_library(FFMPEG_LIBSWSCALE
+NAMES swscale libswscale
+PATHS ${SWSCALE_LIBRARY_DIRS} ${CMAKE_INSTALL_PREFIX}/lib /usr/lib /usr/local/lib /opt/local/lib /sw/lib
+)
+
+#Only set FFMPEG to found if all the libraries are found in the right versions.
+if(AVCODEC_VERSION AND
+ AVDEVICE_VERSION AND
+ AVFORMAT_VERSION AND
+ AVUTIL_VERSION AND
+ SWSCALE_VERSION AND
+ FFMPEG_LIBAVCODEC AND
+ FFMPEG_LIBAVDEVICE AND
+ FFMPEG_LIBAVFORMAT AND
+ FFMPEG_LIBAVUTIL AND
+ FFMPEG_LIBSWSCALE)
+set(FFMPEG_FOUND TRUE)
+endif()
+
+if (FFMPEG_FOUND)
+
+ set(FFMPEG_LIBRARIES
+ ${FFMPEG_LIBAVCODEC}
+ ${FFMPEG_LIBAVDEVICE}
+ ${FFMPEG_LIBAVFORMAT}
+ ${FFMPEG_LIBAVUTIL}
+ ${FFMPEG_LIBSWSCALE}
+ )
+
+endif (FFMPEG_FOUND)
+
+if (FFMPEG_FOUND)
+ if (NOT FFMPEG_FIND_QUIETLY)
+ message(STATUS "Found FFMPEG: ${FFMPEG_LIBRARIES}, ${FFMPEG_INCLUDE_DIR}")
+ endif (NOT FFMPEG_FIND_QUIETLY)
+ else (FFMPEG_FOUND)
+ message(STATUS "Could not find up to date FFMPEG for INDI Webcam. Up to date versions of these packages are required: libavcodec, libavdevice, libavformat, libavutil, and libswscale")
+ if (FFMPEG_FIND_REQUIRED)
+ message(FATAL_ERROR "Error: FFMPEG is required by this package!")
+ endif (FFMPEG_FIND_REQUIRED)
+endif (FFMPEG_FOUND)
+
+endif (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
+
+
diff --git a/cmake_modules/FindFISHCAMP.cmake b/cmake_modules/FindFISHCAMP.cmake
new file mode 100644
index 0000000..e023596
--- /dev/null
+++ b/cmake_modules/FindFISHCAMP.cmake
@@ -0,0 +1,54 @@
+# - Try to find FISHCAMP CCD
+# Once done this will define
+#
+# FISHCAMP_FOUND - system has FISHCAMP
+# FISHCAMP_LIBRARIES - Link these to use FISHCAMP
+# FISHCAMP_INCLUDE_DIR - Fishcamp include directory
+
+# Copyright (c) 2006, Jasem Mutlaq <mutlaqja@ikarustech.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (FISHCAMP_LIBRARIES AND FISHCAMP_INCLUDE_DIR)
+
+ # in cache already
+ set(FISHCAMP_FOUND TRUE)
+ message(STATUS "Found FISHCAMP: ${FISHCAMP_LIBRARIES}")
+
+else (FISHCAMP_LIBRARIES AND FISHCAMP_INCLUDE_DIR)
+
+ find_library(FISHCAMP_LIBRARIES NAMES fishcamp
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ find_path(FISHCAMP_INCLUDE_DIR fishcamp.h
+ PATH_SUFFIXES libfishcamp
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ set(CMAKE_REQUIRED_LIBRARIES ${FISHCAMP_LIBRARIES})
+
+ if(FISHCAMP_LIBRARIES AND FISHCAMP_INCLUDE_DIR)
+ set(FISHCAMP_FOUND TRUE)
+ else (FISHCAMP_LIBRARIES AND FISHCAMP_INCLUDE_DIR)
+ set(FISHCAMP_FOUND FALSE)
+ endif(FISHCAMP_LIBRARIES AND FISHCAMP_INCLUDE_DIR)
+
+ if (FISHCAMP_FOUND)
+ if (NOT FISHCAMP_FIND_QUIETLY)
+ message(STATUS "Found FISHCAMP: ${FISHCAMP_LIBRARIES}")
+ endif (NOT FISHCAMP_FIND_QUIETLY)
+ else (FISHCAMP_FOUND)
+ if (FISHCAMP_FIND_REQUIRED)
+ message(FATAL_ERROR "FISHCAMP not found. Please install FISHCAMP library. http://www.indilib.org")
+ endif (FISHCAMP_FIND_REQUIRED)
+ endif (FISHCAMP_FOUND)
+
+ mark_as_advanced(FISHCAMP_LIBRARIES FISHCAMP_INCLUDE_DIR)
+
+endif (FISHCAMP_LIBRARIES AND FISHCAMP_INCLUDE_DIR)
diff --git a/cmake_modules/FindFLI.cmake b/cmake_modules/FindFLI.cmake
new file mode 100644
index 0000000..3881cf7
--- /dev/null
+++ b/cmake_modules/FindFLI.cmake
@@ -0,0 +1,53 @@
+# - Try to find Finger Lakes Instruments Library
+# Once done this will define
+#
+# FLI_FOUND - system has FLI
+# FLI_INCLUDE_DIR - the FLI include directory
+# FLI_LIBRARIES - Link these to use FLI
+
+# Copyright (c) 2008, Jasem Mutlaq <mutlaqja@ikarustech.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (FLI_INCLUDE_DIR AND FLI_LIBRARIES)
+
+ # in cache already
+ set(FLI_FOUND TRUE)
+ message(STATUS "Found libfli: ${FLI_LIBRARIES}")
+
+else (FLI_INCLUDE_DIR AND FLI_LIBRARIES)
+
+ find_path(FLI_INCLUDE_DIR libfli.h
+ PATH_SUFFIXES fli
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(FLI_LIBRARIES NAMES fli
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(FLI_INCLUDE_DIR AND FLI_LIBRARIES)
+ set(FLI_FOUND TRUE)
+ else (FLI_INCLUDE_DIR AND FLI_LIBRARIES)
+ set(FLI_FOUND FALSE)
+ endif(FLI_INCLUDE_DIR AND FLI_LIBRARIES)
+
+
+ if (FLI_FOUND)
+ if (NOT FLI_FIND_QUIETLY)
+ message(STATUS "Found FLI: ${FLI_LIBRARIES}")
+ endif (NOT FLI_FIND_QUIETLY)
+ else (FLI_FOUND)
+ if (FLI_FIND_REQUIRED)
+ message(FATAL_ERROR "FLI not found. Please install libfli-dev. http://www.indilib.org")
+ endif (FLI_FIND_REQUIRED)
+ endif (FLI_FOUND)
+
+ mark_as_advanced(FLI_INCLUDE_DIR FLI_LIBRARIES)
+
+endif (FLI_INCLUDE_DIR AND FLI_LIBRARIES)
diff --git a/cmake_modules/FindFTDI.cmake b/cmake_modules/FindFTDI.cmake
new file mode 100644
index 0000000..35989ce
--- /dev/null
+++ b/cmake_modules/FindFTDI.cmake
@@ -0,0 +1,54 @@
+# - Try to find FTDI
+# This finds libFTDI that is compatible with old libusb v 0.1
+# For newer libusb > 1.0, use FindFTDI1.cmake
+# Once done this will define
+#
+# FTDI_FOUND - system has FTDI
+# FTDI_INCLUDE_DIR - the FTDI include directory
+# FTDI_LIBRARIES - Link these to use FTDI
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (FTDI_INCLUDE_DIR AND FTDI_LIBRARIES)
+
+ # in cache already
+ set(FTDI_FOUND TRUE)
+ message(STATUS "Found libftdi: ${FTDI_LIBRARIES}")
+
+else (FTDI_INCLUDE_DIR AND FTDI_LIBRARIES)
+
+ find_path(FTDI_INCLUDE_DIR ftdi.h
+ PATH_SUFFIXES libftdi1
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ /usr/local/include
+ )
+
+ find_library(FTDI_LIBRARIES NAMES ftdi ftdi1
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ /usr/local/lib
+ )
+
+ if(FTDI_INCLUDE_DIR AND FTDI_LIBRARIES)
+ set(FTDI_FOUND TRUE)
+ else (FTDI_INCLUDE_DIR AND FTDI_LIBRARIES)
+ set(FTDI_FOUND FALSE)
+ endif(FTDI_INCLUDE_DIR AND FTDI_LIBRARIES)
+
+
+ if (FTDI_FOUND)
+ if (NOT FTDI_FIND_QUIETLY)
+ message(STATUS "Found FTDI: ${FTDI_LIBRARIES}")
+ endif (NOT FTDI_FIND_QUIETLY)
+ else (FTDI_FOUND)
+ if (FTDI_FIND_REQUIRED)
+ message(FATAL_ERROR "FTDI not found. Please install libftdi-dev")
+ endif (FTDI_FIND_REQUIRED)
+ endif (FTDI_FOUND)
+
+ mark_as_advanced(FTDI_INCLUDE_DIR FTDI_LIBRARIES)
+
+endif (FTDI_INCLUDE_DIR AND FTDI_LIBRARIES)
diff --git a/cmake_modules/FindFTDI1.cmake b/cmake_modules/FindFTDI1.cmake
new file mode 100644
index 0000000..2199159
--- /dev/null
+++ b/cmake_modules/FindFTDI1.cmake
@@ -0,0 +1,56 @@
+# - Try to find FTDI1
+# Once done this will define
+#
+# FTDI1_FOUND - system has FTDI
+# FTDI1_INCLUDE_DIR - the FTDI include directory
+# FTDI1_LIBRARIES - Link these to use FTDI
+#
+# N.B. You must include the file as following:
+#
+#include <libftdi1/ftdi.h>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (FTDI1_INCLUDE_DIR AND FTDI1_LIBRARIES)
+
+ # in cache already
+ set(FTDI1_FOUND TRUE)
+ message(STATUS "Found libftdi1: ${FTDI1_LIBRARIES}")
+
+else (FTDI1_INCLUDE_DIR AND FTDI1_LIBRARIES)
+
+ find_path(FTDI1_INCLUDE_DIR ftdi.h
+ PATH_SUFFIXES libftdi1
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ /usr/local/include
+ )
+
+ find_library(FTDI1_LIBRARIES NAMES ftdi1
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ /usr/local/lib
+ )
+
+ if(FTDI1_INCLUDE_DIR AND FTDI1_LIBRARIES)
+ set(FTDI1_FOUND TRUE)
+ else (FTDI1_INCLUDE_DIR AND FTDI1_LIBRARIES)
+ set(FTDI1_FOUND FALSE)
+ endif(FTDI1_INCLUDE_DIR AND FTDI1_LIBRARIES)
+
+
+ if (FTDI1_FOUND)
+ if (NOT FTDI1_FIND_QUIETLY)
+ message(STATUS "Found FTDI1: ${FTDI1_LIBRARIES}")
+ endif (NOT FTDI1_FIND_QUIETLY)
+ else (FTDI1_FOUND)
+ if (FTDI1_FIND_REQUIRED)
+ message(FATAL_ERROR "FTDI not found. Please install libftdi1-dev")
+ endif (FTDI1_FIND_REQUIRED)
+ endif (FTDI1_FOUND)
+
+ mark_as_advanced(FTDI1_INCLUDE_DIR FTDI1_LIBRARIES)
+
+endif (FTDI1_INCLUDE_DIR AND FTDI1_LIBRARIES)
diff --git a/cmake_modules/FindGLIB2.cmake b/cmake_modules/FindGLIB2.cmake
new file mode 100644
index 0000000..976be36
--- /dev/null
+++ b/cmake_modules/FindGLIB2.cmake
@@ -0,0 +1,218 @@
+# - Try to find GLib2
+# Once done this will define
+#
+# GLIB2_FOUND - system has GLib2
+# GLIB2_INCLUDE_DIRS - the GLib2 include directory
+# GLIB2_LIBRARIES - Link these to use GLib2
+#
+# HAVE_GLIB_GREGEX_H glib has gregex.h header and
+# supports g_regex_match_simple
+#
+# Copyright (c) 2006 Andreas Schneider <mail@cynapses.org>
+# Copyright (c) 2006 Philippe Bernery <philippe.bernery@gmail.com>
+# Copyright (c) 2007 Daniel Gollub <dgollub@suse.de>
+# Copyright (c) 2007 Alban Browaeys <prahal@yahoo.com>
+# Copyright (c) 2008 Michael Bell <michael.bell@web.de>
+# Copyright (c) 2008 Bjoern Ricks <bjoern.ricks@googlemail.com>
+#
+# Redistribution and use is allowed according to the terms of the New
+# BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+
+
+IF (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS )
+ # in cache already
+ SET(GLIB2_FOUND TRUE)
+ELSE (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS )
+
+ INCLUDE(FindPkgConfig)
+
+ ## Glib
+ IF ( GLIB2_FIND_REQUIRED )
+ SET( _pkgconfig_REQUIRED "REQUIRED" )
+ ELSE ( GLIB2_FIND_REQUIRED )
+ SET( _pkgconfig_REQUIRED "" )
+ ENDIF ( GLIB2_FIND_REQUIRED )
+
+ IF ( GLIB2_MIN_VERSION )
+ PKG_SEARCH_MODULE( GLIB2 ${_pkgconfig_REQUIRED} glib-2.0>=${GLIB2_MIN_VERSION} )
+ ELSE ( GLIB2_MIN_VERSION )
+ PKG_SEARCH_MODULE( GLIB2 ${_pkgconfig_REQUIRED} glib-2.0 )
+ ENDIF ( GLIB2_MIN_VERSION )
+ IF ( PKG_CONFIG_FOUND )
+ IF ( GLIB2_FOUND )
+ SET ( GLIB2_CORE_FOUND TRUE )
+ ELSE ( GLIB2_FOUND )
+ SET ( GLIB2_CORE_FOUND FALSE )
+ ENDIF ( GLIB2_FOUND )
+ ENDIF ( PKG_CONFIG_FOUND )
+
+ # Look for glib2 include dir and libraries w/o pkgconfig
+ IF ( NOT GLIB2_FOUND AND NOT PKG_CONFIG_FOUND )
+ FIND_PATH(
+ _glibconfig_include_DIR
+ NAMES
+ glibconfig.h
+ PATHS
+ /opt/gnome/lib64
+ /opt/gnome/lib
+ /opt/lib/
+ /opt/local/lib
+ /sw/lib/
+ /usr/lib64
+ /usr/lib
+ /usr/local/include
+ ${CMAKE_LIBRARY_PATH}
+ PATH_SUFFIXES
+ glib-2.0/include
+ )
+
+ FIND_PATH(
+ _glib2_include_DIR
+ NAMES
+ glib.h
+ PATHS
+ /opt/gnome/include
+ /opt/local/include
+ /sw/include
+ /usr/include
+ /usr/local/include
+ PATH_SUFFIXES
+ glib-2.0
+ )
+
+ #MESSAGE(STATUS "Glib headers: ${_glib2_include_DIR}")
+
+ FIND_LIBRARY(
+ _glib2_link_DIR
+ NAMES
+ glib-2.0
+ glib
+ PATHS
+ /opt/gnome/lib
+ /opt/local/lib
+ /sw/lib
+ /usr/lib
+ /usr/local/lib
+ )
+ IF ( _glib2_include_DIR AND _glib2_link_DIR )
+ SET ( _glib2_FOUND TRUE )
+ ENDIF ( _glib2_include_DIR AND _glib2_link_DIR )
+
+
+ IF ( _glib2_FOUND )
+ SET ( GLIB2_INCLUDE_DIRS ${_glib2_include_DIR} ${_glibconfig_include_DIR} )
+ SET ( GLIB2_LIBRARIES ${_glib2_link_DIR} )
+ SET ( GLIB2_CORE_FOUND TRUE )
+ ELSE ( _glib2_FOUND )
+ SET ( GLIB2_CORE_FOUND FALSE )
+ ENDIF ( _glib2_FOUND )
+
+ # Handle dependencies
+ # libintl
+ IF ( NOT LIBINTL_FOUND )
+ FIND_PATH(LIBINTL_INCLUDE_DIR
+ NAMES
+ libintl.h
+ PATHS
+ /opt/gnome/include
+ /opt/local/include
+ /sw/include
+ /usr/include
+ /usr/local/include
+ )
+
+ FIND_LIBRARY(LIBINTL_LIBRARY
+ NAMES
+ intl
+ PATHS
+ /opt/gnome/lib
+ /opt/local/lib
+ /sw/lib
+ /usr/local/lib
+ /usr/lib
+ )
+
+ IF (LIBINTL_LIBRARY AND LIBINTL_INCLUDE_DIR)
+ SET (LIBINTL_FOUND TRUE)
+ ENDIF (LIBINTL_LIBRARY AND LIBINTL_INCLUDE_DIR)
+ ENDIF ( NOT LIBINTL_FOUND )
+
+ # libiconv
+ IF ( NOT LIBICONV_FOUND )
+ FIND_PATH(LIBICONV_INCLUDE_DIR
+ NAMES
+ iconv.h
+ PATHS
+ /opt/gnome/include
+ /opt/local/include
+ /opt/local/include
+ /sw/include
+ /sw/include
+ /usr/local/include
+ /usr/include
+ PATH_SUFFIXES
+ glib-2.0
+ )
+
+ FIND_LIBRARY(LIBICONV_LIBRARY
+ NAMES
+ iconv
+ PATHS
+ /opt/gnome/lib
+ /opt/local/lib
+ /sw/lib
+ /usr/lib
+ /usr/local/lib
+ )
+
+ IF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR)
+ SET (LIBICONV_FOUND TRUE)
+ ENDIF (LIBICONV_LIBRARY AND LIBICONV_INCLUDE_DIR)
+ ENDIF ( NOT LIBICONV_FOUND )
+
+ IF (LIBINTL_FOUND)
+ SET (GLIB2_LIBRARIES ${GLIB2_LIBRARIES} ${LIBINTL_LIBRARY})
+ SET (GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS} ${LIBINTL_INCLUDE_DIR})
+ ENDIF (LIBINTL_FOUND)
+
+ IF (LIBICONV_FOUND)
+ SET (GLIB2_LIBRARIES ${GLIB2_LIBRARIES} ${LIBICONV_LIBRARY})
+ SET (GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS} ${LIBICONV_INCLUDE_DIR})
+ ENDIF (LIBICONV_FOUND)
+
+ ENDIF ( NOT GLIB2_FOUND AND NOT PKG_CONFIG_FOUND )
+ ##
+
+ IF (GLIB2_CORE_FOUND AND GLIB2_INCLUDE_DIRS AND GLIB2_LIBRARIES)
+ SET (GLIB2_FOUND TRUE)
+ ENDIF (GLIB2_CORE_FOUND AND GLIB2_INCLUDE_DIRS AND GLIB2_LIBRARIES)
+
+ IF (GLIB2_FOUND)
+ IF (NOT GLIB2_FIND_QUIETLY)
+ MESSAGE (STATUS "Found GLib2: ${GLIB2_LIBRARIES} ${GLIB2_INCLUDE_DIRS}")
+ ENDIF (NOT GLIB2_FIND_QUIETLY)
+ ELSE (GLIB2_FOUND)
+ IF (GLIB2_FIND_REQUIRED)
+ MESSAGE (SEND_ERROR "Could not find GLib2")
+ ENDIF (GLIB2_FIND_REQUIRED)
+ ENDIF (GLIB2_FOUND)
+
+ # show the GLIB2_INCLUDE_DIRS and GLIB2_LIBRARIES variables only in the advanced view
+ MARK_AS_ADVANCED(GLIB2_INCLUDE_DIRS GLIB2_LIBRARIES)
+ MARK_AS_ADVANCED(LIBICONV_INCLUDE_DIR LIBICONV_LIBRARY)
+ MARK_AS_ADVANCED(LIBINTL_INCLUDE_DIR LIBINTL_LIBRARY)
+
+ENDIF (GLIB2_LIBRARIES AND GLIB2_INCLUDE_DIRS)
+
+IF ( GLIB2_FOUND )
+ # Check if system has a newer version of glib
+ # which supports g_regex_match_simple
+ INCLUDE( CheckIncludeFiles )
+ SET( CMAKE_REQUIRED_INCLUDES ${GLIB2_INCLUDE_DIRS} )
+ CHECK_INCLUDE_FILES ( glib/gregex.h HAVE_GLIB_GREGEX_H )
+ # Reset CMAKE_REQUIRED_INCLUDES
+ SET( CMAKE_REQUIRED_INCLUDES "" )
+ENDIF( GLIB2_FOUND )
+
diff --git a/cmake_modules/FindGMock.cmake b/cmake_modules/FindGMock.cmake
new file mode 100644
index 0000000..3187d72
--- /dev/null
+++ b/cmake_modules/FindGMock.cmake
@@ -0,0 +1,184 @@
+#.rst:
+# FindGMock
+# ---------
+#
+# Locate the Google C++ Mocking Framework.
+#
+# Defines the following variables:
+#
+# ::
+#
+# GMOCK_FOUND - Found the Google Mocking framework
+# GMOCK_INCLUDE_DIRS - Include directories
+#
+#
+#
+# Also defines the library variables below as normal variables. These
+# contain debug/optimized keywords when a debugging library is found.
+#
+# ::
+#
+# GMOCK_LIBRARIES - libgmock
+#
+#
+#
+# Accepts the following variables as input:
+#
+# ::
+#
+# GMOCK_ROOT - (as a CMake or environment variable)
+# The root directory of the gmock install prefix
+#
+#
+#
+# ::
+#
+# GMOCK_MSVC_SEARCH - If compiling with MSVC, this variable can be set to
+# "MD" or "MT" to enable searching a GMock build tree
+# (defaults: "MD")
+#
+#
+#
+# Example Usage:
+#
+# ::
+#
+# find_package(GMock REQUIRED)
+# include_directories(${GMOCK_INCLUDE_DIRS})
+#
+#
+#
+# ::
+#
+# add_executable(foo foo.cc)
+# target_link_libraries(foo ${GMOCK_LIBRARIES})
+#
+#
+#
+# ::
+#
+# add_test(AllMocksInFoo foo)
+#
+#
+#
+#
+#
+# If you would like each Google test to show up in CMock as a test you
+# may use the following macro. NOTE: It will slow down your tests by
+# running an executable for each test and test fixture. You will also
+# have to rerun CMake after adding or removing tests or test fixtures.
+#
+# GMOCK_ADD_MOCKS(executable extra_args ARGN)
+#
+# ::
+#
+# executable = The path to the test executable
+# extra_args = Pass a list of extra arguments to be passed to
+# executable enclosed in quotes (or "" for none)
+# ARGN = A list of source files to search for tests & test
+# fixtures.
+#
+#
+#
+# ::
+#
+# Example:
+# set(FooMockArgs --foo 1 --bar 2)
+# add_executable(FooMock FooUnitMock.cc)
+# GMOCK_ADD_MOCKS(FooMock "${FooMockArgs}" FooUnitMock.cc)
+
+#=============================================================================
+# Copyright 2009 Kitware, Inc.
+# Copyright 2009 Philip Lowman <philip@yhbt.com>
+# Copyright 2009 Daniel Blezek <blezek@gmail.com>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+#
+# Thanks to Daniel Blezek <blezek@gmail.com> for the GMOCK_ADD_MOCKS code
+
+function(GMOCK_ADD_MOCKS executable extra_args)
+ if(NOT ARGN)
+ message(FATAL_ERROR "Missing ARGN: Read the documentation for GMOCK_ADD_MOCKS")
+ endif()
+ foreach(source ${ARGN})
+ file(READ "${source}" contents)
+ string(REGEX MATCHALL "MOCK_?F?\\(([A-Za-z_0-9 ,]+)\\)" found_tests ${contents})
+ foreach(hit ${found_tests})
+ string(REGEX REPLACE ".*\\( *([A-Za-z_0-9]+), *([A-Za-z_0-9]+) *\\).*" "\\1.\\2" test_name ${hit})
+ add_test(${test_name} ${executable} --gmock_filter=${test_name} ${extra_args})
+ endforeach()
+ endforeach()
+endfunction()
+
+function(_gmock_append_debugs _endvar _library)
+ if(${_library} AND ${_library}_DEBUG)
+ set(_output optimized ${${_library}} debug ${${_library}_DEBUG})
+ else()
+ set(_output ${${_library}})
+ endif()
+ set(${_endvar} ${_output} PARENT_SCOPE)
+endfunction()
+
+function(_gmock_find_library _name)
+ find_library(${_name}
+ NAMES ${ARGN}
+ HINTS
+ ENV GMOCK_ROOT
+ ${GMOCK_ROOT}
+ PATH_SUFFIXES ${_gmock_libpath_suffixes}
+ )
+ mark_as_advanced(${_name})
+endfunction()
+
+#
+
+if(NOT DEFINED GMOCK_MSVC_SEARCH)
+ set(GMOCK_MSVC_SEARCH MD)
+endif()
+
+set(_gmock_libpath_suffixes lib)
+if(MSVC)
+ if(GMOCK_MSVC_SEARCH STREQUAL "MD")
+ list(APPEND _gmock_libpath_suffixes
+ msvc/gmock-md/Debug
+ msvc/gmock-md/Release)
+ elseif(GMOCK_MSVC_SEARCH STREQUAL "MT")
+ list(APPEND _gmock_libpath_suffixes
+ msvc/gmock/Debug
+ msvc/gmock/Release)
+ endif()
+endif()
+
+
+find_path(GMOCK_INCLUDE_DIR gmock/gmock.h
+ HINTS
+ $ENV{GMOCK_ROOT}/include
+ ${GMOCK_ROOT}/include
+)
+mark_as_advanced(GMOCK_INCLUDE_DIR)
+
+if(MSVC AND GMOCK_MSVC_SEARCH STREQUAL "MD")
+ # The provided /MD project files for Google Mock add -md suffixes to the
+ # library names.
+ _gmock_find_library(GMOCK_LIBRARY gmock-md gmock)
+ _gmock_find_library(GMOCK_LIBRARY_DEBUG gmock-mdd gmockd)
+else()
+ _gmock_find_library(GMOCK_LIBRARY gmock)
+ _gmock_find_library(GMOCK_LIBRARY_DEBUG gmockd)
+endif()
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GMock DEFAULT_MSG GMOCK_LIBRARY GMOCK_INCLUDE_DIR)
+
+if(GMOCK_FOUND)
+ set(GMOCK_INCLUDE_DIRS ${GMOCK_INCLUDE_DIR})
+ _gmock_append_debugs(GMOCK_LIBRARIES GMOCK_LIBRARY)
+endif()
+
diff --git a/cmake_modules/FindGPHOTO2.cmake b/cmake_modules/FindGPHOTO2.cmake
new file mode 100644
index 0000000..e5ffe29
--- /dev/null
+++ b/cmake_modules/FindGPHOTO2.cmake
@@ -0,0 +1,66 @@
+# - Find the native sqlite3 includes and library
+#
+# This module defines
+# GPHOTO2_INCLUDE_DIR, where to find libgphoto2 header files
+# GPHOTO2_LIBRARIES, the libraries to link against to use libgphoto2
+# GPHOTO2_FOUND, If false, do not try to use libgphoto2.
+# GPHOTO2_VERSION_STRING, e.g. 2.4.14
+# GPHOTO2_VERSION_MAJOR, e.g. 2
+# GPHOTO2_VERSION_MINOR, e.g. 4
+# GPHOTO2_VERSION_PATCH, e.g. 14
+#
+# also defined, but not for general use are
+# GPHOTO2_LIBRARY, where to find the sqlite3 library.
+
+
+#=============================================================================
+# Copyright 2010 henrik andersson
+#=============================================================================
+
+SET(GPHOTO2_FIND_REQUIRED ${Gphoto2_FIND_REQUIRED})
+
+find_path(GPHOTO2_INCLUDE_DIR gphoto2/gphoto2.h)
+mark_as_advanced(GPHOTO2_INCLUDE_DIR)
+
+set(GPHOTO2_NAMES ${GPHOTO2_NAMES} gphoto2 libgphoto2)
+set(GPHOTO2_PORT_NAMES ${GPHOTO2_PORT_NAMES} gphoto2_port libgphoto2_port)
+find_library(GPHOTO2_LIBRARY NAMES ${GPHOTO2_NAMES} )
+find_library(GPHOTO2_PORT_LIBRARY NAMES ${GPHOTO2_PORT_NAMES} )
+mark_as_advanced(GPHOTO2_LIBRARY)
+mark_as_advanced(GPHOTO2_PORT_LIBRARY)
+
+# Detect libgphoto2 version
+FIND_PROGRAM(GPHOTO2CONFIG_EXECUTABLE NAMES gphoto2-config)
+IF(GPHOTO2CONFIG_EXECUTABLE)
+ EXEC_PROGRAM(${GPHOTO2CONFIG_EXECUTABLE} ARGS --version RETURN_VALUE _return_VALUE OUTPUT_VARIABLE GPHOTO2_VERSION)
+ string(REGEX REPLACE "^.*libgphoto2 ([0-9]+).*$" "\\1" GPHOTO2_VERSION_MAJOR "${GPHOTO2_VERSION}")
+ string(REGEX REPLACE "^.*libgphoto2 [0-9]+\\.([0-9]+).*$" "\\1" GPHOTO2_VERSION_MINOR "${GPHOTO2_VERSION}")
+ string(REGEX REPLACE "^.*libgphoto2 [0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" GPHOTO2_VERSION_PATCH "${GPHOTO2_VERSION}")
+
+ set(GPHOTO2_VERSION_STRING "${GPHOTO2_VERSION_MAJOR}.${GPHOTO2_VERSION_MINOR}.${GPHOTO2_VERSION_PATCH}")
+ENDIF(GPHOTO2CONFIG_EXECUTABLE)
+
+# handle the QUIETLY and REQUIRED arguments and set GPHOTO2_FOUND to TRUE if
+# all listed variables are TRUE
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(GPHOTO2 DEFAULT_MSG GPHOTO2_LIBRARY GPHOTO2_INCLUDE_DIR)
+
+IF(GPHOTO2_FOUND)
+ SET(Gphoto2_LIBRARIES ${GPHOTO2_LIBRARY} ${GPHOTO2_PORT_LIBRARY})
+ SET(Gphoto2_INCLUDE_DIRS ${GPHOTO2_INCLUDE_DIR})
+
+ # libgphoto2 dynamically loads and unloads usb library
+ # without calling any cleanup functions (since they are absent from libusb-0.1).
+ # This leaves usb event handling threads running with invalid callback and return addresses,
+ # which causes a crash after any usb event is generated, at least in Mac OS X.
+ # libusb1 backend does correctly call exit function, but ATM it crashes anyway.
+ # Workaround is to link against libusb so that it wouldn't get unloaded.
+ IF(APPLE)
+ find_library(USB_LIBRARY NAMES usb-1.0 libusb-1.0)
+ mark_as_advanced(USB_LIBRARY)
+ IF(USB_LIBRARY)
+ SET(Gphoto2_LIBRARIES ${Gphoto2_LIBRARIES} ${USB_LIBRARY})
+ ENDIF(USB_LIBRARY)
+ ENDIF(APPLE)
+
+ENDIF(GPHOTO2_FOUND)
diff --git a/cmake_modules/FindGPSD.cmake b/cmake_modules/FindGPSD.cmake
new file mode 100644
index 0000000..d5dc416
--- /dev/null
+++ b/cmake_modules/FindGPSD.cmake
@@ -0,0 +1,19 @@
+# - Find GPSD
+# Find the native GPSD includes and library
+
+FIND_PATH(GPSD_INCLUDE_DIR libgpsmm.h gps.h)
+
+SET(GPSD_NAMES ${GPSD_NAMES} gps)
+FIND_LIBRARY(GPSD_LIBRARY NAMES ${GPSD_NAMES} )
+
+# handle the QUIETLY and REQUIRED arguments and set JPEG_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GPSD DEFAULT_MSG GPSD_LIBRARY GPSD_INCLUDE_DIR)
+
+IF(GPSD_FOUND)
+ SET(GPSD_LIBRARIES ${GPSD_LIBRARY})
+ message(STATUS "Found libgps: ${GPSD_LIBRARIES}")
+ENDIF(GPSD_FOUND)
+
+
diff --git a/cmake_modules/FindGSL.cmake b/cmake_modules/FindGSL.cmake
new file mode 100644
index 0000000..ef125c0
--- /dev/null
+++ b/cmake_modules/FindGSL.cmake
@@ -0,0 +1,238 @@
+#.rst:
+# FindGSL
+# --------
+#
+# Find the native GSL includes and libraries.
+#
+# The GNU Scientific Library (GSL) is a numerical library for C and C++
+# programmers. It is free software under the GNU General Public
+# License.
+#
+# Imported Targets
+# ^^^^^^^^^^^^^^^^
+#
+# If GSL is found, this module defines the following :prop_tgt:`IMPORTED`
+# targets::
+#
+# GSL::gsl - The main GSL library.
+# GSL::gslcblas - The CBLAS support library used by GSL.
+#
+# Result Variables
+# ^^^^^^^^^^^^^^^^
+#
+# This module will set the following variables in your project::
+#
+# GSL_FOUND - True if GSL found on the local system
+# GSL_INCLUDE_DIRS - Location of GSL header files.
+# GSL_LIBRARIES - The GSL libraries.
+# GSL_VERSION - The version of the discovered GSL install.
+#
+# Hints
+# ^^^^^
+#
+# Set ``GSL_ROOT_DIR`` to a directory that contains a GSL installation.
+#
+# This script expects to find libraries at ``$GSL_ROOT_DIR/lib`` and the GSL
+# headers at ``$GSL_ROOT_DIR/include/gsl``. The library directory may
+# optionally provide Release and Debug folders. For Unix-like systems, this
+# script will use ``$GSL_ROOT_DIR/bin/gsl-config`` (if found) to aid in the
+# discovery GSL.
+#
+# Cache Variables
+# ^^^^^^^^^^^^^^^
+#
+# This module may set the following variables depending on platform and type
+# of GSL installation discovered. These variables may optionally be set to
+# help this module find the correct files::
+#
+# GSL_CLBAS_LIBRARY - Location of the GSL CBLAS library.
+# GSL_CBLAS_LIBRARY_DEBUG - Location of the debug GSL CBLAS library (if any).
+# GSL_CONFIG_EXECUTABLE - Location of the ``gsl-config`` script (if any).
+# GSL_LIBRARY - Location of the GSL library.
+# GSL_LIBRARY_DEBUG - Location of the debug GSL library (if any).
+#
+
+#=============================================================================
+# Copyright 2014 Kelly Thompson <kgt@lanl.gov>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+# Include these modules to handle the QUIETLY and REQUIRED arguments.
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+
+#=============================================================================
+# If the user has provided ``GSL_ROOT_DIR``, use it! Choose items found
+# at this location over system locations.
+if( EXISTS "$ENV{GSL_ROOT_DIR}" )
+ file( TO_CMAKE_PATH "$ENV{GSL_ROOT_DIR}" GSL_ROOT_DIR )
+ set( GSL_ROOT_DIR "${GSL_ROOT_DIR}" CACHE PATH "Prefix for GSL installation." )
+endif()
+if( NOT EXISTS "${GSL_ROOT_DIR}" )
+ set( GSL_USE_PKGCONFIG ON )
+endif()
+
+#=============================================================================
+# As a first try, use the PkgConfig module. This will work on many
+# *NIX systems. See :module:`findpkgconfig`
+# This will return ``GSL_INCLUDEDIR`` and ``GSL_LIBDIR`` used below.
+if( GSL_USE_PKGCONFIG )
+ find_package(PkgConfig)
+ pkg_check_modules( GSL QUIET gsl )
+
+ if( EXISTS "${GSL_INCLUDEDIR}" )
+ get_filename_component( GSL_ROOT_DIR "${GSL_INCLUDEDIR}" DIRECTORY CACHE)
+ endif()
+endif()
+
+#=============================================================================
+# Set GSL_INCLUDE_DIRS and GSL_LIBRARIES. If we skipped the PkgConfig step, try
+# to find the libraries at $GSL_ROOT_DIR (if provided) or in standard system
+# locations. These find_library and find_path calls will prefer custom
+# locations over standard locations (HINTS). If the requested file is not found
+# at the HINTS location, standard system locations will be still be searched
+# (/usr/lib64 (Redhat), lib/i386-linux-gnu (Debian)).
+
+find_path( GSL_INCLUDE_DIR
+ NAMES gsl/gsl_sf.h
+ HINTS ${GSL_ROOT_DIR}/include ${GSL_INCLUDEDIR}
+)
+find_library( GSL_LIBRARY
+ NAMES gsl
+ HINTS ${GSL_ROOT_DIR}/lib ${GSL_LIBDIR}
+ PATH_SUFFIXES Release Debug
+)
+find_library( GSL_CBLAS_LIBRARY
+ NAMES gslcblas cblas
+ HINTS ${GSL_ROOT_DIR}/lib ${GSL_LIBDIR}
+ PATH_SUFFIXES Release Debug
+)
+# Do we also have debug versions?
+find_library( GSL_LIBRARY_DEBUG
+ NAMES gsl
+ HINTS ${GSL_ROOT_DIR}/lib ${GSL_LIBDIR}
+ PATH_SUFFIXES Debug
+)
+find_library( GSL_CBLAS_LIBRARY_DEBUG
+ NAMES gslcblas cblas
+ HINTS ${GSL_ROOT_DIR}/lib ${GSL_LIBDIR}
+ PATH_SUFFIXES Debug
+)
+set( GSL_INCLUDE_DIRS ${GSL_INCLUDE_DIR} )
+set( GSL_LIBRARIES ${GSL_LIBRARY} ${GSL_CBLAS_LIBRARY} )
+
+# If we didn't use PkgConfig, try to find the version via gsl-config or by
+# reading gsl_version.h.
+if( NOT GSL_VERSION )
+ # 1. If gsl-config exists, query for the version.
+ find_program( GSL_CONFIG_EXECUTABLE
+ NAMES gsl-config
+ HINTS "${GSL_ROOT_DIR}/bin"
+ )
+ if( EXISTS "${GSL_CONFIG_EXECUTABLE}" )
+ execute_process(
+ COMMAND "${GSL_CONFIG_EXECUTABLE}" --version
+ OUTPUT_VARIABLE GSL_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE )
+ endif()
+
+ # 2. If gsl-config is not available, try looking in gsl/gsl_version.h
+ if( NOT GSL_VERSION AND EXISTS "${GSL_INCLUDE_DIRS}/gsl/gsl_version.h" )
+ file( STRINGS "${GSL_INCLUDE_DIRS}/gsl/gsl_version.h" gsl_version_h_contents REGEX "define GSL_VERSION" )
+ string( REGEX REPLACE ".*([0-9].[0-9][0-9]).*" "\\1" GSL_VERSION ${gsl_version_h_contents} )
+ endif()
+
+ # might also try scraping the directory name for a regex match "gsl-X.X"
+endif()
+
+#=============================================================================
+# handle the QUIETLY and REQUIRED arguments and set GSL_FOUND to TRUE if all
+# listed variables are TRUE
+find_package_handle_standard_args( GSL
+ FOUND_VAR
+ GSL_FOUND
+ REQUIRED_VARS
+ GSL_INCLUDE_DIR
+ GSL_LIBRARY
+ GSL_CBLAS_LIBRARY
+ VERSION_VAR
+ GSL_VERSION
+ )
+
+mark_as_advanced( GSL_ROOT_DIR GSL_VERSION GSL_LIBRARY GSL_INCLUDE_DIR
+ GSL_CBLAS_LIBRARY GSL_LIBRARY_DEBUG GSL_CBLAS_LIBRARY_DEBUG
+ GSL_USE_PKGCONFIG GSL_CONFIG )
+
+#=============================================================================
+# Register imported libraries:
+# 1. If we can find a Windows .dll file (or if we can find both Debug and
+# Release libraries), we will set appropriate target properties for these.
+# 2. However, for most systems, we will only register the import location and
+# include directory.
+
+# Look for dlls, or Release and Debug libraries.
+if(WIN32)
+ string( REPLACE ".lib" ".dll" GSL_LIBRARY_DLL "${GSL_LIBRARY}" )
+ string( REPLACE ".lib" ".dll" GSL_CBLAS_LIBRARY_DLL "${GSL_CBLAS_LIBRARY}" )
+ string( REPLACE ".lib" ".dll" GSL_LIBRARY_DEBUG_DLL "${GSL_LIBRARY_DEBUG}" )
+ string( REPLACE ".lib" ".dll" GSL_CBLAS_LIBRARY_DEBUG_DLL "${GSL_CBLAS_LIBRARY_DEBUG}" )
+endif()
+
+if( GSL_FOUND AND NOT TARGET GSL::gsl )
+ if( EXISTS "${GSL_LIBRARY_DLL}" AND EXISTS "${GSL_CBLAS_LIBRARY_DLL}")
+
+ # Windows systems with dll libraries.
+ add_library( GSL::gsl SHARED IMPORTED )
+ add_library( GSL::gslcblas SHARED IMPORTED )
+
+ # Windows with dlls, but only Release libraries.
+ set_target_properties( GSL::gslcblas PROPERTIES
+ IMPORTED_LOCATION_RELEASE "${GSL_CBLAS_LIBRARY_DLL}"
+ IMPORTED_IMPLIB "${GSL_CBLAS_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${GSL_INCLUDE_DIRS}"
+ IMPORTED_CONFIGURATIONS Release
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C" )
+ set_target_properties( GSL::gsl PROPERTIES
+ IMPORTED_LOCATION_RELEASE "${GSL_LIBRARY_DLL}"
+ IMPORTED_IMPLIB "${GSL_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${GSL_INCLUDE_DIRS}"
+ IMPORTED_CONFIGURATIONS Release
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ INTERFACE_LINK_LIBRARIES GSL::gslcblas )
+
+ # If we have both Debug and Release libraries
+ if( EXISTS "${GSL_LIBRARY_DEBUG_DLL}" AND EXISTS "${GSL_CBLAS_LIBRARY_DEBUG_DLL}")
+ set_property( TARGET GSL::gslcblas APPEND PROPERTY IMPORTED_CONFIGURATIONS Debug )
+ set_target_properties( GSL::gslcblas PROPERTIES
+ IMPORTED_LOCATION_DEBUG "${GSL_CBLAS_LIBRARY_DEBUG_DLL}"
+ IMPORTED_IMPLIB_DEBUG "${GSL_CBLAS_LIBRARY_DEBUG}" )
+ set_property( TARGET GSL::gsl APPEND PROPERTY IMPORTED_CONFIGURATIONS Debug )
+ set_target_properties( GSL::gsl PROPERTIES
+ IMPORTED_LOCATION_DEBUG "${GSL_LIBRARY_DEBUG_DLL}"
+ IMPORTED_IMPLIB_DEBUG "${GSL_LIBRARY_DEBUG}" )
+ endif()
+
+ else()
+
+ # For all other environments (ones without dll libraries), create
+ # the imported library targets.
+ add_library( GSL::gsl UNKNOWN IMPORTED )
+ add_library( GSL::gslcblas UNKNOWN IMPORTED )
+ set_target_properties( GSL::gslcblas PROPERTIES
+ IMPORTED_LOCATION "${GSL_CBLAS_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${GSL_INCLUDE_DIRS}"
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C" )
+ set_target_properties( GSL::gsl PROPERTIES
+ IMPORTED_LOCATION "${GSL_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${GSL_INCLUDE_DIRS}"
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ INTERFACE_LINK_LIBRARIES GSL::gslcblas )
+ endif()
+endif()
diff --git a/cmake_modules/FindINDI.cmake b/cmake_modules/FindINDI.cmake
new file mode 100644
index 0000000..b18991f
--- /dev/null
+++ b/cmake_modules/FindINDI.cmake
@@ -0,0 +1,320 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This module can find INDI Library
+#
+# Requirements:
+# - CMake >= 2.8.3 (for new version of find_package_handle_standard_args)
+#
+# The following variables will be defined for your use:
+# - INDI_FOUND : were all of your specified components found (include dependencies)?
+# - INDI_WEBSOCKET : was INDI compiled with websocket support?
+# - INDI_INCLUDE_DIR : INDI include directory
+# - INDI_DATA_DIR : INDI include directory
+# - INDI_LIBRARIES : INDI libraries
+# - INDI_DRIVER_LIBRARIES : Same as above maintained for backward compatibility
+# - INDI_VERSION : complete version of INDI (x.y.z)
+# - INDI_MAJOR_VERSION : major version of INDI
+# - INDI_MINOR_VERSION : minor version of INDI
+# - INDI_RELEASE_VERSION : release version of INDI
+# - INDI_<COMPONENT>_FOUND : were <COMPONENT> found? (FALSE for non specified component if it is not a dependency)
+#
+# For windows or non standard installation, define INDI_ROOT variable to point to the root installation of INDI. Two ways:
+# - run cmake with -DINDI_ROOT=<PATH>
+# - define an environment variable with the same name before running cmake
+# With cmake-gui, before pressing "Configure":
+# 1) Press "Add Entry" button
+# 2) Add a new entry defined as:
+# - Name: INDI_ROOT
+# - Type: choose PATH in the selection list
+# - Press "..." button and select the root installation of INDI
+#
+# Example Usage:
+#
+# 1. Copy this file in the root of your project source directory
+# 2. Then, tell CMake to search this non-standard module in your project directory by adding to your CMakeLists.txt:
+# set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
+# 3. Finally call find_package() once, here are some examples to pick from
+#
+# Require INDI 1.4 or later
+# find_package(INDI 1.4 REQUIRED)
+#
+# if(INDI_FOUND)
+# include_directories(${INDI_INCLUDE_DIR})
+# add_executable(myapp myapp.cpp)
+# target_link_libraries(myapp ${INDI_LIBRARIES})
+# endif(INDI_FOUND)
+#
+#
+# Using Components:
+#
+# You can search for specific components. Currently, the following components are available
+# * driver: to build INDI hardware drivers.
+# * align: to build drivers that use INDI Alignment Subsystem.
+# * client: to build pure C++ INDI clients.
+# * clientqt5: to build Qt5-based INDI clients.
+# * lx200: To build LX200-based 3rd party drivers (you must link with driver above as well).
+#
+# By default, if you do not specify any components, driver and align components are searched.
+#
+# Example:
+#
+# To use INDI Qt5 Client library only in your application:
+#
+# find_package(INDI COMPONENTS clientqt5 REQUIRED)
+#
+# if(INDI_FOUND)
+# include_directories(${INDI_INCLUDE_DIR})
+# add_executable(myapp myapp.cpp)
+# target_link_libraries(myapp ${INDI_LIBRARIES})
+# endif(INDI_FOUND)
+#
+# To use INDI driver + lx200 component in your application:
+#
+# find_package(INDI COMPONENTS driver lx200 REQUIRED)
+#
+# if(INDI_FOUND)
+# include_directories(${INDI_INCLUDE_DIR})
+# add_executable(myapp myapp.cpp)
+# target_link_libraries(myapp ${INDI_LIBRARIES})
+# endif(INDI_FOUND)
+#
+# Notice we still use ${INDI_LIBRARIES} which now should contain both driver & lx200 libraries.
+#==============================================================================================
+# Copyright (c) 2011-2013, julp
+# Copyright (c) 2017-2019 Jasem Mutlaq
+#
+# Distributed under the OSI-approved BSD License
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTINDILAR PURPOSE.
+#=============================================================================
+
+find_package(PkgConfig QUIET)
+
+########## Private ##########
+if(NOT DEFINED INDI_PUBLIC_VAR_NS)
+ set(INDI_PUBLIC_VAR_NS "INDI") # Prefix for all INDI relative public variables
+endif(NOT DEFINED INDI_PUBLIC_VAR_NS)
+if(NOT DEFINED INDI_PRIVATE_VAR_NS)
+ set(INDI_PRIVATE_VAR_NS "_${INDI_PUBLIC_VAR_NS}") # Prefix for all INDI relative internal variables
+endif(NOT DEFINED INDI_PRIVATE_VAR_NS)
+if(NOT DEFINED PC_INDI_PRIVATE_VAR_NS)
+ set(PC_INDI_PRIVATE_VAR_NS "_PC${INDI_PRIVATE_VAR_NS}") # Prefix for all pkg-config relative internal variables
+endif(NOT DEFINED PC_INDI_PRIVATE_VAR_NS)
+
+function(indidebug _VARNAME)
+ if(${INDI_PUBLIC_VAR_NS}_DEBUG)
+ if(DEFINED ${INDI_PUBLIC_VAR_NS}_${_VARNAME})
+ message("${INDI_PUBLIC_VAR_NS}_${_VARNAME} = ${${INDI_PUBLIC_VAR_NS}_${_VARNAME}}")
+ else(DEFINED ${INDI_PUBLIC_VAR_NS}_${_VARNAME})
+ message("${INDI_PUBLIC_VAR_NS}_${_VARNAME} = <UNDEFINED>")
+ endif(DEFINED ${INDI_PUBLIC_VAR_NS}_${_VARNAME})
+ endif(${INDI_PUBLIC_VAR_NS}_DEBUG)
+endfunction(indidebug)
+
+set(${INDI_PRIVATE_VAR_NS}_ROOT "")
+if(DEFINED ENV{INDI_ROOT})
+ set(${INDI_PRIVATE_VAR_NS}_ROOT "$ENV{INDI_ROOT}")
+endif(DEFINED ENV{INDI_ROOT})
+if (DEFINED INDI_ROOT)
+ set(${INDI_PRIVATE_VAR_NS}_ROOT "${INDI_ROOT}")
+endif(DEFINED INDI_ROOT)
+
+set(${INDI_PRIVATE_VAR_NS}_BIN_SUFFIXES )
+set(${INDI_PRIVATE_VAR_NS}_LIB_SUFFIXES )
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ list(APPEND ${INDI_PRIVATE_VAR_NS}_BIN_SUFFIXES "bin64")
+ list(APPEND ${INDI_PRIVATE_VAR_NS}_LIB_SUFFIXES "lib64")
+endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
+list(APPEND ${INDI_PRIVATE_VAR_NS}_BIN_SUFFIXES "bin")
+list(APPEND ${INDI_PRIVATE_VAR_NS}_LIB_SUFFIXES "lib")
+
+set(${INDI_PRIVATE_VAR_NS}_COMPONENTS )
+# <INDI component name> <library name 1> ... <library name N>
+macro(INDI_declare_component _NAME)
+ list(APPEND ${INDI_PRIVATE_VAR_NS}_COMPONENTS ${_NAME})
+ set("${INDI_PRIVATE_VAR_NS}_COMPONENTS_${_NAME}" ${ARGN})
+endmacro(INDI_declare_component)
+
+INDI_declare_component(driver indidriver)
+INDI_declare_component(align indiAlignmentDriver)
+INDI_declare_component(client indiclient)
+INDI_declare_component(clientqt5 indiclientqt5)
+INDI_declare_component(lx200 indilx200)
+
+########## Public ##########
+set(${INDI_PUBLIC_VAR_NS}_FOUND TRUE)
+set(${INDI_PUBLIC_VAR_NS}_LIBRARIES )
+set(${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR )
+foreach(${INDI_PRIVATE_VAR_NS}_COMPONENT ${${INDI_PRIVATE_VAR_NS}_COMPONENTS})
+ string(TOUPPER "${${INDI_PRIVATE_VAR_NS}_COMPONENT}" ${INDI_PRIVATE_VAR_NS}_UPPER_COMPONENT)
+ set("${INDI_PUBLIC_VAR_NS}_${${INDI_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" FALSE) # may be done in the INDI_declare_component macro
+endforeach(${INDI_PRIVATE_VAR_NS}_COMPONENT)
+
+# Check components
+if(NOT ${INDI_PUBLIC_VAR_NS}_FIND_COMPONENTS) # driver and posix client by default
+ set(${INDI_PUBLIC_VAR_NS}_FIND_COMPONENTS driver align)
+else(NOT ${INDI_PUBLIC_VAR_NS}_FIND_COMPONENTS)
+ #list(APPEND ${INDI_PUBLIC_VAR_NS}_FIND_COMPONENTS uc)
+ list(REMOVE_DUPLICATES ${INDI_PUBLIC_VAR_NS}_FIND_COMPONENTS)
+ foreach(${INDI_PRIVATE_VAR_NS}_COMPONENT ${${INDI_PUBLIC_VAR_NS}_FIND_COMPONENTS})
+ if(NOT DEFINED ${INDI_PRIVATE_VAR_NS}_COMPONENTS_${${INDI_PRIVATE_VAR_NS}_COMPONENT})
+ message(FATAL_ERROR "Unknown INDI component: ${${INDI_PRIVATE_VAR_NS}_COMPONENT}")
+ endif(NOT DEFINED ${INDI_PRIVATE_VAR_NS}_COMPONENTS_${${INDI_PRIVATE_VAR_NS}_COMPONENT})
+ endforeach(${INDI_PRIVATE_VAR_NS}_COMPONENT)
+endif(NOT ${INDI_PUBLIC_VAR_NS}_FIND_COMPONENTS)
+
+# Includes
+find_path(
+ ${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR
+ indidevapi.h
+ PATH_SUFFIXES libindi include/libindi
+ ${PC_INDI_INCLUDE_DIR}
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ HINTS ${${INDI_PRIVATE_VAR_NS}_ROOT}
+ DOC "Include directory for INDI"
+)
+
+find_path(
+ WEBSOCKET_HEADER
+ indiwsserver.h
+ PATH_SUFFIXES libindi
+ ${PC_INDI_INCLUDE_DIR}
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+)
+
+if (WEBSOCKET_HEADER)
+ SET(INDI_WEBSOCKET TRUE)
+else()
+ SET(INDI_WEBSOCKET FALSE)
+endif()
+
+find_path(${INDI_PUBLIC_VAR_NS}_DATA_DIR
+ drivers.xml
+ PATH_SUFFIXES share/indi
+ DOC "Data directory for INDI"
+ )
+
+if(${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR)
+ if(EXISTS "${${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR}/indiversion.h") # INDI >= 1.4
+ file(READ "${${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR}/indiversion.h" ${INDI_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS)
+ else()
+ message(FATAL_ERROR "INDI version header not found")
+ endif()
+
+ if(${INDI_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS MATCHES ".*INDI_VERSION ([0-9]+).([0-9]+).([0-9]+)")
+ set(${INDI_PUBLIC_VAR_NS}_MAJOR_VERSION "${CMAKE_MATCH_1}")
+ set(${INDI_PUBLIC_VAR_NS}_MINOR_VERSION "${CMAKE_MATCH_2}")
+ set(${INDI_PUBLIC_VAR_NS}_RELEASE_VERSION "${CMAKE_MATCH_3}")
+ else()
+ message(FATAL_ERROR "failed to detect INDI version")
+ endif()
+ set(${INDI_PUBLIC_VAR_NS}_VERSION "${${INDI_PUBLIC_VAR_NS}_MAJOR_VERSION}.${${INDI_PUBLIC_VAR_NS}_MINOR_VERSION}.${${INDI_PUBLIC_VAR_NS}_RELEASE_VERSION}")
+
+ # Check libraries
+ foreach(${INDI_PRIVATE_VAR_NS}_COMPONENT ${${INDI_PUBLIC_VAR_NS}_FIND_COMPONENTS})
+ set(${INDI_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES )
+ set(${INDI_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES )
+ foreach(${INDI_PRIVATE_VAR_NS}_BASE_NAME ${${INDI_PRIVATE_VAR_NS}_COMPONENTS_${${INDI_PRIVATE_VAR_NS}_COMPONENT}})
+ list(APPEND ${INDI_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES "${${INDI_PRIVATE_VAR_NS}_BASE_NAME}")
+ list(APPEND ${INDI_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES "${${INDI_PRIVATE_VAR_NS}_BASE_NAME}d")
+ list(APPEND ${INDI_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES "${${INDI_PRIVATE_VAR_NS}_BASE_NAME}${INDI_MAJOR_VERSION}${INDI_MINOR_VERSION}")
+ list(APPEND ${INDI_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES "${${INDI_PRIVATE_VAR_NS}_BASE_NAME}${INDI_MAJOR_VERSION}${INDI_MINOR_VERSION}d")
+ endforeach(${INDI_PRIVATE_VAR_NS}_BASE_NAME)
+
+ find_library(
+ ${INDI_PRIVATE_VAR_NS}_LIB_RELEASE_${${INDI_PRIVATE_VAR_NS}_COMPONENT}
+ NAMES ${${INDI_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES}
+ HINTS ${${INDI_PRIVATE_VAR_NS}_ROOT}
+ PATH_SUFFIXES ${_INDI_LIB_SUFFIXES}
+ DOC "Release libraries for INDI"
+ )
+ find_library(
+ ${INDI_PRIVATE_VAR_NS}_LIB_DEBUG_${${INDI_PRIVATE_VAR_NS}_COMPONENT}
+ NAMES ${${INDI_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES}
+ HINTS ${${INDI_PRIVATE_VAR_NS}_ROOT}
+ PATH_SUFFIXES ${_INDI_LIB_SUFFIXES}
+ DOC "Debug libraries for INDI"
+ )
+
+ string(TOUPPER "${${INDI_PRIVATE_VAR_NS}_COMPONENT}" ${INDI_PRIVATE_VAR_NS}_UPPER_COMPONENT)
+ if(NOT ${INDI_PRIVATE_VAR_NS}_LIB_RELEASE_${${INDI_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${INDI_PRIVATE_VAR_NS}_LIB_DEBUG_${${INDI_PRIVATE_VAR_NS}_COMPONENT}) # both not found
+ set("${INDI_PUBLIC_VAR_NS}_${${INDI_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" FALSE)
+ set("${INDI_PUBLIC_VAR_NS}_FOUND" FALSE)
+ else(NOT ${INDI_PRIVATE_VAR_NS}_LIB_RELEASE_${${INDI_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${INDI_PRIVATE_VAR_NS}_LIB_DEBUG_${${INDI_PRIVATE_VAR_NS}_COMPONENT}) # one or both found
+ set("${INDI_PUBLIC_VAR_NS}_${${INDI_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" TRUE)
+ if(NOT ${INDI_PRIVATE_VAR_NS}_LIB_RELEASE_${${INDI_PRIVATE_VAR_NS}_COMPONENT}) # release not found => we are in debug
+ set(${INDI_PRIVATE_VAR_NS}_LIB_${${INDI_PRIVATE_VAR_NS}_COMPONENT} "${${INDI_PRIVATE_VAR_NS}_LIB_DEBUG_${${INDI_PRIVATE_VAR_NS}_COMPONENT}}")
+ elseif(NOT ${INDI_PRIVATE_VAR_NS}_LIB_DEBUG_${${INDI_PRIVATE_VAR_NS}_COMPONENT}) # debug not found => we are in release
+ set(${INDI_PRIVATE_VAR_NS}_LIB_${${INDI_PRIVATE_VAR_NS}_COMPONENT} "${${INDI_PRIVATE_VAR_NS}_LIB_RELEASE_${${INDI_PRIVATE_VAR_NS}_COMPONENT}}")
+ else() # both found
+ set(
+ ${INDI_PRIVATE_VAR_NS}_LIB_${${INDI_PRIVATE_VAR_NS}_COMPONENT}
+ optimized ${${INDI_PRIVATE_VAR_NS}_LIB_RELEASE_${${INDI_PRIVATE_VAR_NS}_COMPONENT}}
+ debug ${${INDI_PRIVATE_VAR_NS}_LIB_DEBUG_${${INDI_PRIVATE_VAR_NS}_COMPONENT}}
+ )
+ endif()
+ list(APPEND ${INDI_PUBLIC_VAR_NS}_LIBRARIES ${${INDI_PRIVATE_VAR_NS}_LIB_${${INDI_PRIVATE_VAR_NS}_COMPONENT}})
+ endif(NOT ${INDI_PRIVATE_VAR_NS}_LIB_RELEASE_${${INDI_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${INDI_PRIVATE_VAR_NS}_LIB_DEBUG_${${INDI_PRIVATE_VAR_NS}_COMPONENT})
+ endforeach(${INDI_PRIVATE_VAR_NS}_COMPONENT)
+
+ # Check find_package arguments
+ include(FindPackageHandleStandardArgs)
+ if(${INDI_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${INDI_PUBLIC_VAR_NS}_FIND_QUIETLY)
+ find_package_handle_standard_args(
+ ${INDI_PUBLIC_VAR_NS}
+ REQUIRED_VARS ${INDI_PUBLIC_VAR_NS}_LIBRARIES ${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR
+ VERSION_VAR ${INDI_PUBLIC_VAR_NS}_VERSION
+ )
+ else(${INDI_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${INDI_PUBLIC_VAR_NS}_FIND_QUIETLY)
+ find_package_handle_standard_args(${INDI_PUBLIC_VAR_NS} "INDI not found" ${INDI_PUBLIC_VAR_NS}_LIBRARIES ${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR)
+ endif(${INDI_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${INDI_PUBLIC_VAR_NS}_FIND_QUIETLY)
+else(${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR)
+ set("${INDI_PUBLIC_VAR_NS}_FOUND" FALSE)
+ if(${INDI_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${INDI_PUBLIC_VAR_NS}_FIND_QUIETLY)
+ message(FATAL_ERROR "Could not find INDI include directory")
+ endif(${INDI_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${INDI_PUBLIC_VAR_NS}_FIND_QUIETLY)
+endif(${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR)
+
+mark_as_advanced(
+ ${INDI_PUBLIC_VAR_NS}_INCLUDE_DIR
+ ${INDI_PUBLIC_VAR_NS}_LIBRARIES
+ INDI_WEBSOCKET
+)
+
+# IN (args)
+indidebug("FIND_COMPONENTS")
+indidebug("FIND_REQUIRED")
+indidebug("FIND_QUIETLY")
+indidebug("FIND_VERSION")
+# OUT
+# Found
+indidebug("FOUND")
+indidebug("SERVER_FOUND")
+indidebug("DRIVERS_FOUND")
+indidebug("CLIENT_FOUND")
+indidebug("QT5CLIENT_FOUND")
+indidebug("LX200_FOUND")
+
+# Linking
+indidebug("INCLUDE_DIR")
+indidebug("DATA_DIR")
+indidebug("LIBRARIES")
+# Backward compatibility
+set(${INDI_PUBLIC_VAR_NS}_DRIVER_LIBRARIES ${${INDI_PUBLIC_VAR_NS}_LIBRARIES})
+indidebug("DRIVER_LIBRARIES")
+# Version
+indidebug("MAJOR_VERSION")
+indidebug("MINOR_VERSION")
+indidebug("RELEASE_VERSION")
+indidebug("VERSION")
diff --git a/cmake_modules/FindINOVASDK.cmake b/cmake_modules/FindINOVASDK.cmake
new file mode 100644
index 0000000..75874e0
--- /dev/null
+++ b/cmake_modules/FindINOVASDK.cmake
@@ -0,0 +1,50 @@
+# - Try to find INOVASDK Universal Library
+# Once done this will define
+#
+# INOVASDK_FOUND - system has INOVASDK
+# INOVASDK_INCLUDE_DIR - the INOVASDK include directory
+# INOVASDK_LIBRARIES - Link these to use INOVASDK
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (INOVASDK_INCLUDE_DIR AND INOVASDK_LIBRARIES)
+
+ # in cache already
+ set(INOVASDK_FOUND TRUE)
+ message(STATUS "Found libinovasdk: ${INOVASDK_LIBRARIES}")
+
+else (INOVASDK_INCLUDE_DIR AND INOVASDK_LIBRARIES)
+
+ find_path(INOVASDK_INCLUDE_DIR inovasdk.h
+ PATH_SUFFIXES inovasdk
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(INOVASDK_LIBRARIES NAMES inovasdk
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(INOVASDK_INCLUDE_DIR AND INOVASDK_LIBRARIES)
+ set(INOVASDK_FOUND TRUE)
+ else (INOVASDK_INCLUDE_DIR AND INOVASDK_LIBRARIES)
+ set(INOVASDK_FOUND FALSE)
+ endif(INOVASDK_INCLUDE_DIR AND INOVASDK_LIBRARIES)
+
+
+ if (INOVASDK_FOUND)
+ if (NOT INOVASDK_FIND_QUIETLY)
+ message(STATUS "Found INOVASDK: ${INOVASDK_LIBRARIES}")
+ endif (NOT INOVASDK_FIND_QUIETLY)
+ else (INOVASDK_FOUND)
+ if (INOVASDK_FIND_REQUIRED)
+ message(FATAL_ERROR "INOVASDK not found. Please install INOVASDK Library http://www.indilib.org")
+ endif (INOVASDK_FIND_REQUIRED)
+ endif (INOVASDK_FOUND)
+
+ mark_as_advanced(INOVASDK_INCLUDE_DIR INOVASDK_LIBRARIES)
+
+endif (INOVASDK_INCLUDE_DIR AND INOVASDK_LIBRARIES)
diff --git a/cmake_modules/FindIconv.cmake b/cmake_modules/FindIconv.cmake
new file mode 100644
index 0000000..ea0e5f3
--- /dev/null
+++ b/cmake_modules/FindIconv.cmake
@@ -0,0 +1,81 @@
+#
+# Copyright (C) 2010 Michael Bell <michael.bell@web.de>
+# 2015-2016 MariaDB Corporation AB
+#
+# Redistribution and use is allowed according to the terms of the New
+# BSD license.
+# For details see the COPYING-CMAKE-SCRIPTS file.
+#
+# ICONV_EXTERNAL - Iconv is an external library (not libc)
+# ICONV_FOUND - system has Iconv
+# ICONV_INCLUDE_DIR - the Iconv include directory
+# ICONV_LIBRARIES - Link these to use Iconv
+# ICONV_SECOND_ARGUMENT_IS_CONST - the second argument for iconv() is const
+# ICONV_VERSION - Iconv version string
+
+if (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
+ # Already in cache, be silent
+ set(ICONV_FIND_QUIETLY TRUE)
+endif (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
+
+find_path(ICONV_INCLUDE_DIR iconv.h)
+
+IF(CMAKE_SYSTEM_NAME MATCHES "SunOS")
+ # There is some libiconv.so in /usr/local that must
+ # be avoided, iconv routines are in libc
+ELSEIF(APPLE)
+ find_library(ICONV_LIBRARIES NAMES iconv libiconv PATHS
+ /usr/lib/
+ NO_CMAKE_SYSTEM_PATH)
+ SET(ICONV_EXTERNAL TRUE)
+ELSE()
+ find_library(ICONV_LIBRARIES NAMES iconv libiconv libiconv-2)
+ IF(ICONV_LIBRARIES)
+ SET(ICONV_EXTERNAL TRUE)
+ ENDIF()
+ENDIF()
+
+if (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
+ set (ICONV_FOUND TRUE)
+endif (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
+
+set(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})
+IF(ICONV_EXTERNAL)
+ set(CMAKE_REQUIRED_LIBRARIES ${ICONV_LIBRARIES})
+ENDIF()
+
+if (ICONV_FOUND)
+ include(CheckCSourceCompiles)
+ CHECK_C_SOURCE_COMPILES("
+ #include <iconv.h>
+ int main(){
+ iconv_t conv = 0;
+ const char* in = 0;
+ size_t ilen = 0;
+ char* out = 0;
+ size_t olen = 0;
+ iconv(conv, &in, &ilen, &out, &olen);
+ return 0;
+ }
+" ICONV_SECOND_ARGUMENT_IS_CONST )
+endif (ICONV_FOUND)
+
+set (CMAKE_REQUIRED_INCLUDES)
+set (CMAKE_REQUIRED_LIBRARIES)
+
+if (ICONV_FOUND)
+ if (NOT ICONV_FIND_QUIETLY)
+ message (STATUS "Found Iconv: ${ICONV_LIBRARIES}")
+ endif (NOT ICONV_FIND_QUIETLY)
+else (ICONV_FOUND)
+ if (Iconv_FIND_REQUIRED)
+ message (FATAL_ERROR "Could not find Iconv")
+ endif (Iconv_FIND_REQUIRED)
+endif (ICONV_FOUND)
+
+MARK_AS_ADVANCED(
+ ICONV_INCLUDE_DIR
+ ICONV_LIBRARIES
+ ICONV_EXTERNAL
+ ICONV_SECOND_ARGUMENT_IS_CONST
+)
diff --git a/cmake_modules/FindJPEG.cmake b/cmake_modules/FindJPEG.cmake
new file mode 100644
index 0000000..3692ee1
--- /dev/null
+++ b/cmake_modules/FindJPEG.cmake
@@ -0,0 +1,28 @@
+# - Find JPEG
+# Find the native JPEG includes and library
+# This module defines
+# JPEG_INCLUDE_DIR, where to find jpeglib.h, etc.
+# JPEG_LIBRARIES, the libraries needed to use JPEG.
+# JPEG_FOUND, If false, do not try to use JPEG.
+# also defined, but not for general use are
+# JPEG_LIBRARY, where to find the JPEG library.
+
+FIND_PATH(JPEG_INCLUDE_DIR jpeglib.h)
+
+SET(JPEG_NAMES ${JPEG_NAMES} jpeg)
+FIND_LIBRARY(JPEG_LIBRARY NAMES ${JPEG_NAMES} )
+
+# handle the QUIETLY and REQUIRED arguments and set JPEG_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(JPEG DEFAULT_MSG JPEG_LIBRARY JPEG_INCLUDE_DIR)
+
+IF(JPEG_FOUND)
+ SET(JPEG_LIBRARIES ${JPEG_LIBRARY})
+ENDIF(JPEG_FOUND)
+
+# Deprecated declarations.
+SET (NATIVE_JPEG_INCLUDE_PATH ${JPEG_INCLUDE_DIR} )
+GET_FILENAME_COMPONENT (NATIVE_JPEG_LIB_PATH ${JPEG_LIBRARY} PATH)
+
+MARK_AS_ADVANCED(JPEG_LIBRARY JPEG_INCLUDE_DIR )
diff --git a/cmake_modules/FindLIMESUITE.cmake b/cmake_modules/FindLIMESUITE.cmake
new file mode 100644
index 0000000..3f1168b
--- /dev/null
+++ b/cmake_modules/FindLIMESUITE.cmake
@@ -0,0 +1,52 @@
+# - Try to find LIMESUITE
+# Once done this will define
+#
+# LIMESUITE_FOUND - system has LIMESUITE
+# LIMESUITE_INCLUDE_DIR - the LIMESUITE include directory
+# LIMESUITE_LIBRARIES - Link these to use LIMESUITE
+# LIMESUITE_VERSION_STRING - Human readable version number of rtlsdr
+# LIMESUITE_VERSION_MAJOR - Major version number of rtlsdr
+# LIMESUITE_VERSION_MINOR - Minor version number of rtlsdr
+
+# Copyright (c) 2017, Ilia Platone, <info@iliaplatone.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (LIMESUITE_LIBRARIES)
+
+ # in cache already
+ set(LIMESUITE_FOUND TRUE)
+ message(STATUS "Found LIMESUITE: ${LIMESUITE_LIBRARIES}")
+
+
+else (LIMESUITE_LIBRARIES)
+
+ find_library(LIMESUITE_LIBRARIES NAMES LimeSuite
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ /usr/local/lib
+ )
+
+ if(LIMESUITE_LIBRARIES)
+ set(LIMESUITE_FOUND TRUE)
+ else (LIMESUITE_LIBRARIES)
+ set(LIMESUITE_FOUND FALSE)
+ endif(LIMESUITE_LIBRARIES)
+
+
+ if (LIMESUITE_FOUND)
+ if (NOT LIMESUITE_FIND_QUIETLY)
+ message(STATUS "Found LIMESUITE: ${LIMESUITE_LIBRARIES}")
+ endif (NOT LIMESUITE_FIND_QUIETLY)
+ else (LIMESUITE_FOUND)
+ if (LIMESUITE_FIND_REQUIRED)
+ message(FATAL_ERROR "LIMESUITE not found. Please install libLimeSuite-dev")
+ endif (LIMESUITE_FIND_REQUIRED)
+ endif (LIMESUITE_FOUND)
+
+ mark_as_advanced(LIMESUITE_LIBRARIES)
+
+endif (LIMESUITE_LIBRARIES)
diff --git a/cmake_modules/FindLibRaw.cmake b/cmake_modules/FindLibRaw.cmake
new file mode 100644
index 0000000..e2dbe09
--- /dev/null
+++ b/cmake_modules/FindLibRaw.cmake
@@ -0,0 +1,79 @@
+# - Find LibRaw
+# Find the LibRaw library <http://www.libraw.org>
+# This module defines
+# LibRaw_VERSION_STRING, the version string of LibRaw
+# LibRaw_INCLUDE_DIR, where to find libraw.h
+# LibRaw_LIBRARIES, the libraries needed to use LibRaw (non-thread-safe)
+# LibRaw_r_LIBRARIES, the libraries needed to use LibRaw (thread-safe)
+# LibRaw_DEFINITIONS, the definitions needed to use LibRaw (non-thread-safe)
+# LibRaw_r_DEFINITIONS, the definitions needed to use LibRaw (thread-safe)
+#
+# Copyright (c) 2013, Pino Toscano <pino at kde dot org>
+# Copyright (c) 2013, Gilles Caulier <caulier dot gilles at gmail dot com>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+FIND_PACKAGE(PkgConfig)
+
+IF(PKG_CONFIG_FOUND)
+ PKG_CHECK_MODULES(PC_LIBRAW libraw)
+ SET(LibRaw_DEFINITIONS ${PC_LIBRAW_CFLAGS_OTHER})
+
+ PKG_CHECK_MODULES(PC_LIBRAW_R libraw_r)
+ SET(LibRaw_r_DEFINITIONS ${PC_LIBRAW_R_CFLAGS_OTHER})
+ENDIF()
+
+FIND_PATH(LibRaw_INCLUDE_DIR libraw.h
+ HINTS
+ ${PC_LIBRAW_INCLUDEDIR}
+ ${PC_LibRaw_INCLUDE_DIRS}
+ PATH_SUFFIXES libraw
+ )
+
+FIND_LIBRARY(LibRaw_LIBRARIES NAMES raw
+ HINTS
+ ${PC_LIBRAW_LIBDIR}
+ ${PC_LIBRAW_LIBRARY_DIRS}
+ )
+
+FIND_LIBRARY(LibRaw_r_LIBRARIES NAMES raw_r
+ HINTS
+ ${PC_LIBRAW_R_LIBDIR}
+ ${PC_LIBRAW_R_LIBRARY_DIRS}
+ )
+
+IF(LibRaw_INCLUDE_DIR)
+ FILE(READ ${LibRaw_INCLUDE_DIR}/libraw_version.h _libraw_version_content)
+
+ STRING(REGEX MATCH "#define LIBRAW_MAJOR_VERSION[ \t]*([0-9]*)\n" _version_major_match ${_libraw_version_content})
+ SET(_libraw_version_major "${CMAKE_MATCH_1}")
+
+ STRING(REGEX MATCH "#define LIBRAW_MINOR_VERSION[ \t]*([0-9]*)\n" _version_minor_match ${_libraw_version_content})
+ SET(_libraw_version_minor "${CMAKE_MATCH_1}")
+
+ STRING(REGEX MATCH "#define LIBRAW_PATCH_VERSION[ \t]*([0-9]*)\n" _version_patch_match ${_libraw_version_content})
+ SET(_libraw_version_patch "${CMAKE_MATCH_1}")
+
+ IF(_version_major_match AND _version_minor_match AND _version_patch_match)
+ SET(LibRaw_VERSION_STRING "${_libraw_version_major}.${_libraw_version_minor}.${_libraw_version_patch}")
+ ELSE()
+ IF(NOT LibRaw_FIND_QUIETLY)
+ MESSAGE(STATUS "Failed to get version information from ${LibRaw_INCLUDE_DIR}/libraw_version.h")
+ ENDIF()
+ ENDIF()
+ENDIF()
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibRaw
+ REQUIRED_VARS LibRaw_LIBRARIES LibRaw_INCLUDE_DIR
+ VERSION_VAR LibRaw_VERSION_STRING
+ )
+
+MARK_AS_ADVANCED(LibRaw_VERSION_STRING
+ LibRaw_INCLUDE_DIR
+ LibRaw_LIBRARIES
+ LibRaw_r_LIBRARIES
+ LibRaw_DEFINITIONS
+ LibRaw_r_DEFINITIONS
+ )
diff --git a/cmake_modules/FindMALLINCAM.cmake b/cmake_modules/FindMALLINCAM.cmake
new file mode 100644
index 0000000..ce296b0
--- /dev/null
+++ b/cmake_modules/FindMALLINCAM.cmake
@@ -0,0 +1,49 @@
+# - Try to find MALLINCAM Camera Library
+# Once done this will define
+#
+# MALLINCAM_FOUND - system has Levenhuk
+# MALLINCAM_INCLUDE_DIR - the Levenhuk include directory
+# MALLINCAM_LIBRARIES - Link these to use Levenhuk
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (MALLINCAM_INCLUDE_DIR AND MALLINCAM_LIBRARIES)
+
+ # in cache already
+ set(MALLINCAM_FOUND TRUE)
+ message(STATUS "Found libnncam: ${MALLINCAM_LIBRARIES}")
+
+else (MALLINCAM_INCLUDE_DIR AND MALLINCAM_LIBRARIES)
+
+ find_path(MALLINCAM_INCLUDE_DIR mallincam.h
+ PATH_SUFFIXES libmallincam
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(MALLINCAM_LIBRARIES NAMES mallincam
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(MALLINCAM_INCLUDE_DIR AND MALLINCAM_LIBRARIES)
+ set(MALLINCAM_FOUND TRUE)
+ else (MALLINCAM_INCLUDE_DIR AND MALLINCAM_LIBRARIES)
+ set(MALLINCAM_FOUND FALSE)
+ endif(MALLINCAM_INCLUDE_DIR AND MALLINCAM_LIBRARIES)
+
+ if (MALLINCAM_FOUND)
+ if (NOT MALLINCAM_FIND_QUIETLY)
+ message(STATUS "Found MALLINCAM: ${MALLINCAM_LIBRARIES}")
+ endif (NOT MALLINCAM_FIND_QUIETLY)
+ else (MALLINCAM_FOUND)
+ if (MALLINCAM_FIND_REQUIRED)
+ message(FATAL_ERROR "MALLINCAM not found. Please install MALLINCAM Library http://www.indilib.org")
+ endif (MALLINCAM_FIND_REQUIRED)
+ endif (MALLINCAM_FOUND)
+
+ mark_as_advanced(MALLINCAM_INCLUDE_DIR MALLINCAM_LIBRARIES)
+
+endif (MALLINCAM_INCLUDE_DIR AND MALLINCAM_LIBRARIES)
diff --git a/cmake_modules/FindMEADE.cmake b/cmake_modules/FindMEADE.cmake
new file mode 100644
index 0000000..59427aa
--- /dev/null
+++ b/cmake_modules/FindMEADE.cmake
@@ -0,0 +1,47 @@
+# - Try to find Meade DSI Library.
+# Once done this will define
+#
+# MEADEDSI_FOUND - system has Meade DSI
+# MEADEDSI_LIBRARIES - Link these to use Meade DSI
+
+# Copyright (c) 2006, Jasem Mutlaq <mutlaqja@ikarustech.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (MEADEDSI_LIBRARIES)
+
+ # in cache already
+ set(MEADEDSI_FOUND TRUE)
+ message(STATUS "Found MEADEDSI: ${MEADEDSI_LIBRARIES}")
+
+else (MEADEDSI_LIBRARIES)
+
+ find_library(MEADEDSI_LIBRARIES NAMES dsi
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ set(CMAKE_REQUIRED_LIBRARIES ${MEADEDSI_LIBRARIES})
+
+ if(MEADEDSI_LIBRARIES)
+ set(MEADEDSI_FOUND TRUE)
+ else (MEADEDSI_LIBRARIES)
+ set(MEADEDSI_FOUND FALSE)
+ endif(MEADEDSI_LIBRARIES)
+
+ if (MEADEDSI_FOUND)
+ if (NOT MEADEDSI_FIND_QUIETLY)
+ message(STATUS "Found Meade DSI: ${MEADEDSI_LIBRARIES}")
+ endif (NOT MEADEDSI_FIND_QUIETLY)
+ else (MEADEDSI_FOUND)
+ if (MEADEDSI_FIND_REQUIRED)
+ message(FATAL_ERROR "Meade DSI not found. Please install Meade DSI library. http://linuxdsi.sourceforge.net")
+ endif (MEADEDSI_FIND_REQUIRED)
+ endif (MEADEDSI_FOUND)
+
+ mark_as_advanced(MEADEDSI_LIBRARIES)
+
+endif (MEADEDSI_LIBRARIES)
diff --git a/cmake_modules/FindMICAM.cmake b/cmake_modules/FindMICAM.cmake
new file mode 100644
index 0000000..b62561b
--- /dev/null
+++ b/cmake_modules/FindMICAM.cmake
@@ -0,0 +1,49 @@
+# - Try to find Moravian Instruments Camera Library
+# Once done this will define
+#
+# MICAM_FOUND - system has MI
+# MICAM_INCLUDE_DIR - the MI include directory
+# MICAM_LIBRARIES - Link these to use MI
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (MICAM_INCLUDE_DIR AND MICAM_LIBRARIES)
+
+ # in cache already
+ set(MICAM_FOUND TRUE)
+ message(STATUS "Found libmicam: ${MICAM_LIBRARIES}")
+
+else (MICAM_INCLUDE_DIR AND MICAM_LIBRARIES)
+
+ find_path(MICAM_INCLUDE_DIR gxccd.h
+ PATH_SUFFIXES libmicam
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(MICAM_LIBRARIES NAMES gxccd
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(MICAM_INCLUDE_DIR AND MICAM_LIBRARIES)
+ set(MICAM_FOUND TRUE)
+ else (MICAM_INCLUDE_DIR AND MICAM_LIBRARIES)
+ set(MICAM_FOUND FALSE)
+ endif(MICAM_INCLUDE_DIR AND MICAM_LIBRARIES)
+
+ if (MICAM_FOUND)
+ if (NOT MICAM_FIND_QUIETLY)
+ message(STATUS "Found MI Library: ${MICAM_LIBRARIES}")
+ endif (NOT MICAM_FIND_QUIETLY)
+ else (MICAM_FOUND)
+ if (MICAM_FIND_REQUIRED)
+ message(FATAL_ERROR "MI Library not found. Please install MI Library http://www.indilib.org")
+ endif (MICAM_FIND_REQUIRED)
+ endif (MICAM_FOUND)
+
+ mark_as_advanced(MICAM_INCLUDE_DIR MICAM_LIBRARIES)
+
+endif (MICAM_INCLUDE_DIR AND MICAM_LIBRARIES)
diff --git a/cmake_modules/FindMMAL.cmake b/cmake_modules/FindMMAL.cmake
new file mode 100644
index 0000000..a537c51
--- /dev/null
+++ b/cmake_modules/FindMMAL.cmake
@@ -0,0 +1,45 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This module can find the MMAL camera libraries.
+#
+cmake_minimum_required(VERSION 3.0.0)
+
+set (MMAL_LIBS mmal_core mmal_util mmal_vc_client)
+set (EGL_LIBS brcmGLESv2 brcmEGL)
+
+foreach(lib ${MMAL_LIBS} ${EGL_LIBS} vcos bcm_host m dl)
+ find_library(${lib}_LIBRARY
+ NAMES ${lib}
+ HINTS ${MMAL_DIR}/lib /opt/vc/lib
+ )
+ if (DEFINED ${lib}_LIBRARY)
+ set(MMAL_LIBRARIES ${MMAL_LIBRARIES} ${${lib}_LIBRARY})
+ else()
+ message(FATAL_ERROR "Failed to find ${${lib}_LIBRARY} library")
+ endif()
+endforeach(lib)
+
+find_path(BCM_INCLUDE_DIR NAMES bcm_host.h
+ HINTS "/opt/vc/include"
+)
+
+find_path(MMAL_BASE_INCLUDE_DIR NAMES mmal.h
+ HINTS "/opt/vc/include/interface/mmal"
+)
+
+find_path(MMAL_UTIL_INCLUDE_DIR NAMES mmal_util.h
+ HINTS "/opt/vc/include/interface/mmal/util"
+)
+
+if (MMAL_BASE_INCLUDE_DIR AND BCM_INCLUDE_DIR AND MMAL_UTIL_INCLUDE_DIR)
+ set(MMAL_INCLUDE_DIR ${MMAL_BASE_INCLUDE_DIR} ${BCM_INCLUDE_DIR} ${MMAL_UTIL_INCLUDE_DIR})
+ set(MMAL_FOUND TRUE)
+endif()
diff --git a/cmake_modules/FindMODBUS.cmake b/cmake_modules/FindMODBUS.cmake
new file mode 100644
index 0000000..42e8c47
--- /dev/null
+++ b/cmake_modules/FindMODBUS.cmake
@@ -0,0 +1,56 @@
+# - Try to find libmodbus
+# Once done this will define
+#
+# MODBUS_FOUND - system has MODBUS
+# MODBUS_INCLUDE_DIR - the MODBUS include directory
+# MODBUS_LIBRARIES - Link these to use MODBUS
+
+# Copyright (c) 2006, Jasem Mutlaq <mutlaqja@ikarustech.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES)
+
+ # in cache already
+ set(MODBUS_FOUND TRUE)
+ message(STATUS "Found libmodbus: ${MODBUS_LIBRARIES}")
+
+else (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES)
+
+ find_path(MODBUS_INCLUDE_DIR modbus.h
+ PATH_SUFFIXES modbus
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(MODBUS_LIBRARIES NAMES modbus
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ set(CMAKE_REQUIRED_INCLUDES ${MODBUS_INCLUDE_DIR})
+ set(CMAKE_REQUIRED_LIBRARIES ${MODBUS_LIBRARIES})
+
+ if(MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES)
+ set(MODBUS_FOUND TRUE)
+ else (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES)
+ set(MODBUS_FOUND FALSE)
+ endif(MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES)
+
+ if (MODBUS_FOUND)
+ if (NOT MODBUS_FIND_QUIETLY)
+ message(STATUS "Found libmodbus: ${MODBUS_LIBRARIES}")
+ endif (NOT MODBUS_FIND_QUIETLY)
+ else (MODBUS_FOUND)
+ if (MODBUS_FIND_REQUIRED)
+ message(FATAL_ERROR "libmodbus not found. Please install libmodbus-devel. https://launchpad.net/libmodbus/")
+ endif (MODBUS_FIND_REQUIRED)
+ endif (MODBUS_FOUND)
+
+ mark_as_advanced(MODBUS_INCLUDE_DIR MODBUS_LIBRARIES)
+
+endif (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES)
+
diff --git a/cmake_modules/FindNNCAM.cmake b/cmake_modules/FindNNCAM.cmake
new file mode 100644
index 0000000..a9eabe1
--- /dev/null
+++ b/cmake_modules/FindNNCAM.cmake
@@ -0,0 +1,49 @@
+# - Try to find NNCAM Camera Library
+# Once done this will define
+#
+# NNCAM_FOUND - system has Levenhuk
+# NNCAM_INCLUDE_DIR - the Levenhuk include directory
+# NNCAM_LIBRARIES - Link these to use Levenhuk
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (NNCAM_INCLUDE_DIR AND NNCAM_LIBRARIES)
+
+ # in cache already
+ set(NNCAM_FOUND TRUE)
+ message(STATUS "Found libnncam: ${NNCAM_LIBRARIES}")
+
+else (NNCAM_INCLUDE_DIR AND NNCAM_LIBRARIES)
+
+ find_path(NNCAM_INCLUDE_DIR nncam.h
+ PATH_SUFFIXES libnncam
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(NNCAM_LIBRARIES NAMES nncam
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(NNCAM_INCLUDE_DIR AND NNCAM_LIBRARIES)
+ set(NNCAM_FOUND TRUE)
+ else (NNCAM_INCLUDE_DIR AND NNCAM_LIBRARIES)
+ set(NNCAM_FOUND FALSE)
+ endif(NNCAM_INCLUDE_DIR AND NNCAM_LIBRARIES)
+
+ if (NNCAM_FOUND)
+ if (NOT NNCAM_FIND_QUIETLY)
+ message(STATUS "Found NNCAM: ${NNCAM_LIBRARIES}")
+ endif (NOT NNCAM_FIND_QUIETLY)
+ else (NNCAM_FOUND)
+ if (NNCAM_FIND_REQUIRED)
+ message(FATAL_ERROR "NNCAM not found. Please install NNCAM Library http://www.indilib.org")
+ endif (NNCAM_FIND_REQUIRED)
+ endif (NNCAM_FOUND)
+
+ mark_as_advanced(NNCAM_INCLUDE_DIR NNCAM_LIBRARIES)
+
+endif (NNCAM_INCLUDE_DIR AND NNCAM_LIBRARIES)
diff --git a/cmake_modules/FindNUTClient.cmake b/cmake_modules/FindNUTClient.cmake
new file mode 100644
index 0000000..bdac85d
--- /dev/null
+++ b/cmake_modules/FindNUTClient.cmake
@@ -0,0 +1,50 @@
+# - Try to find nutclient library (version 2) and include files
+# Once done this will define
+#
+# NUTCLIENT_FOUND - system has NUTCLIENT
+# NUTCLIENT_INCLUDE_DIR - the NUTCLIENT include directory
+# NUTCLIENT_LIBRARIES - Link these to use NUTCLIENT
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (NUTCLIENT_INCLUDE_DIR AND NUTCLIENT_LIBRARIES)
+
+ # in cache already
+ set(NUTCLIENT_FOUND TRUE)
+ message(STATUS "Found libnutclient: ${NUTCLIENT_LIBRARIES}")
+
+else (NUTCLIENT_INCLUDE_DIR AND NUTCLIENT_LIBRARIES)
+
+ find_path(NUTCLIENT_INCLUDE_DIR nutclient.h
+ PATH_SUFFIXES nutclient
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(NUTCLIENT_LIBRARIES NAMES nutclient
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(NUTCLIENT_INCLUDE_DIR AND NUTCLIENT_LIBRARIES)
+ set(NUTCLIENT_FOUND TRUE)
+ else (NUTCLIENT_INCLUDE_DIR AND NUTCLIENT_LIBRARIES)
+ set(NUTCLIENT_FOUND FALSE)
+ endif(NUTCLIENT_INCLUDE_DIR AND NUTCLIENT_LIBRARIES)
+
+
+ if (NUTCLIENT_FOUND)
+ if (NOT NUTCLIENT_FIND_QUIETLY)
+ message(STATUS "Found NUTCLIENT: ${NUTCLIENT_LIBRARIES}")
+ endif (NOT NUTCLIENT_FIND_QUIETLY)
+ else (NUTCLIENT_FOUND)
+ if (NUTCLIENT_FIND_REQUIRED)
+ message(FATAL_ERROR "NUTCLIENT not found. Please install libnutclient development package.")
+ endif (NUTCLIENT_FIND_REQUIRED)
+ endif (NUTCLIENT_FOUND)
+
+ mark_as_advanced(NUTCLIENT_INCLUDE_DIR NUTCLIENT_LIBRARIES)
+
+endif (NUTCLIENT_INCLUDE_DIR AND NUTCLIENT_LIBRARIES)
diff --git a/cmake_modules/FindNova.cmake b/cmake_modules/FindNova.cmake
new file mode 100644
index 0000000..2d6761c
--- /dev/null
+++ b/cmake_modules/FindNova.cmake
@@ -0,0 +1,55 @@
+# - Try to find NOVA
+# Once done this will define
+#
+# NOVA_FOUND - system has NOVA
+# NOVA_INCLUDE_DIR - the NOVA include directory
+# NOVA_LIBRARIES - Link these to use NOVA
+
+# Copyright (c) 2006, Jasem Mutlaq <mutlaqja@ikarustech.com>
+# Based on FindLibfacile by Carsten Niehaus, <cniehaus@gmx.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES)
+
+ # in cache already
+ set(NOVA_FOUND TRUE)
+ message(STATUS "Found libnova: ${NOVA_LIBRARIES}")
+
+else (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES)
+
+ find_path(NOVA_INCLUDE_DIR libnova.h
+ PATH_SUFFIXES libnova
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(NOVA_LIBRARIES NAMES nova libnova libnovad
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ set(CMAKE_REQUIRED_INCLUDES ${NOVA_INCLUDE_DIR})
+ set(CMAKE_REQUIRED_LIBRARIES ${NOVA_LIBRARIES})
+
+ if(NOVA_INCLUDE_DIR AND NOVA_LIBRARIES)
+ set(NOVA_FOUND TRUE)
+ else (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES)
+ set(NOVA_FOUND FALSE)
+ endif(NOVA_INCLUDE_DIR AND NOVA_LIBRARIES)
+
+ if (NOVA_FOUND)
+ if (NOT Nova_FIND_QUIETLY)
+ message(STATUS "Found NOVA: ${NOVA_LIBRARIES}")
+ endif (NOT Nova_FIND_QUIETLY)
+ else (NOVA_FOUND)
+ if (Nova_FIND_REQUIRED)
+ message(FATAL_ERROR "libnova not found. Please install libnova development package.")
+ endif (Nova_FIND_REQUIRED)
+ endif (NOVA_FOUND)
+
+ mark_as_advanced(NOVA_INCLUDE_DIR NOVA_LIBRARIES)
+
+endif (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES)
diff --git a/cmake_modules/FindOMEGONPROCAM.cmake b/cmake_modules/FindOMEGONPROCAM.cmake
new file mode 100644
index 0000000..6e04b37
--- /dev/null
+++ b/cmake_modules/FindOMEGONPROCAM.cmake
@@ -0,0 +1,50 @@
+# - Try to find Omegon Pro Cam Camera Library
+# Once done this will define
+#
+# OMEGONPROCAM_FOUND - system has Omegon Pro Cam
+# OMEGONPROCAM_INCLUDE_DIR - the Omegon Pro Cam include directory
+# OMEGONPROCAM_LIBRARIES - Link these to use Omegon Pro Cam
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (OMEGONPROCAM_INCLUDE_DIR AND OMEGONPROCAM_LIBRARIES)
+
+ # in cache already
+ set(OMEGONPROCAM_FOUND TRUE)
+ message(STATUS "Found libomegonprocam: ${OMEGONPROCAM_LIBRARIES}")
+
+else (OMEGONPROCAM_INCLUDE_DIR AND OMEGONPROCAM_LIBRARIES)
+
+ find_path(OMEGONPROCAM_INCLUDE_DIR omegonprocam.h
+ PATH_SUFFIXES libomegonprocam
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(OMEGONPROCAM_LIBRARIES NAMES omegonprocam
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(OMEGONPROCAM_INCLUDE_DIR AND OMEGONPROCAM_LIBRARIES)
+ set(OMEGONPROCAM_FOUND TRUE)
+ else (OMEGONPROCAM_INCLUDE_DIR AND OMEGONPROCAM_LIBRARIES)
+ set(OMEGONPROCAM_FOUND FALSE)
+ endif(OMEGONPROCAM_INCLUDE_DIR AND OMEGONPROCAM_LIBRARIES)
+
+
+ if (OMEGONPROCAM_FOUND)
+ if (NOT OMEGONPROCAM_FIND_QUIETLY)
+ message(STATUS "Found OmegonProCam: ${OMEGONPROCAM_LIBRARIES}")
+ endif (NOT OMEGONPROCAM_FIND_QUIETLY)
+ else (OMEGONPROCAM_FOUND)
+ if (OMEGONPROCAM_FIND_REQUIRED)
+ message(FATAL_ERROR "OmegonProCam not found. Please install OmegonProCam Library http://www.indilib.org")
+ endif (OMEGONPROCAM_FIND_REQUIRED)
+ endif (OMEGONPROCAM_FOUND)
+
+ mark_as_advanced(OMEGONPROCAM_INCLUDE_DIR OMEGONPROCAM_LIBRARIES)
+
+endif (OMEGONPROCAM_INCLUDE_DIR AND OMEGONPROCAM_LIBRARIES)
diff --git a/cmake_modules/FindOggTheora.cmake b/cmake_modules/FindOggTheora.cmake
new file mode 100644
index 0000000..a536fc1
--- /dev/null
+++ b/cmake_modules/FindOggTheora.cmake
@@ -0,0 +1,47 @@
+#
+# Find the native Ogg/Theora includes and libraries
+#
+# This module defines
+# OGGTHEORA_INCLUDE_DIR, where to find ogg/ogg.h and theora/theora.h
+# OGGTHEORA_LIBRARIES, the libraries to link against to use Ogg/Theora.
+# OGGTHEORA_FOUND, If false, do not try to use Ogg/Theora.
+
+FIND_PATH(OGGTHEORA_ogg_INCLUDE_DIR ogg/ogg.h)
+
+FIND_PATH(OGGTHEORA_theora_INCLUDE_DIR theora/theora.h)
+
+FIND_LIBRARY(OGGTHEORA_ogg_LIBRARY ogg)
+
+FIND_LIBRARY(OGGTHEORA_theoraenc_LIBRARY theoraenc)
+
+FIND_LIBRARY(OGGTHEORA_theoradec_LIBRARY theoradec)
+
+SET(OGGTHEORA_INCLUDE_DIRS
+ ${OGGTHEORA_ogg_INCLUDE_DIR}
+ ${OGGTHEORA_theora_INCLUDE_DIR}
+ )
+#HACK multiple directories
+SET(OGGTHEORA_INCLUDE_DIR ${OGGTHEORA_INCLUDE_DIRS})
+
+SET(OGGTHEORA_LIBRARIES
+ ${OGGTHEORA_theoraenc_LIBRARY}
+ ${OGGTHEORA_theoradec_LIBRARY}
+ ${OGGTHEORA_ogg_LIBRARY}
+ )
+#HACK multiple libraries
+SET(OGGTHEORA_LIBRARY ${OGGTHEORA_LIBRARIES})
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(OGGTHEORA
+ "Could NOT find the ogg and theora libraries"
+ OGGTHEORA_ogg_LIBRARY
+ OGGTHEORA_theoraenc_LIBRARY
+ OGGTHEORA_theoradec_LIBRARY
+ OGGTHEORA_ogg_INCLUDE_DIR
+ OGGTHEORA_theora_INCLUDE_DIR
+ )
+
+MARK_AS_ADVANCED(OGGTHEORA_ogg_INCLUDE_DIR OGGTHEORA_theora_INCLUDE_DIR
+ OGGTHEORA_ogg_LIBRARY OGGTHEORA_theoraenc_LIBRARY
+ OGGTHEORA_theoradec_LIBRARY
+ )
diff --git a/cmake_modules/FindOpenAL.cmake b/cmake_modules/FindOpenAL.cmake
new file mode 100644
index 0000000..8d2933c
--- /dev/null
+++ b/cmake_modules/FindOpenAL.cmake
@@ -0,0 +1,100 @@
+# Locate OpenAL
+# This module defines
+# OPENAL_LIBRARY
+# OPENAL_FOUND, if false, do not try to link to OpenAL
+# OPENAL_INCLUDE_DIR, where to find the headers
+#
+# $OPENALDIR is an environment variable that would
+# correspond to the ./configure --prefix=$OPENALDIR
+# used in building OpenAL.
+#
+# Created by Eric Wing. This was influenced by the FindSDL.cmake module.
+
+# This makes the presumption that you are include al.h like
+# #include "al.h"
+# and not
+# #include <AL/al.h>
+# The reason for this is that the latter is not entirely portable.
+# Windows/Creative Labs does not by default put their headers in AL/ and
+# OS X uses the convention <OpenAL/al.h>.
+#
+# For Windows, Creative Labs seems to have added a registry key for their
+# OpenAL 1.1 installer. I have added that key to the list of search paths,
+# however, the key looks like it could be a little fragile depending on
+# if they decide to change the 1.00.0000 number for bug fix releases.
+# Also, they seem to have laid down groundwork for multiple library platforms
+# which puts the library in an extra subdirectory. Currently there is only
+# Win32 and I have hardcoded that here. This may need to be adjusted as
+# platforms are introduced.
+# The OpenAL 1.0 installer doesn't seem to have a useful key I can use.
+# I do not know if the Nvidia OpenAL SDK has a registry key.
+#
+# For OS X, remember that OpenAL was added by Apple in 10.4 (Tiger).
+# To support the framework, I originally wrote special framework detection
+# code in this module which I have now removed with CMake's introduction
+# of native support for frameworks.
+# In addition, OpenAL is open source, and it is possible to compile on Panther.
+# Furthermore, due to bugs in the initial OpenAL release, and the
+# transition to OpenAL 1.1, it is common to need to override the built-in
+# framework.
+# Per my request, CMake should search for frameworks first in
+# the following order:
+# ~/Library/Frameworks/OpenAL.framework/Headers
+# /Library/Frameworks/OpenAL.framework/Headers
+# /System/Library/Frameworks/OpenAL.framework/Headers
+#
+# On OS X, this will prefer the Framework version (if found) over others.
+# People will have to manually change the cache values of
+# OPENAL_LIBRARY to override this selection or set the CMake environment
+# CMAKE_INCLUDE_PATH to modify the search paths.
+
+FIND_PATH(OPENAL_INCLUDE_DIR al.h
+ PATHS
+ $ENV{OPENALDIR}
+ NO_DEFAULT_PATH
+ PATH_SUFFIXES include/AL include/OpenAL include
+)
+
+FIND_PATH(OPENAL_INCLUDE_DIR al.h
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /usr/local
+ /usr
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir]
+ PATH_SUFFIXES include/AL include/OpenAL include
+)
+
+FIND_LIBRARY(OPENAL_LIBRARY
+ NAMES OpenAL al openal OpenAL32
+ PATHS
+ $ENV{OPENALDIR}
+ NO_DEFAULT_PATH
+ PATH_SUFFIXES lib64 lib libs64 libs libs/Win32 libs/Win64
+)
+
+FIND_LIBRARY(OPENAL_LIBRARY
+ NAMES OpenAL al openal OpenAL32
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /usr/local
+ /usr
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ [HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir]
+ PATH_SUFFIXES lib64 lib libs64 libs libs/Win32 libs/Win64
+)
+
+
+SET(OPENAL_FOUND "NO")
+IF(OPENAL_LIBRARY AND OPENAL_INCLUDE_DIR)
+ SET(OPENAL_FOUND "YES")
+ENDIF(OPENAL_LIBRARY AND OPENAL_INCLUDE_DIR)
+
diff --git a/cmake_modules/FindPENTAX.cmake b/cmake_modules/FindPENTAX.cmake
new file mode 100644
index 0000000..5209c8a
--- /dev/null
+++ b/cmake_modules/FindPENTAX.cmake
@@ -0,0 +1,86 @@
+# - Try to find PENTAX Universal Libraries
+# Once done this will define
+#
+# PENTAX_FOUND - system has PENTAX
+# PENTAX_INCLUDE_DIR - the PENTAX include directory
+# PENTAX_LIBRARIES - Link these to use PENTAX
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (PENTAX_INCLUDE_DIR AND PENTAX_LIBRARIES)
+
+ # in cache already
+ set(PENTAX_FOUND TRUE)
+ message(STATUS "Found PENTAX libraries: ${PENTAX_LIBRARIES}")
+
+else (PENTAX_INCLUDE_DIR AND PENTAX_LIBRARIES)
+
+ find_path(PKTRIGGERCORD_INCLUDE_DIR libpktriggercord.h
+ PATH_SUFFIXES libpktriggercord
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(PKTRIGGERCORD_LIBRARIES NAMES pktriggercord
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ PATH_SUFFIXES indipentax
+ )
+
+#if not armv8, then look for ricoh library; otherwise only use pktriggercord library
+ if(NOT (${CMAKE_SYSTEM_PROCESSOR} MATCHES "^aarch64"))
+ find_path(RICOH_INCLUDE_DIR ricoh_camera_sdk.hpp
+ PATH_SUFFIXES libpentax libricohcamerasdk
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+ find_library(RICOH_LIBRARIES NAMES RicohCameraSDKCpp
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+ find_library(RICOHMTP_LIBRARIES NAMES libmtpricoh.so.9.3.0
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if (RICOH_INCLUDE_DIR AND PKTRIGGERCORD_INCLUDE_DIR)
+ set(PENTAX_INCLUDE_DIR ${RICOH_INCLUDE_DIR} ${PKTRIGGERCORD_INCLUDE_DIR})
+ endif (RICOH_INCLUDE_DIR AND PKTRIGGERCORD_INCLUDE_DIR)
+ if (RICOH_LIBRARIES AND RICOHMTP_LIBRARIES AND PKTRIGGERCORD_LIBRARIES)
+ set(PENTAX_LIBRARIES ${RICOH_LIBRARIES} ${RICOHMTP_LIBRARIES} ${PKTRIGGERCORD_LIBRARIES})
+ endif (RICOH_LIBRARIES AND RICOHMTP_LIBRARIES AND PKTRIGGERCORD_LIBRARIES)
+
+ else()
+ if (PKTRIGGERCORD_INCLUDE_DIR)
+ set(PENTAX_INCLUDE_DIR ${PKTRIGGERCORD_INCLUDE_DIR})
+ endif (PKTRIGGERCORD_INCLUDE_DIR)
+ if (PKTRIGGERCORD_LIBRARIES)
+ set(PENTAX_LIBRARIES ${PKTRIGGERCORD_LIBRARIES})
+ endif (PKTRIGGERCORD_LIBRARIES)
+ endif()
+
+
+ if(PENTAX_INCLUDE_DIR AND PENTAX_LIBRARIES)
+ set(PENTAX_FOUND TRUE)
+ else (PENTAX_INCLUDE_DIR AND PENTAX_LIBRARIES)
+ set(PENTAX_FOUND FALSE)
+ endif(PENTAX_INCLUDE_DIR AND PENTAX_LIBRARIES)
+
+
+ if (PENTAX_FOUND)
+ if (NOT PENTAX_FIND_QUIETLY)
+ message(STATUS "Found PENTAX libraries: ${PENTAX_LIBRARIES}")
+ endif (NOT PENTAX_FIND_QUIETLY)
+ else (PENTAX_FOUND)
+ if (PENTAX_FIND_REQUIRED)
+ message(FATAL_ERROR "One or both of libricohcamersdk and libpktriggercord are not found. Please install them. See http://www.indilib.org.")
+ endif (PENTAX_FIND_REQUIRED)
+ endif (PENTAX_FOUND)
+
+ mark_as_advanced(PENTAX_INCLUDE_DIR PENTAX_LIBRARIES)
+
+endif (PENTAX_INCLUDE_DIR AND PENTAX_LIBRARIES)
diff --git a/cmake_modules/FindPLAYERONE.cmake b/cmake_modules/FindPLAYERONE.cmake
new file mode 100644
index 0000000..9171a51
--- /dev/null
+++ b/cmake_modules/FindPLAYERONE.cmake
@@ -0,0 +1,56 @@
+# - Try to find PlayerOne Library
+# Once done this will define
+#
+# PLAYERONE_FOUND - system has PLAYERONE
+# PLAYERONE_INCLUDE_DIR - the PLAYERONE include directory
+# PLAYERONE_LIBRARIES - Link these to use ASI
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (PLAYERONE_INCLUDE_DIR AND PLAYERONE_LIBRARIES)
+
+ # in cache already
+ set(PLAYERONE_FOUND TRUE)
+ message(STATUS "Found libplayerone: ${PLAYERONE_LIBRARIES}")
+
+else (PLAYERONE_INCLUDE_DIR AND PLAYERONE_LIBRARIES)
+
+ find_path(PLAYERONE_INCLUDE_DIR PlayerOneCamera.h
+ PATH_SUFFIXES libplayerone
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(PLAYERONECAM_LIBRARIES NAMES PlayerOneCamera
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+
+ if (PLAYERONECAM_LIBRARIES)
+ set(PLAYERONE_LIBRARIES ${PLAYERONECAM_LIBRARIES})
+ endif (PLAYERONECAM_LIBRARIES)
+
+
+ if(PLAYERONE_INCLUDE_DIR AND PLAYERONE_LIBRARIES)
+ set(PLAYERONE_FOUND TRUE)
+ else (PLAYERONE_INCLUDE_DIR AND PLAYERONE_LIBRARIES)
+ set(PLAYERONE_FOUND FALSE)
+ endif(PLAYERONE_INCLUDE_DIR AND PLAYERONE_LIBRARIES)
+
+
+ if (PLAYERONE_FOUND)
+ if (NOT PLAYERONE_FIND_QUIETLY)
+ message(STATUS "Found PLAYERONE: ${PLAYERONE_LIBRARIES}")
+ endif (NOT PLAYERONE_FIND_QUIETLY)
+ else (PLAYERONE_FOUND)
+ if (PLAYERONE_FIND_REQUIRED)
+ message(FATAL_ERROR "PLAYERONE not found. Please install libPlayerOneCamera.3 http://www.indilib.org")
+ endif (PLAYERONE_FIND_REQUIRED)
+ endif (PLAYERONE_FOUND)
+
+ mark_as_advanced(PLAYERONE_INCLUDE_DIR PLAYERONE_LIBRARIES)
+
+endif (PLAYERONE_INCLUDE_DIR AND PLAYERONE_LIBRARIES)
diff --git a/cmake_modules/FindPackageHandleStandardArgs.cmake b/cmake_modules/FindPackageHandleStandardArgs.cmake
new file mode 100644
index 0000000..fe2dbea
--- /dev/null
+++ b/cmake_modules/FindPackageHandleStandardArgs.cmake
@@ -0,0 +1,396 @@
+#[=======================================================================[.rst:
+FindPackageHandleStandardArgs
+-----------------------------
+
+This module provides a function intended to be used in :ref:`Find Modules`
+implementing :command:`find_package(<PackageName>)` calls. It handles the
+``REQUIRED``, ``QUIET`` and version-related arguments of ``find_package``.
+It also sets the ``<PackageName>_FOUND`` variable. The package is
+considered found if all variables listed contain valid results, e.g.
+valid filepaths.
+
+.. command:: find_package_handle_standard_args
+
+ There are two signatures::
+
+ find_package_handle_standard_args(<PackageName>
+ (DEFAULT_MSG|<custom-failure-message>)
+ <required-var>...
+ )
+
+ find_package_handle_standard_args(<PackageName>
+ [FOUND_VAR <result-var>]
+ [REQUIRED_VARS <required-var>...]
+ [VERSION_VAR <version-var>]
+ [HANDLE_COMPONENTS]
+ [CONFIG_MODE]
+ [FAIL_MESSAGE <custom-failure-message>]
+ )
+
+ The ``<PackageName>_FOUND`` variable will be set to ``TRUE`` if all
+ the variables ``<required-var>...`` are valid and any optional
+ constraints are satisfied, and ``FALSE`` otherwise. A success or
+ failure message may be displayed based on the results and on
+ whether the ``REQUIRED`` and/or ``QUIET`` option was given to
+ the :command:`find_package` call.
+
+ The options are:
+
+ ``(DEFAULT_MSG|<custom-failure-message>)``
+ In the simple signature this specifies the failure message.
+ Use ``DEFAULT_MSG`` to ask for a default message to be computed
+ (recommended). Not valid in the full signature.
+
+ ``FOUND_VAR <result-var>``
+ Obsolete. Specifies either ``<PackageName>_FOUND`` or
+ ``<PACKAGENAME>_FOUND`` as the result variable. This exists only
+ for compatibility with older versions of CMake and is now ignored.
+ Result variables of both names are always set for compatibility.
+
+ ``REQUIRED_VARS <required-var>...``
+ Specify the variables which are required for this package.
+ These may be named in the generated failure message asking the
+ user to set the missing variable values. Therefore these should
+ typically be cache entries such as ``FOO_LIBRARY`` and not output
+ variables like ``FOO_LIBRARIES``.
+
+ ``VERSION_VAR <version-var>``
+ Specify the name of a variable that holds the version of the package
+ that has been found. This version will be checked against the
+ (potentially) specified required version given to the
+ :command:`find_package` call, including its ``EXACT`` option.
+ The default messages include information about the required
+ version and the version which has been actually found, both
+ if the version is ok or not.
+
+ ``HANDLE_COMPONENTS``
+ Enable handling of package components. In this case, the command
+ will report which components have been found and which are missing,
+ and the ``<PackageName>_FOUND`` variable will be set to ``FALSE``
+ if any of the required components (i.e. not the ones listed after
+ the ``OPTIONAL_COMPONENTS`` option of :command:`find_package`) are
+ missing.
+
+ ``CONFIG_MODE``
+ Specify that the calling find module is a wrapper around a
+ call to ``find_package(<PackageName> NO_MODULE)``. This implies
+ a ``VERSION_VAR`` value of ``<PackageName>_VERSION``. The command
+ will automatically check whether the package configuration file
+ was found.
+
+ ``FAIL_MESSAGE <custom-failure-message>``
+ Specify a custom failure message instead of using the default
+ generated message. Not recommended.
+
+Example for the simple signature:
+
+.. code-block:: cmake
+
+ find_package_handle_standard_args(LibXml2 DEFAULT_MSG
+ LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)
+
+The ``LibXml2`` package is considered to be found if both
+``LIBXML2_LIBRARY`` and ``LIBXML2_INCLUDE_DIR`` are valid.
+Then also ``LibXml2_FOUND`` is set to ``TRUE``. If it is not found
+and ``REQUIRED`` was used, it fails with a
+:command:`message(FATAL_ERROR)`, independent whether ``QUIET`` was
+used or not. If it is found, success will be reported, including
+the content of the first ``<required-var>``. On repeated CMake runs,
+the same message will not be printed again.
+
+Example for the full signature:
+
+.. code-block:: cmake
+
+ find_package_handle_standard_args(LibArchive
+ REQUIRED_VARS LibArchive_LIBRARY LibArchive_INCLUDE_DIR
+ VERSION_VAR LibArchive_VERSION)
+
+In this case, the ``LibArchive`` package is considered to be found if
+both ``LibArchive_LIBRARY`` and ``LibArchive_INCLUDE_DIR`` are valid.
+Also the version of ``LibArchive`` will be checked by using the version
+contained in ``LibArchive_VERSION``. Since no ``FAIL_MESSAGE`` is given,
+the default messages will be printed.
+
+Another example for the full signature:
+
+.. code-block:: cmake
+
+ find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4)
+ find_package_handle_standard_args(Automoc4 CONFIG_MODE)
+
+In this case, a ``FindAutmoc4.cmake`` module wraps a call to
+``find_package(Automoc4 NO_MODULE)`` and adds an additional search
+directory for ``automoc4``. Then the call to
+``find_package_handle_standard_args`` produces a proper success/failure
+message.
+#]=======================================================================]
+
+#=============================================================================
+# Copyright 2007-2009 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/CMakeParseArguments.cmake)
+
+# internal helper macro
+macro(_FPHSA_FAILURE_MESSAGE _msg)
+ if (${_NAME}_FIND_REQUIRED)
+ message(FATAL_ERROR "${_msg}")
+ else ()
+ if (NOT ${_NAME}_FIND_QUIETLY)
+ message(STATUS "${_msg}")
+ endif ()
+ endif ()
+endmacro()
+
+
+# internal helper macro to generate the failure message when used in CONFIG_MODE:
+macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)
+ # <name>_CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found:
+ if(${_NAME}_CONFIG)
+ _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing: ${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})")
+ else()
+ # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version.
+ # List them all in the error message:
+ if(${_NAME}_CONSIDERED_CONFIGS)
+ set(configsText "")
+ list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount)
+ math(EXPR configsCount "${configsCount} - 1")
+ foreach(currentConfigIndex RANGE ${configsCount})
+ list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename)
+ list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version)
+ set(configsText "${configsText} ${filename} (version ${version})\n")
+ endforeach()
+ if (${_NAME}_NOT_FOUND_MESSAGE)
+ set(configsText "${configsText} Reason given by package: ${${_NAME}_NOT_FOUND_MESSAGE}\n")
+ endif()
+ _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}")
+
+ else()
+ # Simple case: No Config-file was found at all:
+ _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}")
+ endif()
+ endif()
+endmacro()
+
+
+function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)
+
+# set up the arguments for CMAKE_PARSE_ARGUMENTS and check whether we are in
+# new extended or in the "old" mode:
+ set(options CONFIG_MODE HANDLE_COMPONENTS)
+ set(oneValueArgs FAIL_MESSAGE VERSION_VAR FOUND_VAR)
+ set(multiValueArgs REQUIRED_VARS)
+ set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} )
+ list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX)
+
+ if(${INDEX} EQUAL -1)
+ set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG})
+ set(FPHSA_REQUIRED_VARS ${ARGN})
+ set(FPHSA_VERSION_VAR)
+ else()
+
+ CMAKE_PARSE_ARGUMENTS(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN})
+
+ if(FPHSA_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"")
+ endif()
+
+ if(NOT FPHSA_FAIL_MESSAGE)
+ set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG")
+ endif()
+ endif()
+
+# now that we collected all arguments, process them
+
+ if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG")
+ set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}")
+ endif()
+
+ # In config-mode, we rely on the variable <package>_CONFIG, which is set by find_package()
+ # when it successfully found the config-file, including version checking:
+ if(FPHSA_CONFIG_MODE)
+ list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG)
+ list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS)
+ set(FPHSA_VERSION_VAR ${_NAME}_VERSION)
+ endif()
+
+ if(NOT FPHSA_REQUIRED_VARS)
+ message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()")
+ endif()
+
+ list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR)
+
+ string(TOUPPER ${_NAME} _NAME_UPPER)
+ string(TOLOWER ${_NAME} _NAME_LOWER)
+
+ if(FPHSA_FOUND_VAR)
+ if(FPHSA_FOUND_VAR MATCHES "^${_NAME}_FOUND$" OR FPHSA_FOUND_VAR MATCHES "^${_NAME_UPPER}_FOUND$")
+ set(_FOUND_VAR ${FPHSA_FOUND_VAR})
+ else()
+ message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_NAME}_FOUND\" and \"${_NAME_UPPER}_FOUND\" are valid names.")
+ endif()
+ else()
+ set(_FOUND_VAR ${_NAME_UPPER}_FOUND)
+ endif()
+
+ # collect all variables which were not found, so they can be printed, so the
+ # user knows better what went wrong (#6375)
+ set(MISSING_VARS "")
+ set(DETAILS "")
+ # check if all passed variables are valid
+ set(FPHSA_FOUND_${_NAME} TRUE)
+ foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS})
+ if(NOT ${_CURRENT_VAR})
+ set(FPHSA_FOUND_${_NAME} FALSE)
+ set(MISSING_VARS "${MISSING_VARS} ${_CURRENT_VAR}")
+ else()
+ set(DETAILS "${DETAILS}[${${_CURRENT_VAR}}]")
+ endif()
+ endforeach()
+ if(FPHSA_FOUND_${_NAME})
+ set(${_NAME}_FOUND TRUE)
+ set(${_NAME_UPPER}_FOUND TRUE)
+ else()
+ set(${_NAME}_FOUND FALSE)
+ set(${_NAME_UPPER}_FOUND FALSE)
+ endif()
+
+ # component handling
+ unset(FOUND_COMPONENTS_MSG)
+ unset(MISSING_COMPONENTS_MSG)
+
+ if(FPHSA_HANDLE_COMPONENTS)
+ foreach(comp ${${_NAME}_FIND_COMPONENTS})
+ if(${_NAME}_${comp}_FOUND)
+
+ if(NOT DEFINED FOUND_COMPONENTS_MSG)
+ set(FOUND_COMPONENTS_MSG "found components: ")
+ endif()
+ set(FOUND_COMPONENTS_MSG "${FOUND_COMPONENTS_MSG} ${comp}")
+
+ else()
+
+ if(NOT DEFINED MISSING_COMPONENTS_MSG)
+ set(MISSING_COMPONENTS_MSG "missing components: ")
+ endif()
+ set(MISSING_COMPONENTS_MSG "${MISSING_COMPONENTS_MSG} ${comp}")
+
+ if(${_NAME}_FIND_REQUIRED_${comp})
+ set(${_NAME}_FOUND FALSE)
+ set(MISSING_VARS "${MISSING_VARS} ${comp}")
+ endif()
+
+ endif()
+ endforeach()
+ set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}")
+ set(DETAILS "${DETAILS}[c${COMPONENT_MSG}]")
+ endif()
+
+ # version handling:
+ set(VERSION_MSG "")
+ set(VERSION_OK TRUE)
+ set(VERSION ${${FPHSA_VERSION_VAR}})
+
+ # check with DEFINED here as the requested or found version may be "0"
+ if (DEFINED ${_NAME}_FIND_VERSION)
+ if(DEFINED ${FPHSA_VERSION_VAR})
+
+ if(${_NAME}_FIND_VERSION_EXACT) # exact version required
+ # count the dots in the version string
+ string(REGEX REPLACE "[^.]" "" _VERSION_DOTS "${VERSION}")
+ # add one dot because there is one dot more than there are components
+ string(LENGTH "${_VERSION_DOTS}." _VERSION_DOTS)
+ if (_VERSION_DOTS GREATER ${_NAME}_FIND_VERSION_COUNT)
+ # Because of the C++ implementation of find_package() ${_NAME}_FIND_VERSION_COUNT
+ # is at most 4 here. Therefore a simple lookup table is used.
+ if (${_NAME}_FIND_VERSION_COUNT EQUAL 1)
+ set(_VERSION_REGEX "[^.]*")
+ elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 2)
+ set(_VERSION_REGEX "[^.]*\\.[^.]*")
+ elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 3)
+ set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*")
+ else ()
+ set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*")
+ endif ()
+ string(REGEX REPLACE "^(${_VERSION_REGEX})\\..*" "\\1" _VERSION_HEAD "${VERSION}")
+ unset(_VERSION_REGEX)
+ if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _VERSION_HEAD)
+ set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"")
+ set(VERSION_OK FALSE)
+ else ()
+ set(VERSION_MSG "(found suitable exact version \"${VERSION}\")")
+ endif ()
+ unset(_VERSION_HEAD)
+ else ()
+ if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL VERSION)
+ set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"")
+ set(VERSION_OK FALSE)
+ else ()
+ set(VERSION_MSG "(found suitable exact version \"${VERSION}\")")
+ endif ()
+ endif ()
+ unset(_VERSION_DOTS)
+
+ else() # minimum version specified:
+ if (${_NAME}_FIND_VERSION VERSION_GREATER VERSION)
+ set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"")
+ set(VERSION_OK FALSE)
+ else ()
+ set(VERSION_MSG "(found suitable version \"${VERSION}\", minimum required is \"${${_NAME}_FIND_VERSION}\")")
+ endif ()
+ endif()
+
+ else()
+
+ # if the package was not found, but a version was given, add that to the output:
+ if(${_NAME}_FIND_VERSION_EXACT)
+ set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")")
+ else()
+ set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")")
+ endif()
+
+ endif()
+ else ()
+ if(VERSION)
+ set(VERSION_MSG "(found version \"${VERSION}\")")
+ endif()
+ endif ()
+
+ if(VERSION_OK)
+ set(DETAILS "${DETAILS}[v${VERSION}(${${_NAME}_FIND_VERSION})]")
+ else()
+ set(${_NAME}_FOUND FALSE)
+ endif()
+
+
+ # print the result:
+ if (${_NAME}_FOUND)
+ FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}")
+ else ()
+
+ if(FPHSA_CONFIG_MODE)
+ _FPHSA_HANDLE_FAILURE_CONFIG_MODE()
+ else()
+ if(NOT VERSION_OK)
+ _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})")
+ else()
+ _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing: ${MISSING_VARS}) ${VERSION_MSG}")
+ endif()
+ endif()
+
+ endif ()
+
+ set(${_NAME}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE)
+ set(${_NAME_UPPER}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE)
+endfunction()
diff --git a/cmake_modules/FindPackageMessage.cmake b/cmake_modules/FindPackageMessage.cmake
new file mode 100644
index 0000000..a0349d3
--- /dev/null
+++ b/cmake_modules/FindPackageMessage.cmake
@@ -0,0 +1,57 @@
+#.rst:
+# FindPackageMessage
+# ------------------
+#
+#
+#
+# FIND_PACKAGE_MESSAGE(<name> "message for user" "find result details")
+#
+# This macro is intended to be used in FindXXX.cmake modules files. It
+# will print a message once for each unique find result. This is useful
+# for telling the user where a package was found. The first argument
+# specifies the name (XXX) of the package. The second argument
+# specifies the message to display. The third argument lists details
+# about the find result so that if they change the message will be
+# displayed again. The macro also obeys the QUIET argument to the
+# find_package command.
+#
+# Example:
+#
+# ::
+#
+# if(X11_FOUND)
+# FIND_PACKAGE_MESSAGE(X11 "Found X11: ${X11_X11_LIB}"
+# "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]")
+# else()
+# ...
+# endif()
+
+#=============================================================================
+# Copyright 2008-2009 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+
+function(FIND_PACKAGE_MESSAGE pkg msg details)
+ # Avoid printing a message repeatedly for the same find result.
+ if(NOT ${pkg}_FIND_QUIETLY)
+ string(REPLACE "\n" "" details "${details}")
+ set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg})
+ if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}")
+ # The message has not yet been printed.
+ message(STATUS "${msg}")
+
+ # Save the find details in the cache to avoid printing the same
+ # message again.
+ set("${DETAILS_VAR}" "${details}"
+ CACHE INTERNAL "Details about finding ${pkg}")
+ endif()
+ endif()
+endfunction()
diff --git a/cmake_modules/FindQHY.cmake b/cmake_modules/FindQHY.cmake
new file mode 100644
index 0000000..9b41ac5
--- /dev/null
+++ b/cmake_modules/FindQHY.cmake
@@ -0,0 +1,50 @@
+# - Try to find QHY Library
+# Once done this will define
+#
+# QHY_FOUND - system has QHY
+# QHY_INCLUDE_DIR - the QHY include directory
+# QHY_LIBRARIES - Link these to use QHY
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (QHY_INCLUDE_DIR AND QHY_LIBRARIES)
+
+ # in cache already
+ set(QHY_FOUND TRUE)
+ message(STATUS "Found libqhyccd: ${QHY_LIBRARIES}")
+
+else (QHY_INCLUDE_DIR AND QHY_LIBRARIES)
+
+ find_path(QHY_INCLUDE_DIR qhyccd.h
+ PATH_SUFFIXES libqhy
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(QHY_LIBRARIES NAMES qhyccd
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(QHY_INCLUDE_DIR AND QHY_LIBRARIES)
+ set(QHY_FOUND TRUE)
+ else (QHY_INCLUDE_DIR AND QHY_LIBRARIES)
+ set(QHY_FOUND FALSE)
+ endif(QHY_INCLUDE_DIR AND QHY_LIBRARIES)
+
+
+ if (QHY_FOUND)
+ if (NOT QHY_FIND_QUIETLY)
+ message(STATUS "Found QHY: ${QHY_LIBRARIES}")
+ endif (NOT QHY_FIND_QUIETLY)
+ else (QHY_FOUND)
+ if (QHY_FIND_REQUIRED)
+ message(FATAL_ERROR "QHY not found. Please install libqhy http://www.indilib.org")
+ endif (QHY_FIND_REQUIRED)
+ endif (QHY_FOUND)
+
+ mark_as_advanced(QHY_INCLUDE_DIR QHY_LIBRARIES)
+
+endif (QHY_INCLUDE_DIR AND QHY_LIBRARIES)
diff --git a/cmake_modules/FindQSI.cmake b/cmake_modules/FindQSI.cmake
new file mode 100644
index 0000000..afaac6d
--- /dev/null
+++ b/cmake_modules/FindQSI.cmake
@@ -0,0 +1,50 @@
+# - Try to find Quantum Scientific Imaging Library
+# Once done this will define
+#
+# QSI_FOUND - system has QSI
+# QSI_INCLUDE_DIR - the QSI include directory
+# QSI_LIBRARIES - Link these to use QSI
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (QSI_INCLUDE_DIR AND QSI_LIBRARIES)
+
+ # in cache already
+ set(QSI_FOUND TRUE)
+ message(STATUS "Found libqsiapi: ${QSI_LIBRARIES}")
+
+else (QSI_INCLUDE_DIR AND QSI_LIBRARIES)
+
+ find_path(QSI_INCLUDE_DIR qsiapi.h
+ PATH_SUFFIXES qsiapi
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(QSI_LIBRARIES NAMES qsiapi
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(QSI_INCLUDE_DIR AND QSI_LIBRARIES)
+ set(QSI_FOUND TRUE)
+ else (QSI_INCLUDE_DIR AND QSI_LIBRARIES)
+ set(QSI_FOUND FALSE)
+ endif(QSI_INCLUDE_DIR AND QSI_LIBRARIES)
+
+
+ if (QSI_FOUND)
+ if (NOT QSI_FIND_QUIETLY)
+ message(STATUS "Found QSI: ${QSI_LIBRARIES}")
+ endif (NOT QSI_FIND_QUIETLY)
+ else (QSI_FOUND)
+ if (QSI_FIND_REQUIRED)
+ message(FATAL_ERROR "QSI not found. Please install libqsi http://www.indilib.org")
+ endif (QSI_FIND_REQUIRED)
+ endif (QSI_FOUND)
+
+ mark_as_advanced(QSI_INCLUDE_DIR QSI_LIBRARIES)
+
+endif (QSI_INCLUDE_DIR AND QSI_LIBRARIES)
diff --git a/cmake_modules/FindRT.cmake b/cmake_modules/FindRT.cmake
new file mode 100644
index 0000000..db7c4de
--- /dev/null
+++ b/cmake_modules/FindRT.cmake
@@ -0,0 +1,39 @@
+# FindRT.cmake - Try to find the RT library
+# Once done this will define
+#
+# RT_FOUND - System has rt
+# RT_INCLUDE_DIR - The rt include directory
+# RT_LIBRARIES - The libraries needed to use rt
+# RT_DEFINITIONS - Compiler switches required for using rt
+#
+# Also creates an import target called RT::RT
+
+find_path (RT_INCLUDE_DIR NAMES time.h
+ PATHS
+ /usr
+ /usr/local
+ /opt
+ PATH_SUFFIXES
+)
+
+find_library(RT_LIBRARIES NAMES rt
+ PATHS
+ /usr
+ /usr/local
+ /opt
+)
+
+include(FindPackageHandleStandardArgs)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(rt DEFAULT_MSG RT_LIBRARIES RT_INCLUDE_DIR)
+
+mark_as_advanced(RT_INCLUDE_DIR RT_LIBRARIES)
+
+if (NOT TARGET RT::RT)
+ add_library(RT::RT INTERFACE IMPORTED)
+
+ set_target_properties(RT::RT PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES ${RT_INCLUDE_DIR}
+ INTERFACE_LINK_LIBRARIES ${RT_LIBRARIES}
+ )
+endif() \ No newline at end of file
diff --git a/cmake_modules/FindSBIG.cmake b/cmake_modules/FindSBIG.cmake
new file mode 100644
index 0000000..db01e93
--- /dev/null
+++ b/cmake_modules/FindSBIG.cmake
@@ -0,0 +1,50 @@
+# - Try to find SBIG Universal Library
+# Once done this will define
+#
+# SBIG_FOUND - system has SBIG
+# SBIG_INCLUDE_DIR - the SBIG include directory
+# SBIG_LIBRARIES - Link these to use SBIG
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (SBIG_INCLUDE_DIR AND SBIG_LIBRARIES)
+
+ # in cache already
+ set(SBIG_FOUND TRUE)
+ message(STATUS "Found libsbig: ${SBIG_LIBRARIES}")
+
+else (SBIG_INCLUDE_DIR AND SBIG_LIBRARIES)
+
+ find_path(SBIG_INCLUDE_DIR sbigudrv.h
+ PATH_SUFFIXES libsbig
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(SBIG_LIBRARIES NAMES sbig
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(SBIG_INCLUDE_DIR AND SBIG_LIBRARIES)
+ set(SBIG_FOUND TRUE)
+ else (SBIG_INCLUDE_DIR AND SBIG_LIBRARIES)
+ set(SBIG_FOUND FALSE)
+ endif(SBIG_INCLUDE_DIR AND SBIG_LIBRARIES)
+
+
+ if (SBIG_FOUND)
+ if (NOT SBIG_FIND_QUIETLY)
+ message(STATUS "Found SBIG: ${SBIG_LIBRARIES}")
+ endif (NOT SBIG_FIND_QUIETLY)
+ else (SBIG_FOUND)
+ if (SBIG_FIND_REQUIRED)
+ message(FATAL_ERROR "SBIG not found. Please install SBIG Library http://www.indilib.org")
+ endif (SBIG_FIND_REQUIRED)
+ endif (SBIG_FOUND)
+
+ mark_as_advanced(SBIG_INCLUDE_DIR SBIG_LIBRARIES)
+
+endif (SBIG_INCLUDE_DIR AND SBIG_LIBRARIES)
diff --git a/cmake_modules/FindSTARSHOOTG.cmake b/cmake_modules/FindSTARSHOOTG.cmake
new file mode 100644
index 0000000..3551be8
--- /dev/null
+++ b/cmake_modules/FindSTARSHOOTG.cmake
@@ -0,0 +1,49 @@
+# - Try to find Starshoot Camera Library
+# Once done this will define
+#
+# STARSHOOTG_FOUND - system has Starshoot
+# STARSHOOTG_INCLUDE_DIR - the Starshoot include directory
+# STARSHOOTG_LIBRARIES - Link these to use Starshoot
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (STARSHOOTG_INCLUDE_DIR AND STARSHOOTG_LIBRARIES)
+
+ # in cache already
+ set(STARSHOOTG_FOUND TRUE)
+ message(STATUS "Found libstarshootg: ${STARSHOOTG_LIBRARIES}")
+
+else (STARSHOOTG_INCLUDE_DIR AND STARSHOOTG_LIBRARIES)
+
+ find_path(STARSHOOTG_INCLUDE_DIR starshootg.h
+ PATH_SUFFIXES libstarshootg
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(STARSHOOTG_LIBRARIES NAMES starshootg
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(STARSHOOTG_INCLUDE_DIR AND STARSHOOTG_LIBRARIES)
+ set(STARSHOOTG_FOUND TRUE)
+ else (STARSHOOTG_INCLUDE_DIR AND STARSHOOTG_LIBRARIES)
+ set(STARSHOOTG_FOUND FALSE)
+ endif(STARSHOOTG_INCLUDE_DIR AND STARSHOOTG_LIBRARIES)
+
+ if (STARSHOOTG_FOUND)
+ if (NOT STARSHOOTG_FIND_QUIETLY)
+ message(STATUS "Found StarshootG: ${STARSHOOTG_LIBRARIES}")
+ endif (NOT STARSHOOTG_FIND_QUIETLY)
+ else (STARSHOOTG_FOUND)
+ if (STARSHOOTG_FIND_REQUIRED)
+ message(FATAL_ERROR "StarshootG not found. Please install StarshootG Library http://www.indilib.org")
+ endif (STARSHOOTG_FIND_REQUIRED)
+ endif (STARSHOOTG_FOUND)
+
+ mark_as_advanced(STARSHOOTG_INCLUDE_DIR STARSHOOTG_LIBRARIES)
+
+endif (STARSHOOTG_INCLUDE_DIR AND STARSHOOTG_LIBRARIES)
diff --git a/cmake_modules/FindSV305.cmake b/cmake_modules/FindSV305.cmake
new file mode 100644
index 0000000..e5ffcaa
--- /dev/null
+++ b/cmake_modules/FindSV305.cmake
@@ -0,0 +1,52 @@
+# - Try to find SV305 Library
+# Once done this will define
+#
+# SV305_FOUND - system has QHY
+# SV305_INCLUDE_DIR - the QHY include directory
+# SV305_LIBRARIES - Link these to use QHY
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (SV305_INCLUDE_DIR AND SV305_LIBRARIES)
+
+ # in cache already
+ set(SV305_FOUND TRUE)
+ message(STATUS "Found libsv305: ${SV305_LIBRARIES}")
+
+else (SV305_INCLUDE_DIR AND SV305_LIBRARIES)
+
+ # find headers
+ find_path(SV305_INCLUDE_DIR NAMES SVBCameraSDK.h
+ PATH_SUFFIXES libsv305
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ # find libraries
+ find_library(SV305_LIBRARIES NAMES SVBCameraSDK
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(SV305_INCLUDE_DIR AND SV305_LIBRARIES)
+ set(SV305_FOUND TRUE)
+ else (SV305_INCLUDE_DIR AND SV305_LIBRARIES)
+ set(SV305_FOUND FALSE)
+ endif(SV305_INCLUDE_DIR AND SV305_LIBRARIES)
+
+
+ if (SV305_FOUND)
+ if (NOT SV305_FIND_QUIETLY)
+ message(STATUS "Found SV305 libraries : ${SV305_LIBRARIES}")
+ endif (NOT SV305_FIND_QUIETLY)
+ else (SV305_FOUND)
+ if (SV305_FIND_REQUIRED)
+ message(FATAL_ERROR "SV305 libraries not found. Please install libsv305 http://www.indilib.org")
+ endif (SV305_FIND_REQUIRED)
+ endif (SV305_FOUND)
+
+ mark_as_advanced(SV305_INCLUDE_DIR SV305_LIBRARIES)
+
+endif (SV305_INCLUDE_DIR AND SV305_LIBRARIES)
diff --git a/cmake_modules/FindTIFFXX.cmake b/cmake_modules/FindTIFFXX.cmake
new file mode 100644
index 0000000..e478c05
--- /dev/null
+++ b/cmake_modules/FindTIFFXX.cmake
@@ -0,0 +1,41 @@
+# - Try to find TIFFXX Library
+# Once done this will define
+#
+# TIFXX_LIBRARY - Link these to use TIFFXX
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (TIFFXX_LIBRARY)
+
+ # in cache already
+ set(TIFFXX_FOUND TRUE)
+ message(STATUS "Found libtiffxx: ${TIFFXX_LIBRARY}")
+
+else (TIFFXX_LIBRARY)
+
+ find_library(TIFFXX_LIBRARY NAMES tiffxx
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(TIFFXX_LIBRARY)
+ set(TIFFXX_FOUND TRUE)
+ else (TIFFXX_LIBRARY)
+ set(TIFFXX_FOUND FALSE)
+ endif(TIFFXX_LIBRARY)
+
+ if (TIFFXX_FOUND)
+ if (NOT TIFFXX_FIND_QUIETLY)
+ message(STATUS "Found tiffxx: ${TIFFXX_LIBRARY}")
+ endif (NOT TIFFXX_FIND_QUIETLY)
+ else (TIFFXX_FOUND)
+ if (TIFFXX_FIND_REQUIRED)
+ message(FATAL_ERROR "tiffxx is not found. Please install it first.")
+ endif (TIFFXX_FIND_REQUIRED)
+ endif (TIFFXX_FOUND)
+
+ mark_as_advanced(TIFFXX_LIBRARY)
+
+endif (TIFFXX_LIBRARY)
diff --git a/cmake_modules/FindTOUPCAM.cmake b/cmake_modules/FindTOUPCAM.cmake
new file mode 100644
index 0000000..626c3a5
--- /dev/null
+++ b/cmake_modules/FindTOUPCAM.cmake
@@ -0,0 +1,50 @@
+# - Try to find Toupcam Camera Library
+# Once done this will define
+#
+# TOUPCAM_FOUND - system has Toupcam
+# TOUPCAM_INCLUDE_DIR - the Toupcam include directory
+# TOUPCAM_LIBRARIES - Link these to use Toupcam
+
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (TOUPCAM_INCLUDE_DIR AND TOUPCAM_LIBRARIES)
+
+ # in cache already
+ set(TOUPCAM_FOUND TRUE)
+ message(STATUS "Found libsbig: ${TOUPCAM_LIBRARIES}")
+
+else (TOUPCAM_INCLUDE_DIR AND TOUPCAM_LIBRARIES)
+
+ find_path(TOUPCAM_INCLUDE_DIR toupcam.h
+ PATH_SUFFIXES libtoupcam
+ ${_obIncDir}
+ ${GNUWIN32_DIR}/include
+ )
+
+ find_library(TOUPCAM_LIBRARIES NAMES toupcam
+ PATHS
+ ${_obLinkDir}
+ ${GNUWIN32_DIR}/lib
+ )
+
+ if(TOUPCAM_INCLUDE_DIR AND TOUPCAM_LIBRARIES)
+ set(TOUPCAM_FOUND TRUE)
+ else (TOUPCAM_INCLUDE_DIR AND TOUPCAM_LIBRARIES)
+ set(TOUPCAM_FOUND FALSE)
+ endif(TOUPCAM_INCLUDE_DIR AND TOUPCAM_LIBRARIES)
+
+
+ if (TOUPCAM_FOUND)
+ if (NOT TOUPCAM_FIND_QUIETLY)
+ message(STATUS "Found Toupcam: ${TOUPCAM_LIBRARIES}")
+ endif (NOT TOUPCAM_FIND_QUIETLY)
+ else (TOUPCAM_FOUND)
+ if (TOUPCAM_FIND_REQUIRED)
+ message(FATAL_ERROR "Toupcam not found. Please install Toupcam Library http://www.indilib.org")
+ endif (TOUPCAM_FIND_REQUIRED)
+ endif (TOUPCAM_FOUND)
+
+ mark_as_advanced(TOUPCAM_INCLUDE_DIR TOUPCAM_LIBRARIES)
+
+endif (TOUPCAM_INCLUDE_DIR AND TOUPCAM_LIBRARIES)
diff --git a/cmake_modules/FindUSB1.cmake b/cmake_modules/FindUSB1.cmake
new file mode 100644
index 0000000..0e155b4
--- /dev/null
+++ b/cmake_modules/FindUSB1.cmake
@@ -0,0 +1,83 @@
+# - Try to find libusb-1.0
+# Once done this will define
+#
+# USB1_FOUND - system has libusb-1.0
+# USB1_INCLUDE_DIRS - the libusb-1.0 include directories
+# USB1_LIBRARIES - Link these to use libusb-1.0
+# USB1_DEFINITIONS - Compiler switches required for using libusb-1.0
+#
+# USB1_HAS_LIBUSB_ERROR_NAME - defined when libusb-1.0 has libusb_error_name()
+
+#=============================================================================
+# Copyright (c) 2017 Pino Toscano <toscano.pino@tiscali.it>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#=============================================================================
+
+find_package(PkgConfig)
+pkg_check_modules(PC_LIBUSB1 QUIET libusb-1.0)
+
+find_path(USB1_INCLUDE_DIR
+ NAMES
+ libusb.h
+ HINTS
+ ${PC_LIBUSB1_INCLUDE_DIRS}
+ PATH_SUFFIXES
+ libusb-1.0
+)
+
+find_library(USB1_LIBRARY
+ NAMES
+ ${PC_LIBUSB1_LIBRARIES}
+ usb-1.0
+ HINTS
+ ${PC_LIBUSB1_LIBRARY_DIRS}
+)
+
+set(USB1_INCLUDE_DIRS ${USB1_INCLUDE_DIR})
+set(USB1_LIBRARIES ${USB1_LIBRARY})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(USB1
+ FOUND_VAR
+ USB1_FOUND
+ REQUIRED_VARS
+ USB1_LIBRARY
+ USB1_INCLUDE_DIR
+ VERSION_VAR
+ PC_LIBUSB1_VERSION
+)
+
+mark_as_advanced(USB1_INCLUDE_DIRS USB1_LIBRARIES)
+
+if(USB1_FOUND)
+ include(CheckCXXSourceCompiles)
+ include(CMakePushCheckState)
+ cmake_push_check_state(RESET)
+ set(CMAKE_REQUIRED_INCLUDES ${USB1_INCLUDE_DIRS})
+ set(CMAKE_REQUIRED_LIBRARIES ${USB1_LIBRARIES})
+ check_cxx_source_compiles("#include <libusb.h>
+ int main() { libusb_error_name(0); return 0; }" USB1_HAS_LIBUSB_ERROR_NAME)
+ cmake_pop_check_state()
+endif()
diff --git a/cmake_modules/FindVorbis.cmake b/cmake_modules/FindVorbis.cmake
new file mode 100644
index 0000000..d5e273e
--- /dev/null
+++ b/cmake_modules/FindVorbis.cmake
@@ -0,0 +1,32 @@
+# - Find vorbis
+# Find the native vorbis includes and libraries
+#
+# VORBIS_INCLUDE_DIR - where to find vorbis.h, etc.
+# VORBIS_LIBRARIES - List of libraries when using vorbis(file).
+# VORBIS_FOUND - True if vorbis found.
+
+if(VORBIS_INCLUDE_DIR)
+ # Already in cache, be silent
+ set(VORBIS_FIND_QUIETLY TRUE)
+endif(VORBIS_INCLUDE_DIR)
+
+find_path(VORBIS_INCLUDE_DIR vorbis/vorbisfile.h)
+
+find_library(OGG_LIBRARY NAMES ogg)
+find_library(VORBIS_LIBRARY NAMES vorbis)
+find_library(VORBISFILE_LIBRARY NAMES vorbisfile)
+
+# Handle the QUIETLY and REQUIRED arguments and set VORBIS_FOUND to TRUE if
+# all listed variables are TRUE.
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(VORBIS DEFAULT_MSG
+ VORBIS_INCLUDE_DIR OGG_LIBRARY VORBIS_LIBRARY VORBIS_LIBRARY)
+
+if(VORBIS_FOUND)
+ set(VORBIS_LIBRARIES ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} ${OGG_LIBRARY})
+else(VORBIS_FOUND)
+ set(VORBIS_LIBRARIES)
+endif(VORBIS_FOUND)
+
+mark_as_advanced(VORBIS_INCLUDE_DIR)
+mark_as_advanced(OGG_LIBRARY VORBIS_LIBRARY VORBISFILE_LIBRARY)
diff --git a/cmake_modules/InstallImported.cmake b/cmake_modules/InstallImported.cmake
new file mode 100644
index 0000000..740753c
--- /dev/null
+++ b/cmake_modules/InstallImported.cmake
@@ -0,0 +1,92 @@
+
+function (install_imported)
+
+ cmake_parse_arguments (ARG "" "DESTINATION" "TARGETS" ${ARGN})
+
+ if (NOT DEFINED ARG_DESTINATION)
+ message (FATAL_ERROR "DESTINATION not defined")
+ endif ()
+
+ foreach (target ${ARG_TARGETS})
+
+ get_target_property (location ${target} LOCATION)
+ get_target_property (version ${target} VERSION)
+ get_target_property (soversion ${target} SOVERSION)
+ get_target_property (output_name ${target} OUTPUT_NAME)
+ get_target_property (suffix ${target} SUFFIX)
+ get_target_property (type ${target} TYPE)
+
+ if (NOT ${type} STREQUAL "SHARED_LIBRARY")
+ message (FATAL_ERROR "install_imported: ${type} not supported")
+ endif ()
+
+ if (${location} STREQUAL "${target}-NOTFOUND")
+ return ()
+ endif ()
+
+ if (NOT ${version} STREQUAL "version-NOTFOUND")
+ set (version ".${version}")
+ else ()
+ set (version "")
+ endif ()
+
+ if (NOT ${soversion} STREQUAL "soversion-NOTFOUND")
+ set (soversion ".${soversion}")
+ else ()
+ set (soversion "")
+ endif ()
+
+ if (${output_name} STREQUAL "output_name-NOTFOUND")
+ set (output_name ${target})
+ endif ()
+
+ set (name_noversion "${CMAKE_SHARED_LIBRARY_PREFIX}${output_name}${CMAKE_SHARED_LIBRARY_SUFFIX}")
+
+ if (APPLE)
+ set (name_version "${CMAKE_SHARED_LIBRARY_PREFIX}${output_name}${version}${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ set (name_soversion "${CMAKE_SHARED_LIBRARY_PREFIX}${output_name}${soversion}${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ else ()
+ set (name_version "${CMAKE_SHARED_LIBRARY_PREFIX}${output_name}${CMAKE_SHARED_LIBRARY_SUFFIX}${version}")
+ set (name_soversion "${CMAKE_SHARED_LIBRARY_PREFIX}${output_name}${CMAKE_SHARED_LIBRARY_SUFFIX}${soversion}")
+ endif ()
+
+ if (NOT IS_ABSOLUTE ${location})
+ set (location ${CMAKE_CURRENT_SOURCE_DIR}/${location})
+ endif ()
+
+ if (NOT ${name_noversion} STREQUAL ${name_soversion})
+ add_custom_command (
+ OUTPUT ${name_noversion}
+ COMMAND ${CMAKE_COMMAND} -E create_symlink ${name_soversion} ${name_noversion} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ MAIN_DEPENDENCY ${name_soversion}
+ )
+
+ install (FILES ${CMAKE_CURRENT_BINARY_DIR}/${name_noversion} DESTINATION ${ARG_DESTINATION})
+ endif ()
+
+ if (NOT ${name_soversion} STREQUAL ${name_version})
+ add_custom_command (
+ OUTPUT ${name_soversion}
+ COMMAND ${CMAKE_COMMAND} -E create_symlink ${name_version} ${name_soversion} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ MAIN_DEPENDENCY ${name_version}
+ )
+
+ install (FILES ${CMAKE_CURRENT_BINARY_DIR}/${name_soversion} DESTINATION ${ARG_DESTINATION})
+ endif ()
+
+ add_custom_command (
+ OUTPUT ${name_version}
+ COMMAND ${CMAKE_COMMAND} -E copy "${location}" "${CMAKE_CURRENT_BINARY_DIR}/${name_version}"
+ MAIN_DEPENDENCY ${location}
+ )
+
+ install (FILES ${CMAKE_CURRENT_BINARY_DIR}/${name_version} DESTINATION ${ARG_DESTINATION})
+
+ add_custom_target(
+ imported_${output_name} ALL
+ DEPENDS ${name_version} ${name_noversion} ${name_soversion}
+ )
+
+ endforeach ()
+
+endfunction ()
diff --git a/cmake_modules/UnityBuild.cmake b/cmake_modules/UnityBuild.cmake
new file mode 100644
index 0000000..7c133f1
--- /dev/null
+++ b/cmake_modules/UnityBuild.cmake
@@ -0,0 +1,158 @@
+#
+# Copyright (c) 2009-2012 Christoph Heindl
+# Copyright (c) 2015 Csaba Kertész (csaba.kertesz@gmail.com)
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the <organization> nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+MACRO (COMMIT_UNITY_FILE UNITY_FILE FILE_CONTENT)
+ SET(DIRTY FALSE)
+ # Check if the build file exists
+ SET(OLD_FILE_CONTENT "")
+ IF (NOT EXISTS ${${UNITY_FILE}} AND NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${${UNITY_FILE}})
+ SET(DIRTY TRUE)
+ ELSE ()
+ # Check the file content
+ FILE(STRINGS ${${UNITY_FILE}} OLD_FILE_CONTENT)
+ STRING(REPLACE ";" "" OLD_FILE_CONTENT "${OLD_FILE_CONTENT}")
+ STRING(REPLACE "\n" "" NEW_CONTENT "${${FILE_CONTENT}}")
+ STRING(COMPARE EQUAL "${OLD_FILE_CONTENT}" "${NEW_CONTENT}" EQUAL_CHECK)
+ IF (NOT EQUAL_CHECK EQUAL 1)
+ SET(DIRTY TRUE)
+ ENDIF ()
+ ENDIF ()
+ IF (DIRTY MATCHES TRUE)
+ MESSAGE(STATUS "Write Unity Build file: " ${${UNITY_FILE}})
+ FILE(WRITE ${${UNITY_FILE}} "${${FILE_CONTENT}}")
+ ENDIF ()
+ # Create a dummy copy of the unity file to trigger CMake reconfigure if it is deleted.
+ SET(UNITY_FILE_PATH "")
+ SET(UNITY_FILE_NAME "")
+ GET_FILENAME_COMPONENT(UNITY_FILE_PATH ${${UNITY_FILE}} PATH)
+ GET_FILENAME_COMPONENT(UNITY_FILE_NAME ${${UNITY_FILE}} NAME)
+ CONFIGURE_FILE(${${UNITY_FILE}} ${UNITY_FILE_PATH}/CMakeFiles/${UNITY_FILE_NAME}.dummy)
+ENDMACRO ()
+
+MACRO (ENABLE_UNITY_BUILD TARGET_NAME SOURCE_VARIABLE_NAME UNIT_SIZE EXTENSION)
+ # Limit is zero based conversion of unit_size
+ MATH(EXPR LIMIT ${UNIT_SIZE}-1)
+ SET(FILES ${SOURCE_VARIABLE_NAME})
+ # Effectivly ignore the source files from the build, but keep track them for changes.
+ SET_SOURCE_FILES_PROPERTIES(${${FILES}} PROPERTIES HEADER_FILE_ONLY true)
+ # Counts the number of source files up to the threshold
+ SET(COUNTER ${LIMIT})
+ # Have one or more unity build files
+ SET(FILE_NUMBER 0)
+ SET(BUILD_FILE "")
+ SET(BUILD_FILE_CONTENT "")
+ SET(UNITY_BUILD_FILES "")
+ SET(_DEPS "")
+
+ FOREACH (SOURCE_FILE ${${FILES}})
+ IF (COUNTER EQUAL LIMIT)
+ SET(_DEPS "")
+ # Write the actual Unity Build file
+ IF (NOT ${BUILD_FILE} STREQUAL "" AND NOT ${BUILD_FILE_CONTENT} STREQUAL "")
+ COMMIT_UNITY_FILE(BUILD_FILE BUILD_FILE_CONTENT)
+ ENDIF ()
+ SET(UNITY_BUILD_FILES ${UNITY_BUILD_FILES} ${BUILD_FILE})
+ # Set the variables for the current Unity Build file
+ SET(BUILD_FILE ${CMAKE_CURRENT_BINARY_DIR}/unitybuild_${FILE_NUMBER}_${TARGET_NAME}.${EXTENSION})
+ SET(BUILD_FILE_CONTENT "// Unity Build file generated by CMake\n")
+ MATH(EXPR FILE_NUMBER ${FILE_NUMBER}+1)
+ SET(COUNTER 0)
+ ENDIF ()
+ # Add source path to the file name if it is not there yet.
+ SET(FINAL_SOURCE_FILE "")
+ SET(SOURCE_PATH "")
+ GET_FILENAME_COMPONENT(SOURCE_PATH ${SOURCE_FILE} PATH)
+ IF (SOURCE_PATH STREQUAL "" OR NOT EXISTS ${SOURCE_FILE})
+ SET(FINAL_SOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_FILE})
+ ELSE ()
+ SET(FINAL_SOURCE_FILE ${SOURCE_FILE})
+ ENDIF ()
+ # Treat only the existing files or moc_*.cpp files
+ STRING(FIND ${SOURCE_FILE} "moc_" MOC_POS)
+ IF (EXISTS ${FINAL_SOURCE_FILE} OR MOC_POS GREATER -1)
+ # Add md5 hash of the source file (except moc files) to the build file content
+ IF (MOC_POS LESS 0)
+ SET(MD5_HASH "")
+ FILE(MD5 ${FINAL_SOURCE_FILE} MD5_HASH)
+ SET(BUILD_FILE_CONTENT "${BUILD_FILE_CONTENT}// md5: ${MD5_HASH}\n")
+ ENDIF ()
+ # Add the source file to the build file content
+ IF (MOC_POS GREATER -1)
+ SET(BUILD_FILE_CONTENT "${BUILD_FILE_CONTENT}#include <${SOURCE_FILE}>\n")
+ ELSE ()
+ SET(BUILD_FILE_CONTENT "${BUILD_FILE_CONTENT}#include <${FINAL_SOURCE_FILE}>\n")
+ ENDIF ()
+ # Add the source dependencies to the Unity Build file
+ GET_SOURCE_FILE_PROPERTY(_FILE_DEPS ${SOURCE_FILE} OBJECT_DEPENDS)
+
+ IF (_FILE_DEPS)
+ SET(_DEPS ${_DEPS} ${_FILE_DEPS})
+ SET_SOURCE_FILES_PROPERTIES(${BUILD_FILE} PROPERTIES OBJECT_DEPENDS "${_DEPS}")
+ ENDIF()
+ # Keep counting up to the threshold. Increment counter.
+ MATH(EXPR COUNTER ${COUNTER}+1)
+ ENDIF ()
+ ENDFOREACH ()
+ # Write out the last Unity Build file
+ IF (NOT ${BUILD_FILE} STREQUAL "" AND NOT ${BUILD_FILE_CONTENT} STREQUAL "")
+ COMMIT_UNITY_FILE(BUILD_FILE BUILD_FILE_CONTENT)
+ ENDIF ()
+ SET(UNITY_BUILD_FILES ${UNITY_BUILD_FILES} ${BUILD_FILE})
+ SET(${SOURCE_VARIABLE_NAME} ${${SOURCE_VARIABLE_NAME}} ${UNITY_BUILD_FILES})
+ENDMACRO ()
+
+MACRO (UNITY_GENERATE_MOC TARGET_NAME SOURCES HEADERS)
+ SET(NEW_SOURCES "")
+ FOREACH (HEADER_FILE ${${HEADERS}})
+ IF (NOT EXISTS ${HEADER_FILE})
+ MESSAGE(FATAL_ERROR "Header file does not exist (mocing): ${HEADER_FILE}")
+ ENDIF ()
+ FILE(READ ${HEADER_FILE} FILE_CONTENT)
+ STRING(FIND "${FILE_CONTENT}" "Q_OBJECT" QOBJECT_POS)
+ STRING(FIND "${FILE_CONTENT}" "Q_SLOTS" QSLOTS_POS)
+ STRING(FIND "${FILE_CONTENT}" "Q_SIGNALS" QSIGNALS_POS)
+ STRING(FIND "${FILE_CONTENT}" "QObject" OBJECT_POS)
+ STRING(FIND "${FILE_CONTENT}" "slots" SLOTS_POS)
+ STRING(FIND "${FILE_CONTENT}" "signals" SIGNALS_POS)
+ IF (QOBJECT_POS GREATER 0 OR OBJECT_POS GREATER 0 OR QSLOTS_POS GREATER 0 OR Q_SIGNALS GREATER 0 OR
+ SLOTS_POS GREATER 0 OR SIGNALS GREATER 0)
+ # Generate the moc filename
+ GET_FILENAME_COMPONENT(HEADER_BASENAME ${HEADER_FILE} NAME_WE)
+ SET(MOC_FILENAME "moc_${HEADER_BASENAME}.cpp")
+ SET(NEW_SOURCES ${NEW_SOURCES} ; "${CMAKE_CURRENT_BINARY_DIR}/${MOC_FILENAME}")
+ ADD_CUSTOM_COMMAND(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${MOC_FILENAME}"
+ DEPENDS ${HEADER_FILE}
+ COMMAND ${QT_MOC_EXECUTABLE} ${HEADER_FILE} -o "${CMAKE_CURRENT_BINARY_DIR}/${MOC_FILENAME}")
+ ENDIF ()
+ ENDFOREACH ()
+ IF (NEW_SOURCES)
+ SET_SOURCE_FILES_PROPERTIES(${NEW_SOURCES} PROPERTIES GENERATED TRUE)
+ SET(${SOURCES} ${${SOURCES}} ; ${NEW_SOURCES})
+ ENDIF ()
+ENDMACRO ()
diff --git a/indi-celestronaux/.gitignore b/indi-celestronaux/.gitignore
new file mode 100644
index 0000000..bee8a64
--- /dev/null
+++ b/indi-celestronaux/.gitignore
@@ -0,0 +1 @@
+__pycache__
diff --git a/indi-celestronaux/CMakeLists.txt b/indi-celestronaux/CMakeLists.txt
new file mode 100644
index 0000000..9a3cd27
--- /dev/null
+++ b/indi-celestronaux/CMakeLists.txt
@@ -0,0 +1,33 @@
+########### Celestron AUX INDI driver ##############
+PROJECT(indi-celestronaux C CXX)
+cmake_minimum_required(VERSION 3.0)
+
+include(GNUInstallDirs)
+
+LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/")
+LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake_modules/")
+
+find_package(INDI REQUIRED)
+find_package(Nova REQUIRED)
+find_package(ZLIB REQUIRED)
+find_package(GSL REQUIRED)
+
+set(CAUX_VERSION_MAJOR 1)
+set(CAUX_VERSION_MINOR 2)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h )
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/indi_celestronaux.xml.cmake ${CMAKE_CURRENT_BINARY_DIR}/indi_celestronaux.xml )
+
+include_directories( ${CMAKE_CURRENT_BINARY_DIR})
+include_directories( ${CMAKE_CURRENT_SOURCE_DIR})
+include_directories( ${INDI_INCLUDE_DIR})
+include_directories( ${NOVA_INCLUDE_DIR})
+include_directories( ${EV_INCLUDE_DIR})
+
+include(CMakeCommon)
+
+add_executable(indi_celestron_aux auxproto.cpp celestronaux.cpp)
+target_link_libraries(indi_celestron_aux ${INDI_LIBRARIES} ${NOVA_LIBRARIES} ${GSL_LIBRARIES})
+install(TARGETS indi_celestron_aux RUNTIME DESTINATION bin)
+
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/indi_celestronaux.xml DESTINATION ${INDI_DATA_DIR})
diff --git a/indi-celestronaux/README.md b/indi-celestronaux/README.md
new file mode 100644
index 0000000..0b831d8
--- /dev/null
+++ b/indi-celestronaux/README.md
@@ -0,0 +1,102 @@
+Celestron AUX protocol driver
+-------------------------------------
+
+Authors: Paweł T. Jochym <jochym@wolf.ifj.edu.pl>
+ Fabrizio Pollastri <https://github.com/fabriziop>
+
+*Do not use this driver unattended! This is BETA software! Always have your power switch ready! It is NOT SUITABLE for autonomous operation yet!*
+*There are no slew limits implemented at this stage.*
+
+This is eqmod-style driver for the NexStar and other Celestron AUX-protocol
+mounts. It works over serial link to PC/AUX ports or HC serial port
+and over WiFi to the NexStar-Evolution or SkyFi-equipped mount.
+
+The driver is in the beta stage.
+It is functional and should work as intended but it is not complete.
+I am using it and will be happy to help any brave testers.
+I of course welcome any feedback/contribution.
+
+What works:
+- N-star alignment (with INDI alignment module)
+- Basic tracking, slew, park/unpark
+- GPS simulation. If you have HC connected and you have active gps driver
+ it can simulate Celestron GPS device and serve GPS data to HC. Works quite
+ nicely on RaspberryPi with a GPS module. You can actually use it as
+ a replacement for the Celestron GPS.
+- Cordwrap control
+
+What does not work/is not implemented:
+- Joystick control
+- Slew limits
+- HC interaction (tracking HC motor commands to function as joystick)
+- Probably many other things
+
+Install
+-------
+
+The driver is not included in the PPA distribution yet - due to its beta
+state. So to use it you need to compile it from the source yourself.
+
+You can make a stand-alone compilation or build the debian packages for your
+system. It should be fairly easy. Let me know if something in the following
+guide is wrong or if you have problem with compiling the driver.
+
+Get the source
+==============
+
+You can get the source from the SVN repository of the system on sourceforge
+maintained by the INDI project (see the website of the project) or get it
+from the github mirror of the sourceforge repository maintained by the author
+of this driver. Both will do fine. The github repository lets you track the
+development of the driver more closely in the nse branch of the repository,
+since only master branch is uploaded back to the upstream SVN repository.
+
+- Make some working directory and change into it.
+- Get the source from the github master branch - it takes a while
+ the repo is 64MB in size.
+
+Compiling on any linux system
+=============================
+
+The compilation is simple. You will need indi libraries installed. The best way
+is to install libindi-dev package from the PPA. You may also want to have
+indi-gpsd and gpsd packages installed (not strictly required). If you cannot use
+the PPA you need to install libindi-dev from your distribution or compile the
+indi libraries yourself using instructions from the INDI website. I have not
+tested the backward compatibility but the driver should compile and work at
+least with the 1.8.4 version of the library. My recommendation: use PPA if you
+can. To compile the driver you will need also: cmake, cdbs, libindi-dev,
+libnova-dev, zlib1g-dev. Run following commands (you can select other install
+prefix):
+
+```sh
+mkdir -p ~/Projects/build/indi-caux
+cd ~/Projects/build/indi-caux
+cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Debug ~/Projects/indi-3rdparty/indi-celestronaux
+make
+```
+You can run `make install` optionally at the end if you like to have the driver
+properly installed.
+
+
+Building debian/ubuntu packages
+===============================
+
+To build the debian package you will need the debian packaging tools:
+`build-essential, devscripts, debhelper, fakeroot`
+
+Create `package` directory at the same level as indilib directory with the
+cloned source. Then execute:
+
+```sh
+mkdir -p ~/Projects/build/deb-indi-caux
+cd ~/Projects/build/deb-indi-caux
+cp -r ~/Projects/indi-3rdparty/indi-celestronaux .
+cp -r ~/Projects/indi-3rdparty/debian//indi-celestronaux debian
+cp -r ~/Projects/indi-3rdparty/cmake_modules indi-celestronaux/
+fakeroot debian/rules binary
+fakeroot debian/rules clean
+```
+this should produce two packages in the main build directory (above `package`),
+which you can install with `sudo dpkg -i indi-celestronaux_*.deb`.
+
diff --git a/indi-celestronaux/auxproto.cpp b/indi-celestronaux/auxproto.cpp
new file mode 100644
index 0000000..9891e10
--- /dev/null
+++ b/indi-celestronaux/auxproto.cpp
@@ -0,0 +1,467 @@
+/*
+ Celestron Aux Command
+
+ Copyright (C) 2020 Paweł T. Jochym
+ Copyright (C) 2020 Fabrizio Pollastri
+ Copyright (C) 2021 Jasem Mutlaq
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include "auxproto.h"
+
+#include <indilogger.h>
+#include <math.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#define READ_TIMEOUT 1 // s
+#define CTS_TIMEOUT 100 // ms
+#define RTS_DELAY 50 // ms
+
+#define BUFFER_SIZE 512
+int MAX_CMD_LEN = 32;
+
+uint8_t AUXCommand::DEBUG_LEVEL = 0;
+char AUXCommand::DEVICE_NAME[64] = {0};
+//////////////////////////////////////////////////
+/////// Utility functions
+//////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void logBytes(unsigned char *buf, int n, const char *deviceName, uint32_t debugLevel)
+{
+ char hex_buffer[BUFFER_SIZE] = {0};
+ for (int i = 0; i < n; i++)
+ sprintf(hex_buffer + 3 * i, "%02X ", buf[i]);
+
+ if (n > 0)
+ hex_buffer[3 * n - 1] = '\0';
+
+ DEBUGFDEVICE(deviceName, debugLevel, "[%s]", hex_buffer);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void AUXCommand::logResponse()
+{
+ char hex_buffer[BUFFER_SIZE] = {0}, part1[BUFFER_SIZE] = {0}, part2[BUFFER_SIZE] = {0}, part3[BUFFER_SIZE] = {0};
+ for (size_t i = 0; i < m_Data.size(); i++)
+ sprintf(hex_buffer + 3 * i, "%02X ", m_Data[i]);
+
+ if (m_Data.size() > 0)
+ hex_buffer[3 * m_Data.size() - 1] = '\0';
+
+ const char * c = commandName(m_Command);
+ const char * s = moduleName(m_Source);
+ const char * d = moduleName(m_Destination);
+
+ if (c != nullptr)
+ snprintf(part1, BUFFER_SIZE, "<%12s>", c);
+ else
+ snprintf(part1, BUFFER_SIZE, "<%02x>", m_Command);
+
+ if (s != nullptr)
+ snprintf(part2, BUFFER_SIZE, "%5s ->", s);
+ else
+ snprintf(part2, BUFFER_SIZE, "%02x ->", m_Source);
+
+ if (s != nullptr)
+ snprintf(part3, BUFFER_SIZE, "%5s", d);
+ else
+ snprintf(part3, BUFFER_SIZE, "%02x", m_Destination);
+
+ if (m_Data.size() > 0)
+ DEBUGFDEVICE(DEVICE_NAME, DEBUG_LEVEL, "RES %s%s%s [%s]", part1, part2, part3, hex_buffer);
+ else
+ DEBUGFDEVICE(DEVICE_NAME, DEBUG_LEVEL, "RES %s%s%s", part1, part2, part3);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void AUXCommand::logCommand()
+{
+ char hex_buffer[BUFFER_SIZE] = {0}, part1[BUFFER_SIZE] = {0}, part2[BUFFER_SIZE] = {0}, part3[BUFFER_SIZE] = {0};
+ for (size_t i = 0; i < m_Data.size(); i++)
+ sprintf(hex_buffer + 3 * i, "%02X ", m_Data[i]);
+
+ if (m_Data.size() > 0)
+ hex_buffer[3 * m_Data.size() - 1] = '\0';
+
+ const char * c = commandName(m_Command);
+ const char * s = moduleName(m_Source);
+ const char * d = moduleName(m_Destination);
+
+ if (c != nullptr)
+ snprintf(part1, BUFFER_SIZE, "<%12s>", c);
+ else
+ snprintf(part1, BUFFER_SIZE, "<%02x>", m_Command);
+
+ if (s != nullptr)
+ snprintf(part2, BUFFER_SIZE, "%5s ->", s);
+ else
+ snprintf(part2, BUFFER_SIZE, "%02x ->", m_Source);
+
+ if (s != nullptr)
+ snprintf(part3, BUFFER_SIZE, "%5s", d);
+ else
+ snprintf(part3, BUFFER_SIZE, "%02x", m_Destination);
+
+ if (m_Data.size() > 0)
+ DEBUGFDEVICE(DEVICE_NAME, DEBUG_LEVEL, "CMD %s%s%s [%s]", part1, part2, part3, hex_buffer);
+ else
+ DEBUGFDEVICE(DEVICE_NAME, DEBUG_LEVEL, "CMD %s%s%s", part1, part2, part3);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void AUXCommand::setDebugInfo(const char *deviceName, uint8_t debugLevel)
+{
+ strncpy(DEVICE_NAME, deviceName, 64);
+ DEBUG_LEVEL = debugLevel;
+}
+////////////////////////////////////////////////
+////// AUXCommand class
+////////////////////////////////////////////////
+
+AUXCommand::AUXCommand()
+{
+ m_Data.reserve(MAX_CMD_LEN);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+AUXCommand::AUXCommand(const AUXBuffer &buf)
+{
+ m_Data.reserve(MAX_CMD_LEN);
+ parseBuf(buf);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+AUXCommand::AUXCommand(AUXCommands command, AUXTargets source, AUXTargets destination, const AUXBuffer &data)
+{
+ m_Command = command;
+ m_Source = source;
+ m_Destination = destination;
+ m_Data.reserve(MAX_CMD_LEN);
+ m_Data = data;
+ len = 3 + m_Data.size();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+AUXCommand::AUXCommand(AUXCommands command, AUXTargets source, AUXTargets destination)
+{
+ m_Command = command;
+ m_Source = source;
+ m_Destination = destination;
+ m_Data.reserve(MAX_CMD_LEN);
+ len = 3 + m_Data.size();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+const char * AUXCommand::commandName(AUXCommands command) const
+{
+ if (m_Source == GPS || m_Destination == GPS)
+ {
+ switch (command)
+ {
+ case GPS_GET_LAT:
+ return "GPS_GET_LAT";
+ case GPS_GET_LONG:
+ return "GPS_GET_LONG";
+ case GPS_GET_DATE:
+ return "GPS_GET_DATE";
+ case GPS_GET_YEAR:
+ return "GPS_GET_YEAR";
+ case GPS_GET_TIME:
+ return "GPS_GET_TIME";
+ case GPS_TIME_VALID:
+ return "GPS_TIME_VALID";
+ case GPS_LINKED:
+ return "GPS_LINKED";
+ case GET_VER:
+ return "GET_VER";
+ default :
+ return nullptr;
+ }
+ }
+ else
+ {
+ switch (command)
+ {
+ case MC_GET_POSITION:
+ return "MC_GET_POSITION";
+ case MC_GOTO_FAST:
+ return "MC_GOTO_FAST";
+ case MC_SET_POSITION:
+ return "MC_SET_POSITION";
+ case MC_SET_POS_GUIDERATE:
+ return "MC_SET_POS_GUIDERATE";
+ case MC_SET_NEG_GUIDERATE:
+ return "MC_SET_NEG_GUIDERATE";
+ case MC_LEVEL_START:
+ return "MC_LEVEL_START";
+ case MC_SLEW_DONE:
+ return "MC_SLEW_DONE";
+ case MC_GOTO_SLOW:
+ return "MC_GOTO_SLOW";
+ case MC_SEEK_INDEX:
+ return "MC_SEEK_INDEX";
+ case MC_MOVE_POS:
+ return "MC_MOVE_POS";
+ case MC_MOVE_NEG:
+ return "MC_MOVE_NEG";
+ case MC_ENABLE_CORDWRAP:
+ return "MC_ENABLE_CORDWRAP";
+ case MC_DISABLE_CORDWRAP:
+ return "MC_DISABLE_CORDWRAP";
+ case MC_SET_CORDWRAP_POS:
+ return "MC_SET_CORDWRAP_POS";
+ case MC_POLL_CORDWRAP:
+ return "MC_POLL_CORDWRAP";
+ case MC_GET_CORDWRAP_POS:
+ return "MC_GET_CORDWRAP_POS";
+ case GET_VER:
+ return "GET_VER";
+ default :
+ return nullptr;
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+int AUXCommand::responseDataSize()
+{
+ if (m_Source == GPS || m_Destination == GPS)
+ {
+ switch (m_Command)
+ {
+ case GPS_GET_LAT:
+ case GPS_GET_LONG:
+ case GPS_GET_TIME:
+ return 3;
+ case GPS_GET_DATE:
+ case GPS_GET_YEAR:
+ case GET_VER:
+ return 2;
+ case GPS_TIME_VALID:
+ case GPS_LINKED:
+ return 1;
+ default :
+ return -1;
+ }
+ }
+ else
+ {
+ switch (m_Command)
+ {
+ case MC_GET_POSITION:
+ case MC_GET_CORDWRAP_POS:
+ return 3;
+ case GET_VER:
+ return 4;
+ case MC_SLEW_DONE:
+ case MC_SEEK_DONE:
+ case MC_LEVEL_DONE:
+ case MC_POLL_CORDWRAP:
+ return 1;
+ case MC_GOTO_FAST:
+ case MC_SET_POSITION:
+ case MC_SET_POS_GUIDERATE:
+ case MC_SET_NEG_GUIDERATE:
+ case MC_LEVEL_START:
+ case MC_GOTO_SLOW:
+ case MC_MOVE_POS:
+ case MC_MOVE_NEG:
+ case MC_ENABLE_CORDWRAP:
+ case MC_DISABLE_CORDWRAP:
+ case MC_SET_CORDWRAP_POS:
+ return 0;
+ case MC_SEEK_INDEX:
+ return -1;
+ default :
+ return -1;
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+const char * AUXCommand::moduleName(AUXTargets n)
+{
+ switch (n)
+ {
+ case ANY :
+ return "ANY";
+ case MB :
+ return "MB";
+ case HC :
+ return "HC";
+ case HCP :
+ return "HC+";
+ case AZM :
+ return "AZM";
+ case ALT :
+ return "ALT";
+ case APP :
+ return "APP";
+ case GPS :
+ return "GPS";
+ case WiFi:
+ return "WiFi";
+ case BAT :
+ return "BAT";
+ case CHG :
+ return "CHG";
+ case LIGHT :
+ return "LIGHT";
+ default :
+ return nullptr;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void AUXCommand::fillBuf(AUXBuffer &buf)
+{
+ buf.resize(len + 3);
+
+ buf[0] = 0x3b;
+ buf[1] = len;
+ buf[2] = m_Source;
+ buf[3] = m_Destination;
+ buf[4] = m_Command;
+ for (uint32_t i = 0; i < m_Data.size(); i++)
+ {
+ buf[i + 5] = m_Data[i];
+ }
+ buf.back() = checksum(buf);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void AUXCommand::parseBuf(AUXBuffer buf)
+{
+ len = buf[1];
+ m_Source = (AUXTargets)buf[2];
+ m_Destination = (AUXTargets)buf[3];
+ m_Command = (AUXCommands)buf[4];
+ m_Data = AUXBuffer(buf.begin() + 5, buf.end() - 1);
+ valid = (checksum(buf) == buf.back());
+ if (valid == false)
+ {
+ DEBUGFDEVICE(DEVICE_NAME, DEBUG_LEVEL, "Checksum error: %02x vs. %02x", checksum(buf), buf.back());
+ };
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void AUXCommand::parseBuf(AUXBuffer buf, bool do_checksum)
+{
+ (void)do_checksum;
+
+ len = buf[1];
+ m_Source = (AUXTargets)buf[2];
+ m_Destination = (AUXTargets)buf[3];
+ m_Command = (AUXCommands)buf[4];
+ if (buf.size() > 5)
+ m_Data = AUXBuffer(buf.begin() + 5, buf.end());
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+unsigned char AUXCommand::checksum(AUXBuffer buf)
+{
+ int l = buf[1];
+ int cs = 0;
+ for (int i = 1; i < l + 2; i++)
+ {
+ cs += buf[i];
+ }
+ return (unsigned char)(((~cs) + 1) & 0xFF);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// Return 8, 16, or 24bit value as dictacted by the data response size.
+/////////////////////////////////////////////////////////////////////////////////////
+uint32_t AUXCommand::getData()
+{
+ uint32_t value = 0;
+ switch (m_Data.size())
+ {
+ case 3:
+ value = (m_Data[0] << 16) | (m_Data[1] << 8) | m_Data[2];
+ break;
+
+ case 2:
+ value = (m_Data[0] << 8) | m_Data[1];
+ break;
+
+ case 1:
+ value = m_Data[0];
+ break;
+ }
+
+ return value;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// Set encoder position in steps.
+/////////////////////////////////////////////////////////////////////////////////////
+void AUXCommand::setData(uint32_t value, uint8_t bytes)
+{
+ m_Data.resize(bytes);
+ switch (bytes)
+ {
+ case 1:
+ len = 4;
+ m_Data[0] = static_cast<uint8_t>(value >> 0 & 0xff);
+ break;
+ case 2:
+ len = 5;
+ m_Data[1] = static_cast<uint8_t>(value >> 0 & 0xff);
+ m_Data[0] = static_cast<uint8_t>(value >> 8 & 0xff);
+ break;
+
+ case 3:
+ default:
+ len = 6;
+ m_Data[2] = static_cast<uint8_t>(value >> 0 & 0xff);
+ m_Data[1] = static_cast<uint8_t>(value >> 8 & 0xff);
+ m_Data[0] = static_cast<uint8_t>(value >> 16 & 0xff);
+ break;
+ }
+}
diff --git a/indi-celestronaux/auxproto.h b/indi-celestronaux/auxproto.h
new file mode 100644
index 0000000..3593eee
--- /dev/null
+++ b/indi-celestronaux/auxproto.h
@@ -0,0 +1,169 @@
+/*
+ Celestron Aux Command
+
+ Copyright (C) 2020 Paweł T. Jochym
+ Copyright (C) 2020 Fabrizio Pollastri
+ Copyright (C) 2021 Jasem Mutlaq
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#pragma once
+
+#include <vector>
+#include <stddef.h>
+#include <stdint.h>
+
+typedef std::vector<uint8_t> AUXBuffer;
+
+enum AUXCommands
+{
+ MC_GET_POSITION = 0x01,
+ MC_GOTO_FAST = 0x02,
+ MC_SET_POSITION = 0x04,
+ MC_SET_POS_GUIDERATE = 0x06,
+ MC_SET_NEG_GUIDERATE = 0x07,
+ MC_LEVEL_START = 0x0b,
+ MC_LEVEL_DONE = 0x12,
+ MC_SLEW_DONE = 0x13,
+ MC_GOTO_SLOW = 0x17,
+ MC_SEEK_DONE = 0x18,
+ MC_SEEK_INDEX = 0x19,
+ MC_MOVE_POS = 0x24,
+ MC_MOVE_NEG = 0x25,
+ MC_AUX_GUIDE = 0x26,
+ MC_AUX_GUIDE_ACTIVE = 0x27,
+ MC_ENABLE_CORDWRAP = 0x38,
+ MC_DISABLE_CORDWRAP = 0x39,
+ MC_SET_CORDWRAP_POS = 0x3a,
+ MC_POLL_CORDWRAP = 0x3b,
+ MC_GET_CORDWRAP_POS = 0x3c,
+ MC_SET_AUTOGUIDE_RATE = 0x46,
+ MC_GET_AUTOGUIDE_RATE = 0x47,
+ GET_VER = 0xfe,
+ GPS_GET_LAT = 0x01,
+ GPS_GET_LONG = 0x02,
+ GPS_GET_DATE = 0x03,
+ GPS_GET_YEAR = 0x04,
+ GPS_GET_TIME = 0x33,
+ GPS_TIME_VALID = 0x36,
+ GPS_LINKED = 0x37
+};
+
+enum AUXTargets
+{
+ ANY = 0x00,
+ MB = 0x01,
+ HC = 0x04,
+ HCP = 0x0d,
+ AZM = 0x10,
+ ALT = 0x11,
+ APP = 0x20,
+ GPS = 0xb0,
+ WiFi = 0xb5,
+ BAT = 0xb6,
+ CHG = 0xb7,
+ LIGHT = 0xbf
+};
+
+#define CAUX_DEFAULT_IP "1.2.3.4"
+#define CAUX_DEFAULT_PORT 2000
+
+void logBytes(unsigned char *buf, int n, const char *deviceName, uint32_t debugLevel);
+
+class AUXCommand
+{
+ public:
+ AUXCommand();
+ AUXCommand(const AUXBuffer &buf);
+ AUXCommand(AUXCommands command, AUXTargets source, AUXTargets destination, const AUXBuffer &data);
+ AUXCommand(AUXCommands command, AUXTargets source, AUXTargets destination);
+
+ ///////////////////////////////////////////////////////////////////////////////
+ /// Buffer Management
+ ///////////////////////////////////////////////////////////////////////////////
+ void fillBuf(AUXBuffer &buf);
+ void parseBuf(AUXBuffer buf);
+ void parseBuf(AUXBuffer buf, bool do_checksum);
+
+ ///////////////////////////////////////////////////////////////////////////////
+ /// Getters
+ ///////////////////////////////////////////////////////////////////////////////
+ const AUXTargets &source() const
+ {
+ return m_Source;
+ }
+ const AUXTargets &destination() const
+ {
+ return m_Destination;
+ }
+ const AUXBuffer &data() const
+ {
+ return m_Data;
+ }
+ AUXCommands command() const
+ {
+ return m_Command;
+ }
+ size_t dataSize() const
+ {
+ return m_Data.size();
+ }
+ const char * commandName() const
+ {
+ return commandName(m_Command);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ /// Set and Get data
+ ///////////////////////////////////////////////////////////////////////////////
+ /**
+ * @brief getData Parses data packet and convert it to a 32bit unsigned integer
+ * @param bytes How many bytes to interpret the data.
+ * @return
+ */
+ uint32_t getData();
+ void setData(uint32_t value, uint8_t bytes = 3);
+
+ ///////////////////////////////////////////////////////////////////////////////
+ /// Check sum
+ ///////////////////////////////////////////////////////////////////////////////
+ uint8_t checksum(AUXBuffer buf);
+
+ ///////////////////////////////////////////////////////////////////////////////
+ /// Logging
+ ///////////////////////////////////////////////////////////////////////////////
+ const char * commandName(AUXCommands command) const;
+ const char * moduleName(AUXTargets n);
+ int responseDataSize();
+ void logResponse();
+ void logCommand();
+ static void setDebugInfo(const char *deviceName, uint8_t debugLevel);
+
+ static uint8_t DEBUG_LEVEL;
+ static char DEVICE_NAME[64];
+
+ private:
+ uint8_t len {0};
+ bool valid {false};
+
+ AUXCommands m_Command;
+ AUXTargets m_Source, m_Destination;
+ AUXBuffer m_Data;
+
+
+
+};
diff --git a/indi-celestronaux/celestronaux.cpp b/indi-celestronaux/celestronaux.cpp
new file mode 100644
index 0000000..ad8afe9
--- /dev/null
+++ b/indi-celestronaux/celestronaux.cpp
@@ -0,0 +1,2907 @@
+/*
+ Celestron Aux Mount Driver.
+
+ Copyright (C) 2020 Paweł T. Jochym
+ Copyright (C) 2020 Fabrizio Pollastri
+ Copyright (C) 2020-2022 Jasem Mutlaq
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ JM 2022.07.07: Added Wedge support.
+*/
+
+#include <algorithm>
+#include <math.h>
+#include <queue>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <thread>
+#include <chrono>
+
+#include <alignment/DriverCommon.h>
+#include "celestronaux.h"
+#include "config.h"
+
+#define DEBUG_PID
+
+using namespace INDI::AlignmentSubsystem;
+
+static std::unique_ptr<CelestronAUX> telescope_caux(new CelestronAUX());
+
+double anglediff(double a, double b)
+{
+ // Signed angle difference
+ double d;
+ b = fmod(b, 360.0);
+ a = fmod(a, 360.0);
+ d = fmod(a - b + 360.0, 360.0);
+ if (d > 180)
+ d = 360.0 - d;
+ return std::abs(d) * ((a - b >= 0 && a - b <= 180) || (a - b <= -180 && a - b >= -360) ? 1 : -1);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+CelestronAUX::CelestronAUX()
+ : ScopeStatus(IDLE),
+ DBG_CAUX(INDI::Logger::getInstance().addDebugLevel("AUX", "CAUX")),
+ DBG_SERIAL(INDI::Logger::getInstance().addDebugLevel("Serial", "CSER"))
+{
+ setVersion(CAUX_VERSION_MAJOR, CAUX_VERSION_MINOR);
+ SetTelescopeCapability(TELESCOPE_CAN_PARK |
+ TELESCOPE_CAN_SYNC |
+ TELESCOPE_CAN_GOTO |
+ TELESCOPE_CAN_ABORT |
+ TELESCOPE_HAS_TIME |
+ TELESCOPE_HAS_LOCATION |
+ TELESCOPE_CAN_CONTROL_TRACK |
+ TELESCOPE_HAS_TRACK_MODE |
+ TELESCOPE_HAS_TRACK_RATE
+ , 8);
+
+ //Both communication available, Serial and network (tcp/ip).
+ setTelescopeConnection(CONNECTION_TCP | CONNECTION_SERIAL);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+CelestronAUX::~CelestronAUX()
+{
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::Handshake()
+{
+ LOGF_DEBUG("CAUX: connect %d (%s)", PortFD, (getActiveConnection() == serialConnection) ? "serial" : "net");
+ if (PortFD > 0)
+ {
+ if (getActiveConnection() == serialConnection)
+ {
+ if (PortTypeSP[PORT_AUX_PC].getState() == ISS_ON)
+ {
+ serialConnection->setDefaultBaudRate(Connection::Serial::B_19200);
+ if (!tty_set_speed(B19200))
+ return false;
+ m_IsRTSCTS = detectRTSCTS();
+ }
+ else
+ {
+ serialConnection->setDefaultBaudRate(Connection::Serial::B_9600);
+ if (!tty_set_speed(B9600))
+ {
+ LOG_ERROR("Cannot set serial speed to 9600 baud.");
+ return false;
+ }
+
+ // wait for speed to settle
+ std::this_thread::sleep_for(std::chrono::milliseconds(200));
+
+ LOG_INFO("Setting serial speed to 9600 baud.");
+
+ // detect if connectd to HC port or to mount USB port
+ // ask for HC version
+ char version[10];
+ if ((m_isHandController = detectHC(version, 10)))
+ LOGF_INFO("Detected Hand Controller (v%s) serial connection.", version);
+ else
+ LOG_INFO("Detected Mount USB serial connection.");
+ }
+ }
+ else
+ std::this_thread::sleep_for(std::chrono::milliseconds(500));
+
+ // read firmware version, if read ok, detected scope
+ LOG_DEBUG("Communicating with mount motor controllers...");
+ if (getVersion(AZM) && getVersion(ALT))
+ {
+ LOG_INFO("Got response from target ALT or AZM.");
+ }
+ else
+ {
+ LOG_ERROR("Got no response from target ALT or AZM.");
+ LOG_ERROR("Cannot continue without connection to motor controllers.");
+ return false;
+ }
+
+ LOG_DEBUG("Connection ready. Starting Processing.");
+
+ // set mount type to alignment subsystem
+ //SetApproximateMountAlignmentFromMountType(static_cast<MountType>(MountTypeSP.findOnSwitchIndex()));
+ // tell the alignment math plugin to reinitialise
+ Initialise(this);
+
+ // update cordwrap position at each init of the alignment subsystem
+ if (isConnected())
+ syncCoordWrapPosition();
+
+ return true;
+ }
+ else
+ {
+ return false ;
+ }
+
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::Disconnect()
+{
+ Abort();
+ return INDI::Telescope::Disconnect();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+const char *CelestronAUX::getDefaultName()
+{
+ return "Celestron AUX";
+}
+
+/////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////
+void CelestronAUX::ISGetProperties(const char *dev)
+{
+ INDI::Telescope::ISGetProperties(dev);
+ defineProperty(&PortTypeSP);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::initProperties()
+{
+ INDI::Telescope::initProperties();
+ setDriverInterface(getDriverInterface() | GUIDER_INTERFACE);
+
+ /////////////////////////////////////////////////////////////////////////////////////
+ /// Main Control Tab
+ /////////////////////////////////////////////////////////////////////////////////////
+ // Mount type
+ int configMountType = ALTAZ;
+ IUGetConfigOnSwitchIndex(getDeviceName(), "MOUNT_TYPE", &configMountType);
+
+ // Detect Equatorial Mounts
+ if (strstr(getDeviceName(), "CGX") ||
+ strstr(getDeviceName(), "CGEM") ||
+ strstr(getDeviceName(), "Advanced VX") ||
+ strstr(getDeviceName(), "Wedge"))
+ {
+ // Force equatorial for such mounts
+ configMountType = EQUATORIAL;
+ m_IsWedge = (strstr(getDeviceName(), "Wedge") != nullptr);
+ }
+
+ if (configMountType == EQUATORIAL)
+ SetApproximateMountAlignment(m_Location.latitude >= 0 ? NORTH_CELESTIAL_POLE : SOUTH_CELESTIAL_POLE);
+ else
+ SetApproximateMountAlignment(ZENITH);
+
+ MountTypeSP[EQUATORIAL].fill("EQUATORIAL", "Equatorial", configMountType == EQUATORIAL ? ISS_ON : ISS_OFF);
+ MountTypeSP[ALTAZ].fill("ALTAZ", "AltAz", configMountType == ALTAZ ? ISS_ON : ISS_OFF);
+ MountTypeSP.fill(getDeviceName(), "MOUNT_TYPE", "Mount Type", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
+
+ // Track Modes for Equatorial Mount
+ if (MountTypeSP[EQUATORIAL].getState() == ISS_ON)
+ {
+ AddTrackMode("TRACK_SIDEREAL", "Sidereal", true);
+ AddTrackMode("TRACK_SOLAR", "Solar");
+ AddTrackMode("TRACK_LUNAR", "Lunar");
+ AddTrackMode("TRACK_CUSTOM", "Custom");
+
+ SetTelescopeCapability(GetTelescopeCapability() | TELESCOPE_HAS_PIER_SIDE, 8);
+ }
+
+ // Horizontal Coords
+ HorizontalCoordsNP[AXIS_AZ].fill("AZ", "Az D:M:S", "%10.6m", 0.0, 360.0, 0.0, 0);
+ HorizontalCoordsNP[AXIS_ALT].fill("ALT", "Alt D:M:S", "%10.6m", -90., 90.0, 0.0, 0);
+ HorizontalCoordsNP.fill(getDeviceName(), "HORIZONTAL_COORD", "Horizontal Coord", MAIN_CONTROL_TAB, IP_RW, 0, IPS_IDLE);
+
+ // Homing
+ HomeSP[HOME_AXIS1].fill("AXIS1", "AZ/RA", ISS_OFF);
+ HomeSP[HOME_AXIS2].fill("AXIS2", "AL/DE", ISS_OFF);
+ HomeSP[HOME_ALL].fill("ALL", "All", ISS_OFF);
+ HomeSP.fill(getDeviceName(), "HOME", "Home", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
+
+ /////////////////////////////////////////////////////////////////////////////////////
+ /// Cord Wrap Tab
+ /////////////////////////////////////////////////////////////////////////////////////
+
+ // Cord wrap Toggle
+ CordWrapToggleSP[INDI_ENABLED].fill("INDI_ENABLED", "Enabled", ISS_OFF);
+ CordWrapToggleSP[INDI_DISABLED].fill("INDI_DISABLED", "Disabled", ISS_ON);
+ CordWrapToggleSP.fill(getDeviceName(), "CORDWRAP", "Cord Wrap", CORDWRAP_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
+
+ // Cord Wrap Position
+ CordWrapPositionSP[CORDWRAP_N].fill("CORDWRAP_N", "North", ISS_ON);
+ CordWrapPositionSP[CORDWRAP_E].fill("CORDWRAP_E", "East", ISS_OFF);
+ CordWrapPositionSP[CORDWRAP_S].fill("CORDWRAP_S", "South", ISS_OFF);
+ CordWrapPositionSP[CORDWRAP_W].fill("CORDWRAP_W", "West", ISS_OFF);
+ CordWrapPositionSP.fill(getDeviceName(), "CORDWRAP_POS", "CW Position", CORDWRAP_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
+
+ // Cord Wrap / Park Base
+ CordWrapBaseSP[CW_BASE_ENC].fill("CW_BASE_ENC", "Encoders", ISS_ON);
+ CordWrapBaseSP[CW_BASE_SKY].fill("CW_BASE_SKY", "Alignment positions", ISS_OFF);
+ CordWrapBaseSP.fill(getDeviceName(), "CW_BASE", "CW Position Base", CORDWRAP_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
+
+ /////////////////////////////////////////////////////////////////////////////////////
+ /// Options
+ /////////////////////////////////////////////////////////////////////////////////////
+ // GPS Emulation
+ GPSEmuSP[GPSEMU_OFF].fill("GPSEMU_OFF", "OFF", ISS_OFF);
+ GPSEmuSP[GPSEMU_ON].fill("GPSEMU_ON", "ON", ISS_ON);
+ GPSEmuSP.fill(getDeviceName(), "GPSEMU", "GPS Emu", OPTIONS_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
+
+ /////////////////////////////////////////////////////////////////////////////////////
+ /// Guide Tab
+ /////////////////////////////////////////////////////////////////////////////////////
+
+ // Guide Properties
+ initGuiderProperties(getDeviceName(), GUIDE_TAB);
+ // Rate rate
+ GuideRateNP[AXIS_AZ].fill("GUIDE_RATE_WE", "W/E Rate", "%.f", 0, 1, .1, 0.5);
+ GuideRateNP[AXIS_ALT].fill("GUIDE_RATE_NS", "N/S Rate", "%.f", 0, 1, .1, 0.5);
+ GuideRateNP.fill(getDeviceName(), "GUIDE_RATE", "Guiding Rate", GUIDE_TAB, IP_RW, 0, IPS_IDLE);
+
+ setDriverInterface(getDriverInterface() | GUIDER_INTERFACE);
+
+ /////////////////////////////////////////////////////////////////////////////////////
+ /// Connection
+ /////////////////////////////////////////////////////////////////////////////////////
+ IUGetConfigOnSwitchIndex(getDeviceName(), "PORT_TYPE", &m_ConfigPortType);
+ PortTypeSP[PORT_AUX_PC].fill("PORT_AUX_PC", "AUX/PC", m_ConfigPortType == PORT_AUX_PC ? ISS_ON : ISS_OFF);
+ PortTypeSP[PORT_HC_USB].fill("PORT_HC_USB", "USB/HC", m_ConfigPortType == PORT_AUX_PC ? ISS_OFF : ISS_ON);
+ PortTypeSP.fill(getDeviceName(), "PORT_TYPE", "Port Type", CONNECTION_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
+ /////////////////////////////////////////////////////////////////////////////////////
+ /// Mount Information
+ /////////////////////////////////////////////////////////////////////////////////////
+
+ // Raw encoder values
+ EncoderNP[AXIS_AZ].fill("AXIS_AZ", "Axis 1", "%.f", 0, STEPS_PER_REVOLUTION, 0, 0);
+ EncoderNP[AXIS_ALT].fill("AXIS_ALT", "Axis 2", "%.f", 0, STEPS_PER_REVOLUTION, 0, 0);
+ EncoderNP.fill(getDeviceName(), "TELESCOPE_ENCODER_STEPS", "Encoders", MOUNTINFO_TAB, IP_RW, 60, IPS_IDLE);
+
+ // Encoder -> Angle values
+ AngleNP[AXIS_AZ].fill("AXIS_AZ", "Axis 1", "%.2f", 0, 360, 0, 0);
+ AngleNP[AXIS_ALT].fill("AXIS_ALT", "Axis 2", "%.2f", -90, 90, 0, 0);
+ AngleNP.fill(getDeviceName(), "TELESCOPE_ENCODER_ANGLES", "Angles", MOUNTINFO_TAB, IP_RO, 60, IPS_IDLE);
+
+ // PID Control
+ Axis1PIDNP[Propotional].fill("Propotional", "Propotional", "%.2f", 0, 500, 10, GAIN_STEPS);
+ Axis1PIDNP[Derivative].fill("Derivative", "Derivative", "%.2f", 0, 500, 10, 0);
+ Axis1PIDNP[Integral].fill("Integral", "Integral", "%.2f", 0, 500, 10, 0);
+ Axis1PIDNP.fill(getDeviceName(), "AXIS1_PID", "Axis1 PID", MOUNTINFO_TAB, IP_RW, 60, IPS_IDLE);
+
+ Axis2PIDNP[Propotional].fill("Propotional", "Propotional", "%.2f", 0, 500, 10, GAIN_STEPS);
+ Axis2PIDNP[Derivative].fill("Derivative", "Derivative", "%.2f", 0, 100, 10, 0);
+ Axis2PIDNP[Integral].fill("Integral", "Integral", "%.2f", 0, 100, 10, 1);
+ Axis2PIDNP.fill(getDeviceName(), "AXIS2_PID", "Axis2 PID", MOUNTINFO_TAB, IP_RW, 60, IPS_IDLE);
+
+ // Firmware Info
+ FirmwareTP[FW_HC].fill("HC version", "", nullptr);
+ FirmwareTP[FW_MB].fill("Mother Board version", "", nullptr);
+ FirmwareTP[FW_AZM].fill("Ra/AZM version", "", nullptr);
+ FirmwareTP[FW_ALT].fill("Dec/ALT version", "", nullptr);
+ FirmwareTP[FW_WiFi].fill("WiFi version", "", nullptr);
+ FirmwareTP[FW_BAT].fill("Battery version", "", nullptr);
+ FirmwareTP[FW_GPS].fill("GPS version", "", nullptr);
+ FirmwareTP.fill(getDeviceName(), "Firmware Info", "Firmware Info", MOUNTINFO_TAB, IP_RO, 0, IPS_IDLE);
+
+ // Gain Rate
+ // GainNP[AXIS_AZ].fill("AXIS_AZ", "Axis1", "%.f", -10000, 10000, 500, 0);
+ // GainNP[AXIS_ALT].fill("AXIS_ALT", "Axis2", "%.f", -10000, 10000, 500, 0);
+ // GainNP.fill(getDeviceName(), "TRACK_GAIN", "Gain", MAIN_CONTROL_TAB, IP_RW, 60, IPS_IDLE);
+ /////////////////////////////////////////////////////////////////////////////////////
+ /// Initial Configuration
+ /////////////////////////////////////////////////////////////////////////////////////
+
+ // Set Debug Information for AUX Commands
+ AUXCommand::setDebugInfo(getDeviceName(), DBG_CAUX);
+
+ // Add debug controls so we may debug driver if necessary
+ addDebugControl();
+
+ // Add alignment properties
+ InitAlignmentProperties(this);
+
+ // set alignment system be on the first time by default
+ getSwitch("ALIGNMENT_SUBSYSTEM_ACTIVE")->sp[0].s = ISS_ON;
+
+ // Default connection options
+ serialConnection->setDefaultBaudRate(Connection::Serial::B_19200);
+ tcpConnection->setDefaultHost(CAUX_DEFAULT_IP);
+ tcpConnection->setDefaultPort(CAUX_DEFAULT_PORT);
+
+ SetParkDataType(PARK_AZ_ALT_ENCODER);
+
+ // to update cordwrap pos at each init of alignment subsystem
+ IDSnoopDevice(getDeviceName(), "ALIGNMENT_SUBSYSTEM_MATH_PLUGIN_INITIALISE");
+
+ // JM 2020-09-23 Make it easier for users to connect by default via WiFi if they
+ // selected the Celestron WiFi labeled driver.
+ if (strstr(getDeviceName(), "WiFi"))
+ setActiveConnection(tcpConnection);
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void CelestronAUX::formatVersionString(char *s, int n, uint8_t *verBuf)
+{
+ if (verBuf[0] == 0 && verBuf[1] == 0 && verBuf[2] == 0 && verBuf[3] == 0)
+ snprintf(s, n, "Unknown");
+ else
+ snprintf(s, n, "%d.%02d.%d", verBuf[0], verBuf[1], verBuf[2] * 256 + verBuf[3]);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::updateProperties()
+{
+ INDI::Telescope::updateProperties();
+
+ if (isConnected())
+ {
+ // Main Control Panel
+ defineProperty(&MountTypeSP);
+ //defineProperty(&GainNP);
+ if (MountTypeSP[ALTAZ].getState() == ISS_ON)
+ defineProperty(&HorizontalCoordsNP);
+ defineProperty(&HomeSP);
+
+ // Guide
+ defineProperty(&GuideNSNP);
+ defineProperty(&GuideWENP);
+ defineProperty(&GuideRateNP);
+
+ // Cord wrap Enabled?
+ if (MountTypeSP[ALTAZ].getState() == ISS_ON)
+ {
+ getCordWrapEnabled();
+ CordWrapToggleSP[INDI_ENABLED].s = m_CordWrapActive ? ISS_ON : ISS_OFF;
+ CordWrapToggleSP[INDI_DISABLED].s = m_CordWrapActive ? ISS_OFF : ISS_ON;
+ defineProperty(&CordWrapToggleSP);
+
+ // Cord wrap Position?
+ getCordWrapPosition();
+ double cordWrapAngle = range360(m_CordWrapPosition / STEPS_PER_DEGREE);
+ LOGF_INFO("Cord Wrap position angle %.2f", cordWrapAngle);
+ CordWrapPositionSP[static_cast<int>(std::floor(cordWrapAngle / 90))].s = ISS_ON;
+ defineProperty(&CordWrapPositionSP);
+ defineProperty(&CordWrapBaseSP);
+ }
+
+ defineProperty(&GPSEmuSP);
+
+ // Encoders
+ defineProperty(&EncoderNP);
+ defineProperty(&AngleNP);
+ if (MountTypeSP[ALTAZ].getState() == ISS_ON)
+ {
+ defineProperty(&Axis1PIDNP);
+ defineProperty(&Axis2PIDNP);
+ }
+
+ getVersions();
+ // display firmware versions
+ char fwText[16] = {0};
+ formatVersionString(fwText, 10, m_HCVersion);
+ FirmwareTP[FW_HC].setText(fwText);
+ formatVersionString(fwText, 10, m_MainBoardVersion);
+ FirmwareTP[FW_MB].setText(fwText);
+ formatVersionString(fwText, 10, m_AzimuthVersion);
+ FirmwareTP[FW_AZM].setText(fwText);
+ formatVersionString(fwText, 10, m_AltitudeVersion);
+ FirmwareTP[FW_ALT].setText(fwText);
+ formatVersionString(fwText, 10, m_WiFiVersion);
+ FirmwareTP[FW_WiFi].setText(fwText);
+ formatVersionString(fwText, 10, m_BATVersion);
+ FirmwareTP[FW_BAT].setText(fwText);
+ formatVersionString(fwText, 10, m_GPSVersion);
+ FirmwareTP[FW_GPS].setText(fwText);
+ defineProperty(&FirmwareTP);
+
+ if (InitPark())
+ {
+ // If loading parking data is successful, we just set the default parking values.
+ SetAxis1ParkDefault(0);
+ SetAxis2ParkDefault(0);
+ }
+ else
+ {
+ // Otherwise, we set all parking data to default in case no parking data is found.
+ SetAxis1Park(0);
+ SetAxis2Park(0);
+ SetAxis1ParkDefault(0);
+ SetAxis2ParkDefault(0);
+ }
+ }
+ else
+ {
+ deleteProperty(MountTypeSP.getName());
+ //deleteProperty(GainNP.getName());
+ if (MountTypeSP[ALTAZ].getState() == ISS_ON)
+ deleteProperty(HorizontalCoordsNP.getName());
+ deleteProperty(HomeSP.getName());
+
+ deleteProperty(GuideNSNP.name);
+ deleteProperty(GuideWENP.name);
+ deleteProperty(GuideRateNP.getName());
+
+ if (MountTypeSP[ALTAZ].getState() == ISS_ON)
+ {
+ deleteProperty(CordWrapToggleSP.getName());
+ deleteProperty(CordWrapPositionSP.getName());
+ deleteProperty(CordWrapBaseSP.getName());
+ }
+
+ deleteProperty(GPSEmuSP.getName());
+
+ deleteProperty(EncoderNP.getName());
+ deleteProperty(AngleNP.getName());
+
+ if (MountTypeSP[ALTAZ].getState() == ISS_ON)
+ {
+ deleteProperty(Axis1PIDNP.getName());
+ deleteProperty(Axis2PIDNP.getName());
+ }
+
+ deleteProperty(FirmwareTP.getName());
+ }
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::saveConfigItems(FILE *fp)
+{
+ INDI::Telescope::saveConfigItems(fp);
+ SaveAlignmentConfigProperties(fp);
+
+ IUSaveConfigSwitch(fp, &MountTypeSP);
+ IUSaveConfigSwitch(fp, &PortTypeSP);
+ IUSaveConfigSwitch(fp, &CordWrapToggleSP);
+ IUSaveConfigSwitch(fp, &CordWrapPositionSP);
+ IUSaveConfigSwitch(fp, &CordWrapBaseSP);
+ IUSaveConfigSwitch(fp, &GPSEmuSP);
+
+ if (MountTypeSP[ALTAZ].getState() == ISS_ON)
+ {
+ IUSaveConfigNumber(fp, &Axis1PIDNP);
+ IUSaveConfigNumber(fp, &Axis2PIDNP);
+ }
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::ISSnoopDevice(XMLEle *root)
+{
+ const char *propName = findXMLAttValu(root, "name");
+
+ // update cordwrap position at each init of the alignment subsystem
+ if (!strcmp(propName, "ALIGNMENT_SUBSYSTEM_MATH_PLUGIN_INITIALISE") && telescope_caux->isConnected())
+ telescope_caux->syncCoordWrapPosition();
+
+ return Telescope::ISSnoopDevice(root);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[],
+ char *formats[], char *names[], int n)
+{
+ if (strcmp(dev, getDeviceName()) == 0)
+ {
+ // Process alignment properties
+ ProcessAlignmentBLOBProperties(this, name, sizes, blobsizes, blobs, formats, names, n);
+ }
+ // Pass it up the chain
+ return INDI::Telescope::ISNewBLOB(dev, name, sizes, blobsizes, blobs, formats, names, n);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
+{
+ if (strcmp(dev, getDeviceName()) == 0)
+ {
+ // Gain
+ // if (GainNP.isNameMatch(name))
+ // {
+ // GainNP.update(values, names, n);
+ // GainNP.setState(IPS_OK);
+ // GainNP.apply();
+ // return true;
+ // }
+
+ // Axis1 PID
+ if (Axis1PIDNP.isNameMatch(name))
+ {
+ Axis1PIDNP.update(values, names, n);
+ Axis1PIDNP.setState(IPS_OK);
+ Axis1PIDNP.apply();
+ saveConfig(true, Axis1PIDNP.getName());
+ return true;
+ }
+
+ // Axis2 PID
+ if (Axis2PIDNP.isNameMatch(name))
+ {
+ Axis2PIDNP.update(values, names, n);
+ Axis2PIDNP.setState(IPS_OK);
+ Axis2PIDNP.apply();
+ saveConfig(true, Axis2PIDNP.getName());
+ return true;
+ }
+
+ // Horizontal Coords
+ if (HorizontalCoordsNP.isNameMatch(name))
+ {
+ double az = 0, alt = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ if (HorizontalCoordsNP[AXIS_AZ].isNameMatch(names[i]))
+ az = values[i];
+ else if (HorizontalCoordsNP[AXIS_ALT].isNameMatch(names[i]))
+ alt = values[i];
+ }
+
+ // Convert Celestial Alt-Az to Equatorial
+ INDI::IHorizontalCoordinates celestialAzAlt = {az, alt};
+ INDI::IEquatorialCoordinates celestialEquatorial;
+ INDI::HorizontalToEquatorial(&celestialAzAlt, &m_Location, ln_get_julian_from_sys(), &celestialEquatorial);
+
+ if (Goto(celestialEquatorial.rightascension, celestialEquatorial.declination))
+ {
+ // State already set in Goto so no need to set state here
+ char azStr[32], alStr[32];
+ fs_sexa(azStr, celestialAzAlt.azimuth, 2, 3600);
+ fs_sexa(alStr, celestialAzAlt.altitude, 2, 3600);
+ LOGF_INFO("Slewing to AZ: %s AL: %s", azStr, alStr);
+ }
+ else
+ {
+ HorizontalCoordsNP.setState(IPS_ALERT);
+ HorizontalCoordsNP.apply();
+ }
+
+ return true;
+ }
+
+ // Guide Rate
+ if (GuideRateNP.isNameMatch(name))
+ {
+ GuideRateNP.update(values, names, n);
+ GuideRateNP.setState(IPS_OK);
+ GuideRateNP.apply();
+ return true;
+ }
+
+ // Encoder Values
+ if (EncoderNP.isNameMatch(name))
+ {
+ uint32_t axisSteps1 {0}, axisSteps2 {0};
+ for (int i = 0; i < n; i++)
+ {
+ if (!strcmp(names[i], EncoderNP[AXIS_AZ].getName()))
+ axisSteps1 = values[i];
+ else if (!strcmp(names[i], EncoderNP[AXIS_ALT].getName()))
+ axisSteps2 = values[i];
+ }
+
+ slewTo(AXIS_AZ, axisSteps1);
+ slewTo(AXIS_ALT, axisSteps2);
+ TrackState = SCOPE_SLEWING;
+ EncoderNP.setState(IPS_OK);
+ EncoderNP.apply();
+ return true;
+ }
+
+ // Process Guide Properties
+ processGuiderProperties(name, values, names, n);
+
+ // Process Alignment Properties
+ ProcessAlignmentNumberProperties(this, name, values, names, n);
+ }
+
+ return INDI::Telescope::ISNewNumber(dev, name, values, names, n);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
+{
+ if (strcmp(dev, getDeviceName()) == 0)
+ {
+ // mount type
+ if (MountTypeSP.isNameMatch(name))
+ {
+ // Get current type
+ MountType currentMountType = IUFindOnSwitchIndex(&MountTypeSP) ? ALTAZ : EQUATORIAL;
+
+ MountTypeSP.update(states, names, n);
+ MountTypeSP.setState(IPS_OK);
+ MountTypeSP.apply();
+
+ // Get target type
+ MountType targetMountType = IUFindOnSwitchIndex(&MountTypeSP) ? ALTAZ : EQUATORIAL;
+
+ // If different then update
+ if (currentMountType != targetMountType)
+ {
+ LOG_INFO("Mount type updated. You must restart the driver for changes to take effect.");
+ saveConfig(true, MountTypeSP.getName());
+ }
+
+ return true;
+ }
+
+ // Port Type
+ if (PortTypeSP.isNameMatch(name))
+ {
+ PortTypeSP.update(states, names, n);
+ PortTypeSP.setState(IPS_OK);
+ PortTypeSP.apply();
+ if (m_ConfigPortType != IUFindOnSwitchIndex(&PortTypeSP))
+ {
+ m_ConfigPortType = IUFindOnSwitchIndex(&PortTypeSP);
+ saveConfig(true, PortTypeSP.getName());
+ }
+ return true;
+ }
+
+ // Cord Wrap Toggle
+ if (CordWrapToggleSP.isNameMatch(name))
+ {
+ CordWrapToggleSP.update(states, names, n);
+ const bool toEnable = CordWrapToggleSP[INDI_ENABLED].s == ISS_ON;
+ LOGF_INFO("Cord Wrap is %s.", toEnable ? "enabled" : "disabled");
+ setCordWrapEnabled(toEnable);
+ getCordWrapEnabled();
+ CordWrapToggleSP.setState(IPS_OK);
+ CordWrapToggleSP.apply();
+
+ return true;
+ }
+
+ // Cord Wrap Position
+ if (CordWrapPositionSP.isNameMatch(name))
+ {
+ CordWrapPositionSP.update(states, names, n);
+ LOGF_DEBUG("Cord Wrap Position is %s.", CordWrapPositionSP.findOnSwitch()->getLabel());
+ CordWrapPositionSP.setState(IPS_OK);
+ CordWrapPositionSP.apply();
+ switch (CordWrapPositionSP.findOnSwitchIndex())
+ {
+ case CORDWRAP_N:
+ m_RequestedCordwrapPos = 0;
+ break;
+ case CORDWRAP_E:
+ m_RequestedCordwrapPos = 90;
+ break;
+ case CORDWRAP_S:
+ m_RequestedCordwrapPos = 180;
+ break;
+ case CORDWRAP_W:
+ m_RequestedCordwrapPos = 270;
+ break;
+ default:
+ m_RequestedCordwrapPos = 0;
+ break;
+ }
+
+ syncCoordWrapPosition();
+ return true;
+ }
+
+ // Park position base
+ if (CordWrapBaseSP.isNameMatch(name))
+ {
+ CordWrapBaseSP.update(states, names, n);
+ CordWrapBaseSP.setState(IPS_OK);
+ CordWrapBaseSP.apply();
+ return true;
+ }
+
+ // GPS Emulation
+ if (GPSEmuSP.isNameMatch(name))
+ {
+ GPSEmuSP.update(states, names, n);
+ GPSEmuSP.setState(IPS_OK);
+ GPSEmuSP.apply();
+ m_GPSEmulation = GPSEmuSP[GPSEMU_ON].s == ISS_ON;
+ return true;
+ }
+
+ // Homing/Leveling
+ if (HomeSP.isNameMatch(name))
+ {
+ HomeSP.update(states, names, n);
+ bool rc = false;
+ switch (HomeSP.findOnSwitchIndex())
+ {
+ case HOME_AXIS1:
+ rc = goHome(AXIS_AZ);
+ break;
+ case HOME_AXIS2:
+ rc = goHome(AXIS_ALT);
+ break;
+ case HOME_ALL:
+ rc = goHome(AXIS_AZ) && goHome(AXIS_ALT);
+ break;
+ }
+
+ if (rc)
+ {
+ HomeSP.setState(IPS_BUSY);
+ LOG_INFO("Homing in progress...");
+ }
+ else
+ {
+ HomeSP.reset();
+ HomeSP.setState(IPS_ALERT);
+ LOG_ERROR("Failed to start homing.");
+ }
+
+ HomeSP.apply();
+ return true;
+ }
+
+ // Process alignment properties
+ ProcessAlignmentSwitchProperties(this, name, states, names, n);
+ }
+
+ return INDI::Telescope::ISNewSwitch(dev, name, states, names, n);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
+{
+ if (!strcmp(dev, getDeviceName()))
+ ProcessAlignmentTextProperties(this, name, texts, names, n);
+
+ return INDI::Telescope::ISNewText(dev, name, texts, names, n);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::Park()
+{
+ slewTo(AXIS_AZ, GetAxis1Park());
+ slewTo(AXIS_ALT, GetAxis2Park());
+ TrackState = SCOPE_PARKING;
+ LOG_INFO("Parking in progress...");
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::UnPark()
+{
+ SetParked(false);
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+INDI::IHorizontalCoordinates CelestronAUX::AltAzFromRaDec(double ra, double dec, double ts)
+{
+ // Call the alignment subsystem to translate the celestial reference frame coordinate
+ // into a telescope reference frame coordinate
+ TelescopeDirectionVector TDV;
+ INDI::IHorizontalCoordinates AltAz;
+
+ if (TransformCelestialToTelescope(ra, dec, ts, TDV))
+ // The alignment subsystem has successfully transformed my coordinate
+ AltitudeAzimuthFromTelescopeDirectionVector(TDV, AltAz);
+ else
+ {
+ LOG_DEBUG("AltAzFromRaDec - TransformCelestialToTelescope failed");
+
+ INDI::IEquatorialCoordinates EquatorialCoordinates { ra, dec };
+ INDI::EquatorialToHorizontal(&EquatorialCoordinates, &m_Location, ln_get_julian_from_sys(), &AltAz);
+ TDV = TelescopeDirectionVectorFromAltitudeAzimuth(AltAz);
+ switch (GetApproximateMountAlignment())
+ {
+ case ZENITH:
+ break;
+
+ case NORTH_CELESTIAL_POLE:
+ // Rotate the TDV coordinate system clockwise (negative) around the y axis by 90 minus
+ // the (positive)observatory latitude. The vector itself is rotated anticlockwise
+ TDV.RotateAroundY(m_Location.latitude - 90.0);
+ break;
+
+ case SOUTH_CELESTIAL_POLE:
+ // Rotate the TDV coordinate system anticlockwise (positive) around the y axis by 90 plus
+ // the (negative)observatory latitude. The vector itself is rotated clockwise
+ TDV.RotateAroundY(m_Location.latitude + 90.0);
+ break;
+ }
+ AltitudeAzimuthFromTelescopeDirectionVector(TDV, AltAz);
+ }
+
+ return AltAz;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+double CelestronAUX::getNorthAz()
+{
+ INDI::IGeographicCoordinates location;
+ double northAz;
+ if (!GetDatabaseReferencePosition(location))
+ northAz = 0.;
+ else
+ northAz = DegreesToAzimuth(AltAzFromRaDec(get_local_sidereal_time(m_Location.longitude), 0., 0.).azimuth);
+ LOGF_DEBUG("North Azimuth = %lf", northAz);
+ return northAz;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void CelestronAUX::syncCoordWrapPosition()
+{
+ // No coord wrap for equatorial mounts.
+ if (MountTypeSP[EQUATORIAL].getState() == ISS_ON)
+ return;
+
+ uint32_t coordWrapPosition = 0;
+ if (CordWrapBaseSP[CW_BASE_SKY].s == ISS_ON)
+ coordWrapPosition = range360(m_RequestedCordwrapPos + getNorthAz()) * STEPS_PER_DEGREE;
+ else
+ coordWrapPosition = range360(m_RequestedCordwrapPos) * STEPS_PER_DEGREE;
+ setCordWrapPosition(coordWrapPosition);
+ getCordWrapPosition();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command)
+{
+ int rate = IUFindOnSwitchIndex(&SlewRateSP) + 1;
+ m_AxisDirection[AXIS_ALT] = (dir == DIRECTION_NORTH) ? FORWARD : REVERSE;
+ m_AxisStatus[AXIS_ALT] = (command == MOTION_START) ? SLEWING : STOPPED;
+ ScopeStatus = SLEWING_MANUAL;
+ TrackState = SCOPE_SLEWING;
+ if (command == MOTION_START)
+ {
+ return slewByRate(AXIS_ALT, ((m_AxisDirection[AXIS_ALT] == FORWARD) ? 1 : -1) * rate);
+ }
+ else
+ return stopAxis(AXIS_ALT);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command)
+{
+ int rate = IUFindOnSwitchIndex(&SlewRateSP) + 1;
+ if (isNorthHemisphere())
+ m_AxisDirection[AXIS_AZ] = (dir == DIRECTION_WEST) ? FORWARD : REVERSE;
+ else
+ m_AxisDirection[AXIS_AZ] = (dir == DIRECTION_WEST) ? REVERSE : FORWARD;
+ m_AxisStatus[AXIS_AZ] = (command == MOTION_START) ? SLEWING : STOPPED;
+ ScopeStatus = SLEWING_MANUAL;
+ TrackState = SCOPE_SLEWING;
+ if (command == MOTION_START)
+ {
+ return slewByRate(AXIS_AZ, ((m_AxisDirection[AXIS_AZ] == FORWARD) ? 1 : -1) * rate);
+ }
+ else
+ return stopAxis(AXIS_AZ);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+IPState CelestronAUX::GuideNorth(uint32_t ms)
+{
+ int8_t rate = static_cast<int8_t>(GuideRateNP[AXIS_ALT].getValue() * 100);
+ guidePulse(AXIS_DE, ms, rate);
+ return IPS_BUSY;
+}
+
+IPState CelestronAUX::GuideSouth(uint32_t ms)
+{
+ int8_t rate = static_cast<int8_t>(GuideRateNP[AXIS_ALT].getValue() * 100);
+ guidePulse(AXIS_DE, ms, -rate);
+ return IPS_BUSY;
+}
+
+IPState CelestronAUX::GuideEast(uint32_t ms)
+{
+ int8_t rate = static_cast<int8_t>(GuideRateNP[AXIS_AZ].getValue() * 100);
+ guidePulse(AXIS_RA, ms, -rate);
+ return IPS_BUSY;
+}
+
+IPState CelestronAUX::GuideWest(uint32_t ms)
+{
+ int8_t rate = static_cast<int8_t>(GuideRateNP[AXIS_AZ].getValue() * 100);
+ guidePulse(AXIS_RA, ms, rate);
+ return IPS_BUSY;
+}
+
+bool CelestronAUX::guidePulse(INDI_EQ_AXIS axis, uint32_t ms, int8_t rate)
+{
+ // For Equatorial mounts, use regular guiding.
+ if (MountTypeSP[EQUATORIAL].getState() == ISS_ON)
+ {
+ uint8_t ticks = std::min(255u, ms / 10);
+ AUXBuffer data(2);
+ data[0] = rate;
+ data[1] = ticks;
+ AUXCommand cmd(MC_AUX_GUIDE, APP, axis == AXIS_DE ? ALT : AZM, data);
+ return sendAUXCommand(cmd);
+ }
+ // For Alt-Az mounts in tracking state, add to guide delta
+ else if (TrackState == SCOPE_TRACKING)
+ {
+ double arcsecs = TRACKRATE_SIDEREAL * ms / 1000.0 * rate / 100.;
+ double steps = arcsecs * STEPS_PER_ARCSEC;
+ m_GuideOffset[axis] += steps;
+ }
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void CelestronAUX::resetTracking()
+{
+ // getEncoder(AXIS_AZ);
+ // getEncoder(AXIS_ALT);
+ // m_TrackStartSteps[AXIS_AZ] = EncoderNP[AXIS_AZ].getValue();
+ // m_TrackStartSteps[AXIS_ALT] = EncoderNP[AXIS_ALT].getValue();
+
+ m_Controllers[AXIS_AZ].reset(new PID(1, 100000, -100000, Axis1PIDNP[Propotional].getValue(),
+ Axis1PIDNP[Derivative].getValue(), Axis1PIDNP[Integral].getValue()));
+ m_Controllers[AXIS_AZ]->setIntegratorLimits(-2000, 2000);
+ m_Controllers[AXIS_ALT].reset(new PID(1, 100000, -100000, Axis2PIDNP[Propotional].getValue(),
+ Axis2PIDNP[Derivative].getValue(), Axis2PIDNP[Integral].getValue()));
+ m_Controllers[AXIS_ALT]->setIntegratorLimits(-2000, 2000);
+ m_TrackingElapsedTimer.restart();
+ m_GuideOffset[AXIS_AZ] = m_GuideOffset[AXIS_ALT] = 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::isTrackingRequested()
+{
+ return (ISS_ON == IUFindSwitch(&CoordSP, "TRACK")->s);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::ReadScopeStatus()
+{
+ if (!isConnected())
+ return false;
+
+ if (!getStatus(AXIS_AZ))
+ return false;
+ if (!getStatus(AXIS_ALT))
+ return false;
+
+ double axis1 = EncoderNP[AXIS_AZ].getValue();
+ double axis2 = EncoderNP[AXIS_ALT].getValue();
+
+ if (!getEncoder(AXIS_AZ))
+ {
+ if (EncoderNP.getState() != IPS_ALERT)
+ {
+ EncoderNP.setState(IPS_ALERT);
+ AngleNP.setState(IPS_ALERT);
+ EncoderNP.apply();
+ AngleNP.apply();
+ }
+ return false;
+ }
+ if (!getEncoder(AXIS_ALT))
+ {
+ if (EncoderNP.getState() != IPS_ALERT)
+ {
+ EncoderNP.setState(IPS_ALERT);
+ AngleNP.setState(IPS_ALERT);
+ EncoderNP.apply();
+ AngleNP.apply();
+ }
+ return false;
+ }
+
+ // Mount Alt-Az Coords
+ if (MountTypeSP[ALTAZ].getState() == ISS_ON)
+ {
+ EncodersToAltAz(m_MountCurrentAltAz);
+ }
+ // Mount RA/DE Coords.
+ else
+ {
+ TelescopePierSide pierSide = currentPierSide;
+ EncodersToRADE(m_MountCurrentRADE, pierSide);
+ setPierSide(pierSide);
+ }
+
+ // Send to client if updated
+ if (std::abs(axis1 - EncoderNP[AXIS_AZ].getValue()) > 1 || std::abs(axis2 - EncoderNP[AXIS_ALT].getValue()) > 1)
+ {
+ EncoderNP.setState(IPS_OK);
+ EncoderNP.apply();
+ if (MountTypeSP[ALTAZ].getState() == ISS_ON)
+ {
+ AngleNP[AXIS_AZ].setValue(m_MountCurrentAltAz.azimuth);
+ AngleNP[AXIS_ALT].setValue(m_MountCurrentAltAz.altitude);
+ }
+ else
+ {
+ AngleNP[AXIS_RA].setValue(range360(range24(get_local_sidereal_time(m_Location.longitude) -
+ m_MountCurrentRADE.rightascension) * 15));
+ AngleNP[AXIS_DE].setValue(rangeDec(m_MountCurrentRADE.declination));
+ }
+ AngleNP.setState(IPS_OK);
+ AngleNP.apply();
+ }
+
+ // Get sky coordinates
+ mountToSkyCoords();
+ char RAStr[32] = {0}, DecStr[32] = {0};
+ fs_sexa(RAStr, m_SkyCurrentRADE.rightascension, 2, 3600);
+ fs_sexa(DecStr, m_SkyCurrentRADE.declination, 2, 3600);
+
+ INDI::IHorizontalCoordinates celestialAzAlt;
+ INDI::EquatorialToHorizontal(&m_SkyCurrentRADE, &m_Location, ln_get_julian_from_sys(), &celestialAzAlt);
+
+ char AzStr[32] = {0}, AltStr[32] = {0}, HAStr[32] = {0};
+ fs_sexa(AzStr, celestialAzAlt.azimuth, 2, 3600);
+ fs_sexa(AltStr, celestialAzAlt.altitude, 2, 3600);
+ double HA = rangeHA(ln_get_julian_from_sys() - m_SkyCurrentRADE.rightascension);
+ fs_sexa(HAStr, HA, 2, 3600);
+ DEBUGF(INDI::AlignmentSubsystem::DBG_ALIGNMENT, "Mount -> Sky RA: %s DE: %s AZ: %s AL: %s HA: %s Pier: %s",
+ RAStr,
+ DecStr,
+ AzStr,
+ AltStr,
+ HAStr,
+ MountTypeSP[ALTAZ].getState() == ISS_ON ? "NA" : getPierSideStr(currentPierSide));
+
+ if (std::abs(celestialAzAlt.azimuth - HorizontalCoordsNP[AXIS_AZ].getValue()) > 0.1 ||
+ std::abs(celestialAzAlt.altitude - HorizontalCoordsNP[AXIS_ALT].getValue()) > 0.1)
+ {
+ HorizontalCoordsNP[AXIS_AZ].setValue(celestialAzAlt.azimuth);
+ HorizontalCoordsNP[AXIS_ALT].setValue(celestialAzAlt.altitude);
+ HorizontalCoordsNP.apply();
+ }
+
+ if (TrackState == SCOPE_SLEWING)
+ {
+ if (isSlewing() == false)
+ {
+ // Stages are GOTO --> SLEWING FAST --> APPRAOCH --> SLEWING SLOW --> TRACKING
+ if (ScopeStatus == SLEWING_FAST)
+ {
+ ScopeStatus = APPROACH;
+ return Goto(m_SkyGOTOTarget.rightascension, m_SkyGOTOTarget.declination);
+ }
+
+ // If tracking was engaged, start it.
+ if (isTrackingRequested())
+ {
+ // Goto has finished start tracking
+ ScopeStatus = TRACKING;
+ if (HorizontalCoordsNP.getState() == IPS_BUSY)
+ {
+ HorizontalCoordsNP.setState(IPS_OK);
+ HorizontalCoordsNP.apply();
+ }
+ TrackState = SCOPE_TRACKING;
+ resetTracking();
+
+ // For equatorial mounts, engage tracking.
+ if (MountTypeSP[EQUATORIAL].getState() == ISS_ON)
+ SetTrackMode(IUFindOnSwitchIndex(&TrackModeSP));
+ LOG_INFO("Tracking started.");
+ }
+ else
+ {
+ TrackState = SCOPE_IDLE;
+ ScopeStatus = IDLE;
+ }
+ }
+ }
+ else if (TrackState == SCOPE_PARKING)
+ {
+ if (isSlewing() == false)
+ {
+ SetParked(true);
+ SetTrackEnabled(false);
+ }
+ }
+
+ NewRaDec(m_SkyCurrentRADE.rightascension, m_SkyCurrentRADE.declination);
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void CelestronAUX::EncodersToAltAz(INDI::IHorizontalCoordinates &coords)
+{
+ coords.azimuth = DegreesToAzimuth(EncodersToDegrees(EncoderNP[AXIS_AZ].getValue()));
+ coords.altitude = EncodersToDegrees(EncoderNP[AXIS_ALT].getValue());
+ DEBUGF(INDI::AlignmentSubsystem::DBG_ALIGNMENT, "Axis1 encoder %10.f -> AZ %.4f°", EncoderNP[AXIS_AZ].getValue(),
+ coords.azimuth);
+ DEBUGF(INDI::AlignmentSubsystem::DBG_ALIGNMENT, "Axis2 encoder %10.f -> AL %.4f°", EncoderNP[AXIS_ALT].getValue(),
+ coords.altitude);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::Goto(double ra, double dec)
+{
+ char RAStr[32] = {0}, DecStr[32] = {0};
+ fs_sexa(RAStr, ra, 2, 3600);
+ fs_sexa(DecStr, dec, 2, 3600);
+
+ // In case we have appaoch ongoing
+ if (ScopeStatus == APPROACH)
+ {
+ DEBUGF(INDI::AlignmentSubsystem::DBG_ALIGNMENT, "Slow Iterative GOTO RA %s DE %s", RAStr, DecStr);
+ }
+ // Fast GOTO
+ else
+ {
+ if (TrackState != SCOPE_IDLE)
+ Abort();
+
+ m_GuideOffset[AXIS_AZ] = m_GuideOffset[AXIS_ALT] = 0;
+ m_SkyGOTOTarget.rightascension = ra;
+ m_SkyGOTOTarget.declination = dec;
+
+ DEBUGF(INDI::AlignmentSubsystem::DBG_ALIGNMENT, "Fast GOTO RA %s DE %s", RAStr, DecStr);
+
+ if (isTrackingRequested())
+ {
+ m_SkyTrackingTarget = m_SkyGOTOTarget;
+ }
+ }
+
+ uint32_t axis1Steps {0}, axis2Steps {0};
+
+ TelescopeDirectionVector TDV;
+ INDI::IEquatorialCoordinates MountRADE { ra, dec };
+
+ // Transform Celestial to Telescope coordinates.
+ // We have no good way to estimate how long will the mount takes to reach target (with deceleration,
+ // and not just speed). So we will use iterative GOTO once the first GOTO is complete.
+ if (TransformCelestialToTelescope(ra, dec, 0.0, TDV))
+ {
+ // For Alt-Az Mounts, we get the Mount AltAz coords
+ if (MountTypeSP[MOUNT_ALTAZ].getState() == ISS_ON)
+ {
+ INDI::IHorizontalCoordinates MountAltAz { 0, 0 };
+ AltitudeAzimuthFromTelescopeDirectionVector(TDV, MountAltAz);
+ // Converts to steps and we're done.
+ axis1Steps = DegreesToEncoders(AzimuthToDegrees(MountAltAz.azimuth));
+ axis2Steps = DegreesToEncoders(MountAltAz.altitude);
+
+ // For logging purposes
+ INDI::HorizontalToEquatorial(&MountAltAz, &m_Location, ln_get_julian_from_sys(), &MountRADE);
+ }
+ // For Equatorial mounts
+ else
+ {
+ EquatorialCoordinatesFromTelescopeDirectionVector(TDV, MountRADE);
+ // Converts to steps and we're done.
+ RADEToEncoders(MountRADE, axis1Steps, axis2Steps);
+ }
+ }
+ // Conversion failed, use values as is
+ else
+ {
+ if (MountTypeSP[EQUATORIAL].getState() == ISS_ON)
+ {
+ RADEToEncoders(MountRADE, axis1Steps, axis2Steps);
+ }
+ else
+ {
+ INDI::IHorizontalCoordinates MountAltAz { 0, 0 };
+ INDI::EquatorialToHorizontal(&MountRADE, &m_Location, ln_get_julian_from_sys(), &MountAltAz);
+ TDV = TelescopeDirectionVectorFromAltitudeAzimuth(MountAltAz);
+ switch (GetApproximateMountAlignment())
+ {
+ case ZENITH:
+ break;
+
+ case NORTH_CELESTIAL_POLE:
+ // Rotate the TDV coordinate system clockwise (negative) around the y axis by 90 minus
+ // the (positive)observatory latitude. The vector itself is rotated anticlockwise
+ TDV.RotateAroundY(m_Location.latitude - 90.0);
+ break;
+
+ case SOUTH_CELESTIAL_POLE:
+ // Rotate the TDV coordinate system anticlockwise (positive) around the y axis by 90 plus
+ // the (negative)observatory latitude. The vector itself is rotated clockwise
+ TDV.RotateAroundY(m_Location.latitude + 90.0);
+ break;
+ }
+ AltitudeAzimuthFromTelescopeDirectionVector(TDV, MountAltAz);
+
+ // Converts to steps and we're done.
+ axis1Steps = DegreesToEncoders(AzimuthToDegrees(MountAltAz.azimuth));
+ axis2Steps = DegreesToEncoders(MountAltAz.altitude);
+ }
+ }
+
+ fs_sexa(RAStr, MountRADE.rightascension, 2, 3600);
+ fs_sexa(DecStr, MountRADE.declination, 2, 3600);
+ DEBUGF(INDI::AlignmentSubsystem::DBG_ALIGNMENT, "Sky -> Mount RA %s (%ld) DE %s (%ld)", RAStr, axis1Steps, DecStr,
+ axis2Steps);
+
+ // Slew to physical steps.
+ slewTo(AXIS_AZ, axis1Steps, ScopeStatus != APPROACH);
+ slewTo(AXIS_ALT, axis2Steps, ScopeStatus != APPROACH);
+
+ ScopeStatus = (ScopeStatus == APPROACH) ? SLEWING_SLOW : SLEWING_FAST;
+ TrackState = SCOPE_SLEWING;
+
+ if (MountTypeSP[ALTAZ].getState() == ISS_ON && HorizontalCoordsNP.getState() != IPS_BUSY)
+ {
+ HorizontalCoordsNP.setState(IPS_BUSY);
+ HorizontalCoordsNP.apply();
+
+ }
+ return true;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::Sync(double ra, double dec)
+{
+ // Compute a telescope direction vector from the current encoders
+ if (!getEncoder(AXIS_AZ))
+ return false;
+ if (!getEncoder(AXIS_ALT))
+ return false;
+
+
+ AlignmentDatabaseEntry NewEntry;
+ NewEntry.ObservationJulianDate = ln_get_julian_from_sys();
+ NewEntry.RightAscension = ra;
+ NewEntry.Declination = dec;
+
+
+ if (MountTypeSP[MOUNT_ALTAZ].getState() == ISS_ON)
+ {
+ INDI::IHorizontalCoordinates MountAltAz { 0, 0 };
+ MountAltAz.azimuth = DegreesToAzimuth(EncodersToDegrees(EncoderNP[AXIS_AZ].getValue()));
+ MountAltAz.altitude = EncodersToDegrees(EncoderNP[AXIS_ALT].getValue());
+ NewEntry.TelescopeDirection = TelescopeDirectionVectorFromAltitudeAzimuth(MountAltAz);
+ }
+ else
+ {
+ INDI::IEquatorialCoordinates MountRADE {0, 0};
+ TelescopePierSide pierSide;
+ EncodersToRADE(MountRADE, pierSide);
+ NewEntry.TelescopeDirection = TelescopeDirectionVectorFromEquatorialCoordinates(MountRADE);
+ }
+ NewEntry.PrivateDataSize = 0;
+
+ DEBUGF(INDI::AlignmentSubsystem::DBG_ALIGNMENT, "New sync point Date %lf RA %lf DEC %lf TDV(x %lf y %lf z %lf)",
+ NewEntry.ObservationJulianDate, NewEntry.RightAscension, NewEntry.Declination, NewEntry.TelescopeDirection.x,
+ NewEntry.TelescopeDirection.y, NewEntry.TelescopeDirection.z);
+
+ if (!CheckForDuplicateSyncPoint(NewEntry))
+ {
+ GetAlignmentDatabase().push_back(NewEntry);
+
+ // Tell the client about size change
+ UpdateSize();
+
+ // Tell the math plugin to reinitialise
+ Initialise(this);
+
+ // Force read before restarting
+ ReadScopeStatus();
+
+ // Sync cord wrap
+ syncCoordWrapPosition();
+
+ // The tracking seconds should be reset to restart the drift compensation
+ resetTracking();
+
+ return true;
+ }
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+///
+//////////////////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::mountToSkyCoords()
+{
+ double RightAscension, Declination;
+
+ // TODO for Alt-Az Mounts on a Wedge, we need a watch to set this.
+ if (MountTypeSP[ALTAZ].getState() == ISS_ON)
+ {
+ INDI::IHorizontalCoordinates AltAz = m_MountCurrentAltAz;
+ TelescopeDirectionVector TDV = TelescopeDirectionVectorFromAltitudeAzimuth(AltAz);
+ if (!TransformTelescopeToCelestial(TDV, RightAscension, Declination))
+ {
+ TelescopeDirectionVector RotatedTDV(TDV);
+ switch (GetApproximateMountAlignment())
+ {
+ case ZENITH:
+ break;
+
+ case NORTH_CELESTIAL_POLE:
+ // Rotate the TDV coordinate system anticlockwise (positive) around the y axis by 90 minus
+ // the (positive)observatory latitude. The vector itself is rotated clockwise
+ RotatedTDV.RotateAroundY(90.0 - m_Location.latitude);
+ AltitudeAzimuthFromTelescopeDirectionVector(RotatedTDV, AltAz);
+ break;
+
+ case SOUTH_CELESTIAL_POLE:
+ // Rotate the TDV coordinate system clockwise (negative) around the y axis by 90 plus
+ // the (negative)observatory latitude. The vector itself is rotated anticlockwise
+ RotatedTDV.RotateAroundY(-90.0 - m_Location.latitude);
+ AltitudeAzimuthFromTelescopeDirectionVector(RotatedTDV, AltAz);
+ break;
+ }
+
+ INDI::IEquatorialCoordinates EquatorialCoordinates;
+ INDI::HorizontalToEquatorial(&AltAz, &m_Location, ln_get_julian_from_sys(), &EquatorialCoordinates);
+ RightAscension = EquatorialCoordinates.rightascension;
+ Declination = EquatorialCoordinates.declination;
+ }
+ }
+ else
+ {
+ INDI::IEquatorialCoordinates EquatorialCoordinates = m_MountCurrentRADE;
+ TelescopeDirectionVector TDV = TelescopeDirectionVectorFromEquatorialCoordinates(EquatorialCoordinates);
+ if (!TransformTelescopeToCelestial(TDV, RightAscension, Declination))
+ {
+ RightAscension = EquatorialCoordinates.rightascension;
+ Declination = EquatorialCoordinates.declination;
+ }
+ }
+
+ m_SkyCurrentRADE.rightascension = RightAscension;
+ m_SkyCurrentRADE.declination = Declination;
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void CelestronAUX::TimerHit()
+{
+ INDI::Telescope::TimerHit();
+
+ switch (TrackState)
+ {
+ case SCOPE_SLEWING:
+ break;
+
+ case SCOPE_TRACKING:
+ {
+ // Check if manual motion in progress but we stopped
+ if (m_ManualMotionActive && isSlewing() == false)
+ {
+ m_ManualMotionActive = false;
+ // If we slewed manually using NSWE keys, then we need to restart tracking
+ // whatever point we are AT now. We need to update the SkyTrackingTarget accordingly.
+ m_SkyTrackingTarget.rightascension = EqN[AXIS_RA].value;
+ m_SkyTrackingTarget.declination = EqN[AXIS_DE].value;
+ resetTracking();
+ }
+ // If we're manually moving by WESN controls, update the tracking coordinates.
+ if (m_ManualMotionActive)
+ {
+ break;
+ }
+ // We only engage ACTIVE tracking if the mount is Alt-Az.
+ // For Equatorial mount, we simply use user-selected tracking mode and let it passively track.
+ else if (MountTypeSP[MOUNT_ALTAZ].getState() == ISS_ON)
+ {
+ TelescopeDirectionVector TDV;
+ INDI::IHorizontalCoordinates targetMountAxisCoordinates { 0, 0 };
+
+ // Start by transforming tracking target celestial coordinates to telescope coordinates.
+ if (TransformCelestialToTelescope(m_SkyTrackingTarget.rightascension, m_SkyTrackingTarget.declination,
+ 0, TDV))
+ {
+ // If mount is Alt-Az then that's all we need to do
+ AltitudeAzimuthFromTelescopeDirectionVector(TDV, targetMountAxisCoordinates);
+ }
+ // If transformation failed.
+ else
+ {
+ INDI::IEquatorialCoordinates EquatorialCoordinates { 0, 0 };
+ EquatorialCoordinates.rightascension = m_SkyTrackingTarget.rightascension;
+ EquatorialCoordinates.declination = m_SkyTrackingTarget.declination;
+ INDI::EquatorialToHorizontal(&EquatorialCoordinates, &m_Location, ln_get_julian_from_sys(), &targetMountAxisCoordinates);
+ }
+
+ // Now add the guiding offsets.
+ targetMountAxisCoordinates.azimuth += m_GuideOffset[AXIS_AZ];
+ targetMountAxisCoordinates.altitude += m_GuideOffset[AXIS_ALT];
+
+ // If we had guiding pulses active, mark them as complete
+ if (GuideWENP.s == IPS_BUSY)
+ GuideComplete(AXIS_RA);
+ if (GuideNSNP.s == IPS_BUSY)
+ GuideComplete(AXIS_DE);
+
+ // Next get current alt-az
+ INDI::IHorizontalCoordinates currentAltAz { 0, 0 };
+ currentAltAz.azimuth = DegreesToAzimuth(EncodersToDegrees(EncoderNP[AXIS_AZ].getValue()));
+ currentAltAz.altitude = EncodersToDegrees(EncoderNP[AXIS_ALT].getValue());
+
+ // Offset in degrees
+ double offsetAngle[2] = {0, 0};
+ offsetAngle[AXIS_AZ] = (targetMountAxisCoordinates.azimuth - currentAltAz.azimuth);
+ offsetAngle[AXIS_ALT] = (targetMountAxisCoordinates.altitude - currentAltAz.altitude);
+
+ int32_t offsetSteps[2] = {0, 0};
+ int32_t targetSteps[2] = {0, 0};
+ double trackRates[2] = {0, 0};
+
+ offsetSteps[AXIS_AZ] = offsetAngle[AXIS_AZ] * STEPS_PER_DEGREE;
+ offsetSteps[AXIS_ALT] = offsetAngle[AXIS_ALT] * STEPS_PER_DEGREE;
+
+ // Only apply trackinf IF we're still on the same side of the curve
+ // If we switch over, let's settle for a bit
+ if (m_LastOffset[AXIS_AZ] * offsetSteps[AXIS_AZ] >= 0 || m_OffsetSwitchSettle[AXIS_AZ]++ > 3)
+ {
+ m_OffsetSwitchSettle[AXIS_AZ] = 0;
+ m_LastOffset[AXIS_AZ] = offsetSteps[AXIS_AZ];
+ targetSteps[AXIS_AZ] = DegreesToEncoders(AzimuthToDegrees(targetMountAxisCoordinates.azimuth));
+ trackRates[AXIS_AZ] = m_Controllers[AXIS_AZ]->calculate(targetSteps[AXIS_AZ], EncoderNP[AXIS_AZ].getValue());
+
+ LOGF_DEBUG("Tracking AZ Now: %.f Target: %d Offset: %d Rate: %.2f", EncoderNP[AXIS_AZ].getValue(), targetSteps[AXIS_AZ],
+ offsetSteps[AXIS_AZ], trackRates[AXIS_AZ]);
+#ifdef DEBUG_PID
+ LOGF_DEBUG("Tracking AZ P: %f I: %f D: %f",
+ m_Controllers[AXIS_AZ]->propotionalTerm(),
+ m_Controllers[AXIS_AZ]->integralTerm(),
+ m_Controllers[AXIS_AZ]->derivativeTerm());
+#endif
+
+ // Use PID to determine appropiate tracking rate
+ trackByRate(AXIS_AZ, trackRates[AXIS_AZ]);
+ }
+
+ // Only apply trackinf IF we're still on the same side of the curve
+ // If we switch over, let's settle for a bit
+ if (m_LastOffset[AXIS_ALT] * offsetSteps[AXIS_ALT] >= 0 || m_OffsetSwitchSettle[AXIS_ALT]++ > 3)
+ {
+ m_OffsetSwitchSettle[AXIS_ALT] = 0;
+ m_LastOffset[AXIS_ALT] = offsetSteps[AXIS_ALT];
+ targetSteps[AXIS_ALT] = DegreesToEncoders(targetMountAxisCoordinates.altitude);
+ trackRates[AXIS_ALT] = m_Controllers[AXIS_ALT]->calculate(targetSteps[AXIS_ALT], EncoderNP[AXIS_ALT].getValue());
+
+ LOGF_DEBUG("Tracking AL Now: %.f Target: %d Offset: %d Rate: %.2f", EncoderNP[AXIS_ALT].getValue(), targetSteps[AXIS_ALT],
+ offsetSteps[AXIS_ALT], trackRates[AXIS_ALT]);
+#ifdef DEBUG_PID
+ LOGF_DEBUG("Tracking AL P: %f I: %f D: %f",
+ m_Controllers[AXIS_ALT]->propotionalTerm(),
+ m_Controllers[AXIS_ALT]->integralTerm(),
+ m_Controllers[AXIS_ALT]->derivativeTerm());
+#endif
+ trackByRate(AXIS_ALT, trackRates[AXIS_ALT]);
+ }
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Check if seeking index or leveling is done
+ if (HomeSP.getState() == IPS_BUSY)
+ {
+ isHomingDone(AXIS_AZ);
+ isHomingDone(AXIS_ALT);
+
+ if (!m_HomingProgress[AXIS_AZ] && !m_HomingProgress[AXIS_ALT])
+ {
+ LOG_INFO("Homing complete.");
+ HomeSP.reset();
+ HomeSP.setState(IPS_OK);
+ HomeSP.apply();
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::updateLocation(double latitude, double longitude, double elevation)
+{
+ // Update INDI Alignment Subsystem Location
+ UpdateLocation(latitude, longitude, elevation);
+
+ // Do we really need this in update Location??
+ // take care of latitude for north or south emisphere
+ //SetApproximateMountAlignmentFromMountType(static_cast<MountType>(IUFindOnSwitchIndex(&MountTypeSP)));
+ // tell the alignment math plugin to reinitialise
+ //Initialise(this);
+
+ // update cordwrap position at each init of the alignment subsystem
+ syncCoordWrapPosition();
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// 0 to 360 degrees
+/////////////////////////////////////////////////////////////////////////////////////
+double CelestronAUX::EncodersToDegrees(uint32_t steps)
+{
+ return range360(steps * DEGREES_PER_STEP);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+uint32_t CelestronAUX::DegreesToEncoders(double degree)
+{
+ return round(range360(degree) * STEPS_PER_DEGREE);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+double CelestronAUX::DegreesToAzimuth(double degree)
+{
+ if (isNorthHemisphere())
+ return degree;
+ else
+ return range360(degree + 180);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+double CelestronAUX::AzimuthToDegrees(double degree)
+{
+ if (isNorthHemisphere())
+ return degree;
+ else
+ return range360(degree + 180);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// 0 to 24 hours
+/////////////////////////////////////////////////////////////////////////////////////
+double CelestronAUX::EncodersToHours(uint32_t steps)
+{
+ double value = steps * HOURS_PER_STEP;
+ // North hemisphere
+ if (isNorthHemisphere())
+ return range24(value);
+ else
+ return range24(24 - value);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+uint32_t CelestronAUX::HoursToEncoders(double hour)
+{
+ return DegreesToEncoders(hour * 15);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void CelestronAUX::EncodersToRADE(INDI::IEquatorialCoordinates &coords, TelescopePierSide &pierSide)
+{
+ auto haEncoder = (EncoderNP[AXIS_RA].getValue() / STEPS_PER_REVOLUTION) * 360.0;
+ auto deEncoder = 360.0 - (EncoderNP[AXIS_DE].getValue() / STEPS_PER_REVOLUTION) * 360.0;
+
+ double de = 0, ha = 0;
+ // Northern Hemisphere
+ if (LocationN[LOCATION_LATITUDE].value >= 0)
+ {
+ if (m_IsWedge)
+ {
+ pierSide = PIER_UNKNOWN;
+ if (deEncoder >= 270)
+ de = 360 - deEncoder;
+ else if (deEncoder >= 90)
+ de = deEncoder - 180;
+ else
+ de = -deEncoder;
+
+ if (haEncoder >= 180)
+ ha = -((360 - haEncoder) / 360.0) * 24.0 ;
+ else
+ ha = (haEncoder / 360.0) * 24.0 ;
+ }
+ // "Normal" Pointing State (East, looking West)
+ else if (deEncoder >= 0)
+ {
+ de = std::min(90 - deEncoder, 90.0);
+ ha = -6.0 + (haEncoder / 360.0) * 24.0 ;
+ pierSide = PIER_EAST;
+ }
+ // "Reversed" Pointing State (West, looking East)
+ else
+ {
+ de = 90 + deEncoder;
+ ha = 6.0 + (haEncoder / 360.0) * 24.0 ;
+ pierSide = PIER_WEST;
+ }
+ }
+ else
+ {
+ if (m_IsWedge)
+ {
+ pierSide = PIER_UNKNOWN;
+ if (deEncoder >= 270)
+ de = deEncoder - 360;
+ else if (deEncoder >= 90)
+ de = 180 - deEncoder;
+ else
+ de = deEncoder;
+
+ if (haEncoder >= 180)
+ ha = -((360 - haEncoder) / 360.0) * 24.0 ;
+ else
+ ha = (haEncoder / 360.0) * 24.0 ;
+ }
+ // East
+ else if (deEncoder <= 0)
+ {
+ de = std::max(-90 - deEncoder, -90.0);
+ ha = -6.0 - (haEncoder / 360.0) * 24.0 ;
+ pierSide = PIER_WEST;
+ }
+ // West
+ else
+ {
+ de = -90 + deEncoder;
+ ha = 6.0 - (haEncoder / 360.0) * 24.0 ;
+ pierSide = PIER_EAST;
+ }
+ }
+
+ double lst = get_local_sidereal_time(LocationN[LOCATION_LONGITUDE].value);
+ double ra = range24(lst - ha);
+
+ coords.rightascension = ra;
+ coords.declination = de;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// HA encoders at 0 (HA = LST). When going WEST, steps increase from 0 to STEPS_PER_REVOLUTION {16777216}
+/// counter clock-wise.
+/// HA 0 to 6 hours range: 0 to 4194304
+/// HA 0 to -6 hours range: 16777216 to 12582912
+/////////////////////////////////////////////////////////////////////////////////////
+void CelestronAUX::RADEToEncoders(const INDI::IEquatorialCoordinates &coords, uint32_t &haEncoder, uint32_t &deEncoder)
+{
+ double lst = get_local_sidereal_time(LocationN[LOCATION_LONGITUDE].value);
+ double dHA = rangeHA(lst - coords.rightascension);
+ double de = 0, ha = 0;
+ // Northern Hemisphere
+ if (LocationN[LOCATION_LATITUDE].value >= 0)
+ {
+ if (m_IsWedge)
+ {
+ if (coords.declination < 0)
+ de = -coords.declination;
+ else
+ de = 360 - coords.declination;
+
+ if (dHA < 0)
+ ha = 360 - ((dHA / -24.0) * 360.0);
+ else
+ ha = (dHA / 24.0) * 360.0;
+
+ }
+ // "Normal" Pointing State (East, looking West)
+ else if (dHA <= 0)
+ {
+ de = -(coords.declination - 90.0);
+ ha = (dHA + 6.0) * 360.0 / 24.0;
+ }
+ // "Reversed" Pointing State (West, looking East)
+ else
+ {
+ de = coords.declination - 90.0;
+ ha = (dHA - 6.0) * 360.0 / 24.0;
+ }
+ }
+ else
+ {
+ if (m_IsWedge)
+ {
+ if (coords.declination >= 0)
+ de = coords.declination;
+ else
+ de = 360 + coords.declination;
+
+ if (dHA < 0)
+ ha = 360 - ((dHA / -24.0) * 360.0);
+ else
+ ha = (dHA / 24.0) * 360.0;
+
+ }
+ // "Normal" Pointing State (East, looking West)
+ else if (dHA <= 0)
+ {
+ de = -(coords.declination + 90.0);
+ ha = -(dHA + 6.0) * 360.0 / 24.0;
+ }
+ // "Reversed" Pointing State (West, looking East)
+ else
+ {
+ de = (coords.declination + 90.0);
+ ha = -(dHA - 6.0) * 360 / 24.0;
+ }
+ }
+
+ haEncoder = (range360(ha) / 360.0) * STEPS_PER_REVOLUTION;
+ deEncoder = (360.0 - range360(de)) / 360.0 * STEPS_PER_REVOLUTION;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// -90 to +90
+/////////////////////////////////////////////////////////////////////////////////////
+double CelestronAUX::EncodersToDE(uint32_t steps, TelescopePierSide pierSide)
+{
+ double degrees = EncodersToDegrees(steps);
+ double de = 0;
+ if (m_IsWedge)
+ de = degrees;
+ else if ((isNorthHemisphere() && pierSide == PIER_WEST) || (!isNorthHemisphere() && pierSide == PIER_EAST))
+ de = degrees - 270;
+ else
+ de = 90 - degrees;
+
+ return rangeDec(de);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+double CelestronAUX::DEToEncoders(double de)
+{
+ double degrees = 0;
+ if (m_IsWedge)
+ degrees = de;
+ else if ((isNorthHemisphere() && m_TargetPierSide == PIER_WEST) || (!isNorthHemisphere() && m_TargetPierSide == PIER_EAST))
+ degrees = 270 + de;
+ else
+ degrees = 90 - de;
+ return DegreesToEncoders(degrees);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::isSlewing()
+{
+ return m_AxisStatus[AXIS_AZ] == SLEWING || m_AxisStatus[AXIS_ALT] == SLEWING;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::slewTo(INDI_HO_AXIS axis, uint32_t steps, bool fast)
+{
+ // Stop first.
+ trackByRate(axis, 0);
+ AUXCommand command(fast ? MC_GOTO_FAST : MC_GOTO_SLOW, APP, axis == AXIS_AZ ? AZM : ALT);
+ m_AxisStatus[axis] = SLEWING;
+ command.setData(steps, 3);
+ sendAUXCommand(command);
+ readAUXResponse(command);
+ return true;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::slewByRate(INDI_HO_AXIS axis, int8_t rate)
+{
+ // Stop first.
+ trackByRate(axis, 0);
+ AUXCommand command(rate >= 0 ? MC_MOVE_POS : MC_MOVE_NEG, APP, axis == AXIS_AZ ? AZM : ALT);
+ command.setData(std::abs(rate), 1);
+ sendAUXCommand(command);
+ readAUXResponse(command);
+ return true;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::goHome(INDI_HO_AXIS axis)
+{
+ AUXCommand command(axis == AXIS_AZ ? MC_SEEK_INDEX : MC_LEVEL_START, APP, axis == AXIS_AZ ? AZM : ALT);
+ sendAUXCommand(command);
+ readAUXResponse(command);
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::isHomingDone(INDI_HO_AXIS axis)
+{
+ AUXCommand command(axis == AXIS_AZ ? MC_SEEK_DONE : MC_LEVEL_DONE, APP, axis == AXIS_AZ ? AZM : ALT);
+ sendAUXCommand(command);
+ readAUXResponse(command);
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::getVersion(AUXTargets target)
+{
+ AUXCommand firmver(GET_VER, APP, target);
+ if (! sendAUXCommand(firmver))
+ return false;
+ if (! readAUXResponse(firmver))
+ return false;
+ return true;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void CelestronAUX::getVersions()
+{
+ if (!m_isHandController)
+ {
+ // Do not ask HC/MB for the version over AUX channel
+ // We got HC version from detectHC
+ getVersion(MB);
+ getVersion(HC);
+ getVersion(HCP);
+ }
+ getVersion(AZM);
+ getVersion(ALT);
+ getVersion(GPS);
+ getVersion(WiFi);
+ getVersion(BAT);
+
+ // These are the same as battery controller
+ // Probably the same chip inside the mount
+ //getVersion(CHG);
+ //getVersion(LIGHT);
+ //getVersion(ANY);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::setCordWrapEnabled(bool enable)
+{
+
+ AUXCommand command(enable ? MC_ENABLE_CORDWRAP : MC_DISABLE_CORDWRAP, APP, AZM);
+ sendAUXCommand(command);
+ readAUXResponse(command);
+ return true;
+};
+
+bool CelestronAUX::getCordWrapEnabled()
+{
+ AUXCommand command(MC_POLL_CORDWRAP, APP, AZM);
+ sendAUXCommand(command);
+ readAUXResponse(command);
+ return m_CordWrapActive;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::setCordWrapPosition(uint32_t steps)
+{
+ AUXCommand command(MC_SET_CORDWRAP_POS, APP, AZM);
+ command.setData(steps, 3);
+ sendAUXCommand(command);
+ readAUXResponse(command);
+ return true;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+uint32_t CelestronAUX::getCordWrapPosition()
+{
+ AUXCommand command(MC_GET_CORDWRAP_POS, APP, AZM);
+ sendAUXCommand(command);
+ readAUXResponse(command);
+ return m_CordWrapPosition;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::stopAxis(INDI_HO_AXIS axis)
+{
+ m_AxisStatus[axis] = STOPPED;
+ trackByRate(axis, 0);
+ AUXCommand command(MC_MOVE_POS, APP, (axis == AXIS_ALT) ? ALT : AZM);
+ command.setData(0, 1);
+ sendAUXCommand(command);
+ readAUXResponse(command);
+ return true;
+
+}
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::Abort()
+{
+ // getEncoder(AXIS_AZ);
+ // getEncoder(AXIS_ALT);
+ // double ms = m_TrackingElapsedTimer.elapsed();
+ // LOGF_INFO("*** Elapsed %.f ms", ms);
+ // LOGF_INFO("*** Axis1 start: %.f finish: %.f steps/s: %.4f", m_TrackStartSteps[AXIS_AZ], EncoderNP[AXIS_AZ].getValue(), std::abs(EncoderNP[AXIS_AZ].getValue() - m_TrackStartSteps[AXIS_AZ]) / (ms/1000.));
+ // LOGF_INFO("*** Axis2 start: %.f finish: %.f steps/s: %.4f", m_TrackStartSteps[AXIS_ALT], EncoderNP[AXIS_ALT].getValue(), std::abs(EncoderNP[AXIS_ALT].getValue() - m_TrackStartSteps[AXIS_ALT]) / (ms/1000.));
+ stopAxis(AXIS_AZ);
+ stopAxis(AXIS_ALT);
+ m_GuideOffset[AXIS_AZ] = m_GuideOffset[AXIS_ALT] = 0;
+ TrackState = SCOPE_IDLE;
+
+ if (HorizontalCoordsNP.getState() != IPS_IDLE)
+ {
+ HorizontalCoordsNP.setState(IPS_IDLE);
+ HorizontalCoordsNP.apply();
+ }
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// Rate is Celestron specific and roughly equals 80 ticks per 1 motor step
+/// rate = 80 would cause the motor to spin at a rate of 1 step/s
+/// Have to check if 80 is specific to my Evolution 6" or not.
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::trackByRate(INDI_HO_AXIS axis, int32_t rate)
+{
+ if (std::abs(rate) > 0 && rate == m_LastTrackRate[axis])
+ return true;
+
+ m_LastTrackRate[axis] = rate;
+ AUXCommand command(rate < 0 ? MC_SET_NEG_GUIDERATE : MC_SET_POS_GUIDERATE, APP, axis == AXIS_AZ ? AZM : ALT);
+ // 24bit rate
+ command.setData(std::abs(rate), 3);
+ sendAUXCommand(command);
+ readAUXResponse(command);
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::trackByMode(INDI_HO_AXIS axis, uint8_t mode)
+{
+ AUXCommand command(isNorthHemisphere() ? MC_SET_POS_GUIDERATE : MC_SET_NEG_GUIDERATE, APP, axis == AXIS_AZ ? AZM : ALT);
+ switch (mode)
+ {
+ case TRACK_SOLAR:
+ command.setData(AUX_SOLAR, 2);
+ break;
+ case TRACK_LUNAR:
+ command.setData(AUX_LUNAR, 2);
+ break;
+ case TRACK_SIDEREAL:
+ default:
+ command.setData(AUX_SIDEREAL, 2);
+ break;
+ }
+
+ sendAUXCommand(command);
+ readAUXResponse(command);
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::SetTrackEnabled(bool enabled)
+{
+ if (enabled)
+ {
+ TrackState = SCOPE_TRACKING;
+ resetTracking();
+ m_SkyTrackingTarget.rightascension = EqN[AXIS_RA].value;
+ m_SkyTrackingTarget.declination = EqN[AXIS_DE].value;
+
+ if (IUFindOnSwitchIndex(&TrackModeSP) == TRACK_CUSTOM)
+ return SetTrackRate(TrackRateN[AXIS_AZ].value, TrackRateN[AXIS_ALT].value);
+ else
+ return SetTrackMode(IUFindOnSwitchIndex(&TrackModeSP));
+ }
+ else
+ {
+ TrackState = SCOPE_IDLE;
+ trackByRate(AXIS_AZ, 0);
+ trackByRate(AXIS_ALT, 0);
+
+ if (HorizontalCoordsNP.getState() != IPS_IDLE)
+ {
+ HorizontalCoordsNP.setState(IPS_IDLE);
+ HorizontalCoordsNP.apply();
+ }
+ }
+
+ return true;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::SetTrackRate(double raRate, double deRate)
+{
+ m_TrackRates[AXIS_AZ] = raRate;
+ m_TrackRates[AXIS_ALT] = deRate;
+
+ if (TrackState == SCOPE_TRACKING)
+ {
+
+ double steps[2] = {0, 0};
+ // rate = (steps) * gain
+ steps[AXIS_AZ] = raRate * STEPS_PER_ARCSEC * GAIN_STEPS;
+ steps[AXIS_ALT] = deRate * STEPS_PER_ARCSEC * GAIN_STEPS;
+ trackByRate(AXIS_AZ, steps[AXIS_AZ]);
+ trackByRate(AXIS_ALT, steps[AXIS_ALT]);
+ }
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::SetTrackMode(uint8_t mode)
+{
+ if (mode == TRACK_SIDEREAL)
+ m_TrackRates[AXIS_AZ] = TRACKRATE_SIDEREAL;
+ else if (mode == TRACK_SOLAR)
+ m_TrackRates[AXIS_AZ] = TRACKRATE_SOLAR;
+ else if (mode == TRACK_LUNAR)
+ m_TrackRates[AXIS_AZ] = TRACKRATE_LUNAR;
+ else if (mode == TRACK_CUSTOM)
+ {
+ m_TrackRates[AXIS_AZ] = TrackRateN[AXIS_RA].value;
+ m_TrackRates[AXIS_ALT] = TrackRateN[AXIS_DE].value;
+ }
+
+ if (TrackState == SCOPE_TRACKING)
+ {
+ if (mode == TRACK_CUSTOM)
+ {
+ double steps[2] = {0, 0};
+ // rate = (steps) * gain
+ steps[AXIS_AZ] = m_TrackRates[AXIS_AZ] * STEPS_PER_ARCSEC * GAIN_STEPS;
+ steps[AXIS_ALT] = m_TrackRates[AXIS_ALT] * STEPS_PER_ARCSEC * GAIN_STEPS;
+ trackByRate(AXIS_AZ, steps[AXIS_AZ]);
+ trackByRate(AXIS_ALT, steps[AXIS_ALT]);
+ }
+ else
+ trackByMode(AXIS_AZ, mode);
+ }
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::getStatus(INDI_HO_AXIS axis)
+{
+ if (m_AxisStatus[axis] == SLEWING && ScopeStatus != SLEWING_MANUAL)
+ {
+ AUXCommand command(MC_SLEW_DONE, APP, axis == AXIS_AZ ? AZM : ALT);
+ sendAUXCommand(command);
+ readAUXResponse(command);
+ }
+
+ return true;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::getEncoder(INDI_HO_AXIS axis)
+{
+ AUXCommand command(MC_GET_POSITION, APP, axis == AXIS_AZ ? AZM : ALT);
+ sendAUXCommand(command);
+ readAUXResponse(command);
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+/// This is simple GPS emulation for HC.
+/// If HC asks for the GPS we reply with data from our GPS/Site info.
+/// We send reply blind (not reading any response) to avoid processing loop.
+/// That is why the readAUXResponse calls are commented out.
+/// This is OK since we are not going to do anything with the response anyway.
+/////////////////////////////////////////////////////////////////////////////////////
+void CelestronAUX::emulateGPS(AUXCommand &m)
+{
+ if (m.destination() != GPS)
+ return;
+
+ LOGF_DEBUG("GPS: Got 0x%02x", m.command());
+ if (m_GPSEmulation == false)
+ return;
+
+ switch (m.command())
+ {
+ case GET_VER:
+ {
+ LOGF_DEBUG("GPS: GET_VER from 0x%02x", m.source());
+ AUXBuffer dat(2);
+ dat[0] = 0x01;
+ dat[1] = 0x02;
+ AUXCommand cmd(GET_VER, GPS, m.source(), dat);
+ sendAUXCommand(cmd);
+ //readAUXResponse(cmd);
+ break;
+ }
+ case GPS_GET_LAT:
+ case GPS_GET_LONG:
+ {
+ LOGF_DEBUG("GPS: Sending LAT/LONG Lat:%f Lon:%f", LocationN[LOCATION_LATITUDE].value,
+ LocationN[LOCATION_LONGITUDE].value);
+ AUXCommand cmd(m.command(), GPS, m.source());
+ if (m.command() == GPS_GET_LAT)
+ cmd.setData(STEPS_PER_DEGREE * LocationN[LOCATION_LATITUDE].value);
+ else
+ cmd.setData(STEPS_PER_DEGREE * LocationN[LOCATION_LONGITUDE].value);
+ sendAUXCommand(cmd);
+ //readAUXResponse(cmd);
+ break;
+ }
+ case GPS_GET_TIME:
+ {
+ LOGF_DEBUG("GPS: GET_TIME from 0x%02x", m.source());
+ time_t gmt;
+ struct tm *ptm;
+ AUXBuffer dat(3);
+
+ time(&gmt);
+ ptm = gmtime(&gmt);
+ dat[0] = unsigned(ptm->tm_hour);
+ dat[1] = unsigned(ptm->tm_min);
+ dat[2] = unsigned(ptm->tm_sec);
+ AUXCommand cmd(GPS_GET_TIME, GPS, m.source(), dat);
+ sendAUXCommand(cmd);
+ //readAUXResponse(cmd);
+ break;
+ }
+ case GPS_GET_DATE:
+ {
+ LOGF_DEBUG("GPS: GET_DATE from 0x%02x", m.source());
+ time_t gmt;
+ struct tm *ptm;
+ AUXBuffer dat(2);
+
+ time(&gmt);
+ ptm = gmtime(&gmt);
+ dat[0] = unsigned(ptm->tm_mon + 1);
+ dat[1] = unsigned(ptm->tm_mday);
+ AUXCommand cmd(GPS_GET_DATE, GPS, m.source(), dat);
+ sendAUXCommand(cmd);
+ //readAUXResponse(cmd);
+ break;
+ }
+ case GPS_GET_YEAR:
+ {
+ LOGF_DEBUG("GPS: GET_YEAR from 0x%02x", m.source());
+ time_t gmt;
+ struct tm *ptm;
+ AUXBuffer dat(2);
+
+ time(&gmt);
+ ptm = gmtime(&gmt);
+ dat[0] = unsigned(ptm->tm_year + 1900) >> 8;
+ dat[1] = unsigned(ptm->tm_year + 1900) & 0xFF;
+ LOGF_DEBUG("GPS: Sending: %d [%d,%d]", ptm->tm_year, dat[0], dat[1]);
+ AUXCommand cmd(GPS_GET_YEAR, GPS, m.source(), dat);
+ sendAUXCommand(cmd);
+ //readAUXResponse(cmd);
+ break;
+ }
+ case GPS_LINKED:
+ {
+ LOGF_DEBUG("GPS: LINKED from 0x%02x", m.source());
+ AUXBuffer dat(1);
+
+ dat[0] = unsigned(1);
+ AUXCommand cmd(GPS_LINKED, GPS, m.source(), dat);
+ sendAUXCommand(cmd);
+ //readAUXResponse(cmd);
+ break;
+ }
+ default:
+ LOGF_DEBUG("GPS: Got 0x%02x", m.command());
+ break;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::processResponse(AUXCommand &m)
+{
+ m.logResponse();
+
+ if ((m.destination() == GPS) && (m.source() != APP))
+ {
+ // Avoid infinite loop by not responding to ourselves
+ emulateGPS(m);
+ }
+ else if (m.destination() == APP)
+ switch (m.command())
+ {
+ case MC_GET_POSITION:
+ switch (m.source())
+ {
+ case ALT:
+ EncoderNP[AXIS_ALT].setValue(m.getData());
+ break;
+ case AZM:
+ EncoderNP[AXIS_AZ].setValue(m.getData());
+ break;
+ default:
+ break;
+ }
+ break;
+ case MC_SLEW_DONE:
+ switch (m.source())
+ {
+ case ALT:
+ m_AxisStatus[AXIS_ALT] = (m.getData() == 0xff) ? STOPPED : SLEWING;
+ break;
+ case AZM:
+ m_AxisStatus[AXIS_AZ] = (m.getData() == 0xff) ? STOPPED : SLEWING;
+ break;
+ default:
+ break;
+ }
+ break;
+ case MC_POLL_CORDWRAP:
+ if (m.source() == AZM)
+ m_CordWrapActive = m.getData() == 0xff;
+ break;
+ case MC_GET_CORDWRAP_POS:
+ if (m.source() == AZM)
+ m_CordWrapPosition = m.getData();
+ break;
+
+ case MC_GET_AUTOGUIDE_RATE:
+ switch (m.source())
+ {
+ case ALT:
+ GuideRateNP[AXIS_ALT].setValue(m.getData() / 255.);
+ break;
+ case AZM:
+ GuideRateNP[AXIS_AZ].setValue(m.getData() * 255.);
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case MC_SET_AUTOGUIDE_RATE:
+ // Nothing to do.
+ break;
+
+ case MC_AUX_GUIDE:
+ // Nothing to do
+ break;
+
+ case MC_LEVEL_DONE:
+ m_HomingProgress[AXIS_ALT] = m.getData() == 0x00;
+ break;
+
+ case MC_SEEK_DONE:
+ m_HomingProgress[AXIS_AZ] = m.getData() == 0x00;
+ break;
+
+ case MC_AUX_GUIDE_ACTIVE:
+ switch (m.source())
+ {
+ case ALT:
+ if (m.getData() == 0x00)
+ GuideComplete(AXIS_DE);
+ break;
+ case AZM:
+ if (m.getData() == 0x00)
+ GuideComplete(AXIS_RA);
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case GET_VER:
+ {
+ uint8_t *verBuf = nullptr;
+ switch (m.source())
+ {
+ case MB:
+ verBuf = m_MainBoardVersion;
+ break;
+ case ALT:
+ verBuf = m_AltitudeVersion;
+ break;
+ case AZM:
+ verBuf = m_AzimuthVersion;
+ break;
+ case HCP:
+ case HC:
+ verBuf = m_HCVersion;
+ break;
+ case BAT:
+ verBuf = m_BATVersion;
+ break;
+ case WiFi:
+ verBuf = m_WiFiVersion;
+ break;
+ case GPS:
+ verBuf = m_GPSVersion;
+ break;
+ case APP:
+ LOGF_DEBUG("Got echo of GET_VERSION from %s", m.moduleName(m.destination()));
+ break;
+ default:
+ break;
+ }
+ if (verBuf != nullptr)
+ {
+ size_t verBuflen = 4;
+ if ( verBuflen != m.dataSize())
+ {
+ LOGF_DEBUG("Data and buffer size mismatch for GET_VER: buf[%d] vs data[%d]", verBuflen, m.dataSize());
+ }
+ for (int i = 0; i < (int)std::min(verBuflen, m.dataSize()); i++)
+ verBuf[i] = m.data()[i];
+ }
+ }
+ break;
+ default:
+ break;
+
+ }
+ else
+ {
+ DEBUGF(DBG_CAUX, "Got msg not for me (%s). Ignoring.", m.moduleName(m.destination()));
+ }
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::serialReadResponse(AUXCommand c)
+{
+ int n;
+ unsigned char buf[32];
+ char hexbuf[24];
+ AUXCommand cmd;
+
+ // We are not connected. Nothing to do.
+ if ( PortFD <= 0 )
+ return false;
+
+ if (m_IsRTSCTS || !m_isHandController)
+ {
+ // if connected to AUX or PC ports, receive AUX command response.
+ // search for packet preamble (0x3b)
+ do
+ {
+ if (aux_tty_read((char*)buf, 1, READ_TIMEOUT, &n) != TTY_OK)
+ return false;
+ }
+ while (buf[0] != 0x3b);
+
+ // packet preamble is found, now read packet length.
+ if (aux_tty_read((char*)(buf + 1), 1, READ_TIMEOUT, &n) != TTY_OK)
+ return false;
+
+ // now packet length is known, read the rest of the packet.
+ if (aux_tty_read((char*)(buf + 2), buf[1] + 1, READ_TIMEOUT, &n)
+ != TTY_OK || n != buf[1] + 1)
+ {
+ LOG_DEBUG("Did not got whole packet. Dropping out.");
+ return false;
+ }
+
+ AUXBuffer b(buf, buf + (n + 2));
+ hex_dump(hexbuf, b, b.size());
+ DEBUGF(DBG_SERIAL, "RES <%s>", hexbuf);
+ cmd.parseBuf(b);
+ }
+ else
+ {
+ // if connected to HC serial, build up the AUX command response from
+ // given AUX command and passthrough response without checksum.
+ // read passthrough response
+ if ((tty_read(PortFD, (char *)buf + 5, response_data_size + 1, READ_TIMEOUT, &n) !=
+ TTY_OK) || (n != response_data_size + 1))
+ return false;
+
+ // if last char is not '#', there was an error.
+ if (buf[response_data_size + 5] != '#')
+ {
+ LOGF_ERROR("Resp. char %d is %2.2x ascii %c", n, buf[n + 5], (char)buf[n + 5]);
+ AUXBuffer b(buf, buf + (response_data_size + 5));
+ hex_dump(hexbuf, b, b.size());
+ LOGF_ERROR("RES <%s>", hexbuf);
+ return false;
+ }
+
+ buf[0] = 0x3b;
+ buf[1] = response_data_size + 1;
+ buf[2] = c.destination();
+ buf[3] = c.source();
+ buf[4] = c.command();
+
+ AUXBuffer b(buf, buf + (response_data_size + 5));
+ hex_dump(hexbuf, b, b.size());
+ DEBUGF(DBG_SERIAL, "RES (%d B): <%s>", (int)b.size(), hexbuf);
+ cmd.parseBuf(b, false);
+ }
+
+ // Got the packet, process it
+ // n:length field >=3
+ // The buffer of n+2>=5 bytes contains:
+ // 0x3b <n>=3> <from> <to> <type> <n-3 bytes> <xsum>
+
+ DEBUGF(DBG_SERIAL, "Got %d bytes: ; payload length field: %d ; MSG:", n, buf[1]);
+ logBytes(buf, n + 2, getDeviceName(), DBG_SERIAL);
+ processResponse(cmd);
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::tcpReadResponse()
+{
+ int n, i;
+ unsigned char buf[BUFFER_SIZE] = {0};
+ AUXCommand cmd;
+
+ // We are not connected. Nothing to do.
+ if ( PortFD <= 0 )
+ return false;
+
+ timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 50000;
+ setsockopt(PortFD, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval));
+
+ // Drain the channel
+ while ((n = recv(PortFD, buf, sizeof(buf), MSG_DONTWAIT | MSG_PEEK)) > 0)
+ {
+ // DEBUGF(DBG_CAUX, "Got %d bytes: ", n);
+ // for (i = 0; i < n; i++)
+ // IDLog("%02x ", buf[i]);
+
+ for (i = 0; i < n;)
+ {
+ if (buf[i] == 0x3b)
+ {
+ int shft;
+ shft = i + buf[i + 1] + 3;
+ if (shft <= n)
+ {
+ AUXBuffer b(buf + i, buf + shft);
+ cmd.parseBuf(b);
+
+ char hexbuf[32 * 3] = {0};
+ hex_dump(hexbuf, b, b.size());
+ DEBUGF(DBG_SERIAL, "RES <%s>", hexbuf);
+
+ processResponse(cmd);
+ }
+ else
+ {
+ DEBUGF(DBG_SERIAL, "Partial message recv. dropping (i=%d %d/%d)", i, shft, n);
+ logBytes(buf + i, n - i, getDeviceName(), DBG_SERIAL);
+ recv(PortFD, buf, n, MSG_DONTWAIT);
+ break;
+ }
+ i = shft;
+ }
+ else
+ {
+ i++;
+ }
+ }
+ // Actually consume data we parsed. Leave the rest for later.
+ if (i > 0)
+ {
+ n = recv(PortFD, buf, i, MSG_DONTWAIT);
+ //DEBUGF(DBG_CAUX, "Consumed %d/%d bytes", n, i);
+ }
+ }
+ return true;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::readAUXResponse(AUXCommand c)
+{
+ if (getActiveConnection() == serialConnection)
+ return serialReadResponse(c);
+ else
+ return tcpReadResponse();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+int CelestronAUX::sendBuffer(AUXBuffer buf)
+{
+ if ( PortFD > 0 )
+ {
+ int n;
+
+ if (aux_tty_write((char*)buf.data(), buf.size(), CTS_TIMEOUT, &n) != TTY_OK)
+ return 0;
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ if (n == -1)
+ LOG_ERROR("CAUX::sendBuffer");
+ if ((unsigned)n != buf.size())
+ LOGF_WARN("sendBuffer: incomplete send n=%d size=%d", n, (int)buf.size());
+
+ char hexbuf[32 * 3] = {0};
+ hex_dump(hexbuf, buf, buf.size());
+ DEBUGF(DBG_SERIAL, "CMD <%s>", hexbuf);
+
+ return n;
+ }
+ else
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::sendAUXCommand(AUXCommand &command)
+{
+ AUXBuffer buf;
+ command.logCommand();
+
+ if (m_IsRTSCTS || !m_isHandController || getActiveConnection() != serialConnection)
+ // Direct connection (AUX/PC/USB port)
+ command.fillBuf(buf);
+ else
+ {
+ // connection is through HC serial and destination is not HC,
+ // convert AUX command to a passthrough command
+
+ // fixed len = 8
+ buf.resize(8);
+ // prefix
+ buf[0] = 0x50;
+ // length
+ buf[1] = 1 + command.dataSize();
+ // destination
+ buf[2] = command.destination();
+ buf[3] = command.command(); // command id
+ for (size_t i = 0; i < command.dataSize(); i++) // payload
+ {
+ buf[i + 4] = command.data()[i];
+ }
+ buf[7] = response_data_size = command.responseDataSize();
+ }
+
+ tcflush(PortFD, TCIOFLUSH);
+ return (sendBuffer(buf) == static_cast<int>(buf.size()));
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Wrap functions around the standard driver communication functions tty_read
+// and tty_write.
+// When the communication is serial, these wrap functions implement the
+// Celestron hardware handshake used by telescope serial ports AUX and PC.
+// When the communication is by network, these wrap functions are trasparent.
+// Read and write calls are passed, as is, to the standard functions tty_read
+// and tty_write.
+// 16-Feb-2020 Fabrizio Pollastri <mxgbot@gmail.com>
+////////////////////////////////////////////////////////////////////////////////
+void CelestronAUX::setRTS(bool rts)
+{
+ if (ioctl(PortFD, TIOCMGET, &m_ModemControl) == -1)
+ LOGF_ERROR("Error getting handshake lines %s(%d).", strerror(errno), errno);
+ if (rts)
+ m_ModemControl |= TIOCM_RTS;
+ else
+ m_ModemControl &= ~TIOCM_RTS;
+ if (ioctl(PortFD, TIOCMSET, &m_ModemControl) == -1)
+ LOGF_ERROR("Error setting handshake lines %s(%d).", strerror(errno), errno);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::waitCTS(float timeout)
+{
+ float step = timeout / 20.;
+ for (; timeout >= 0; timeout -= step)
+ {
+ std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(step)));
+ if (ioctl(PortFD, TIOCMGET, &m_ModemControl) == -1)
+ {
+ LOGF_ERROR("Error getting handshake lines %s(%d).", strerror(errno), errno);
+ return 0;
+ }
+ if (m_ModemControl & TIOCM_CTS)
+ return 1;
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::detectRTSCTS()
+{
+ setRTS(1);
+ bool retval = waitCTS(300.);
+ setRTS(0);
+ return retval;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::detectHC(char *version, size_t size)
+{
+ AUXBuffer b;
+ char buf[3];
+
+ b.resize(1);
+ b[0] = 'V';
+
+ // We are not connected. Nothing to do.
+ if ( PortFD <= 0 )
+ return false;
+
+ // send get firmware version command
+ if (sendBuffer(b) != (int)b.size())
+ return false;
+
+ // read response
+ int n;
+ if (aux_tty_read((char*)buf, 3, READ_TIMEOUT, &n) != TTY_OK)
+ return false;
+
+ // non error response must end with '#'
+ if (buf[2] != '#')
+ return false;
+
+ // return printable HC version
+ // fill in the version field
+ m_HCVersion[0] = static_cast<uint8_t>(buf[0]);
+ m_HCVersion[1] = static_cast<uint8_t>(buf[1]);
+ m_HCVersion[2] = 0;
+ m_HCVersion[3] = 0;
+ snprintf(version, size, "%d.%02d", static_cast<uint8_t>(buf[0]), static_cast<uint8_t>(buf[1]));
+
+ return true;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+int CelestronAUX::aux_tty_read(char *buf, int bufsiz, int timeout, int *n)
+{
+ int errcode;
+ DEBUGF(DBG_SERIAL, "aux_tty_read: %d", PortFD);
+
+ // if hardware flow control is required, set RTS to off to receive: PC port
+ // bahaves as half duplex.
+ if (m_IsRTSCTS)
+ setRTS(0);
+
+ if((errcode = tty_read(PortFD, buf, bufsiz, timeout, n)) != TTY_OK)
+ {
+ char errmsg[MAXRBUF] = {0};
+ tty_error_msg(errcode, errmsg, MAXRBUF);
+ LOGF_ERROR("%s", errmsg);
+ }
+
+ return errcode;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+int CelestronAUX::aux_tty_write(char *buf, int bufsiz, float timeout, int *n)
+{
+ int errcode, ne;
+ char errmsg[MAXRBUF];
+
+ //DEBUGF(DBG_CAUX, "aux_tty_write: %d", PortFD);
+
+ // if hardware flow control is required, set RTS to on then wait for CTS
+ // on to write: PC port bahaves as half duplex. RTS may be already on.
+ if (m_IsRTSCTS)
+ {
+ DEBUG(DBG_SERIAL, "aux_tty_write: set RTS");
+ setRTS(1);
+ DEBUG(DBG_SERIAL, "aux_tty_write: wait CTS");
+ if (!waitCTS(timeout))
+ {
+ LOGF_ERROR("Error getting handshake lines %s(%d).\n", strerror(errno), errno);
+ return TTY_TIME_OUT;
+ }
+ }
+
+ errcode = tty_write(PortFD, buf, bufsiz, n);
+
+ if (errcode != TTY_OK)
+ {
+ tty_error_msg(errcode, errmsg, MAXRBUF);
+ LOGF_ERROR("%s", errmsg);
+ return errcode;
+ }
+
+ // if hardware flow control is required, Wait for tx complete, set RTS to
+ // off, to receive (half duplex).
+ if (m_IsRTSCTS)
+ {
+ DEBUG(DBG_SERIAL, "aux_tty_write: clear RTS");
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ setRTS(0);
+
+ // ports requiring hardware flow control echo all sent characters,
+ // verify them.
+ DEBUG(DBG_SERIAL, "aux_tty_write: verify echo");
+ if ((errcode = tty_read(PortFD, errmsg, *n, READ_TIMEOUT, &ne)) != TTY_OK)
+ {
+ tty_error_msg(errcode, errmsg, MAXRBUF);
+ LOGF_ERROR("%s", errmsg);
+ return errcode;
+ }
+
+ if (*n != ne)
+ return TTY_WRITE_ERROR;
+
+ for (int i = 0; i < ne; i++)
+ if (buf[i] != errmsg[i])
+ return TTY_WRITE_ERROR;
+ }
+
+ return TTY_OK;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+bool CelestronAUX::tty_set_speed(speed_t speed)
+{
+ struct termios tty_setting;
+
+ if (tcgetattr(PortFD, &tty_setting))
+ {
+ LOGF_ERROR("Error getting tty attributes %s(%d).", strerror(errno), errno);
+ return false;
+ }
+
+ if (cfsetspeed(&tty_setting, speed))
+ {
+ LOGF_ERROR("Error setting serial speed %s(%d).", strerror(errno), errno);
+ return false;
+ }
+
+ if (tcsetattr(PortFD, TCSANOW, &tty_setting))
+ {
+ LOGF_ERROR("Error setting tty attributes %s(%d).", strerror(errno), errno);
+ return false;
+ }
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+///
+/////////////////////////////////////////////////////////////////////////////////////
+void CelestronAUX::hex_dump(char *buf, AUXBuffer data, size_t size)
+{
+ for (size_t i = 0; i < size; i++)
+ sprintf(buf + 3 * i, "%02X ", data[i]);
+
+ if (size > 0)
+ buf[3 * size - 1] = '\0';
+}
+
diff --git a/indi-celestronaux/celestronaux.h b/indi-celestronaux/celestronaux.h
new file mode 100644
index 0000000..6a79280
--- /dev/null
+++ b/indi-celestronaux/celestronaux.h
@@ -0,0 +1,442 @@
+/*
+ Celestron Aux Mount Driver.
+
+ Copyright (C) 2020 Paweł T. Jochym
+ Copyright (C) 2020 Fabrizio Pollastri
+ Copyright (C) 2020-2022 Jasem Mutlaq
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ JM 2022.07.07: Added Wedge support.
+*/
+
+#pragma once
+
+#include <indicom.h>
+#include <indiguiderinterface.h>
+#include <inditelescope.h>
+#include <indielapsedtimer.h>
+#include <connectionplugins/connectionserial.h>
+#include <connectionplugins/connectiontcp.h>
+#include <alignment/AlignmentSubsystemForDrivers.h>
+#include <indipropertyswitch.h>
+#include <indipropertynumber.h>
+#include <indipropertytext.h>
+#include <pid.h>
+#include <termios.h>
+
+#include "auxproto.h"
+
+class CelestronAUX :
+ public INDI::Telescope,
+ public INDI::GuiderInterface,
+ public INDI::AlignmentSubsystem::AlignmentSubsystemForDrivers
+{
+ public:
+ CelestronAUX();
+ ~CelestronAUX() override;
+
+ virtual bool ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[],
+ char *formats[], char *names[], int n) override;
+ virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override;
+ virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override;
+ virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override;
+ virtual bool ISSnoopDevice(XMLEle *root) override;
+
+ // Type defs
+ enum ScopeStatus_t
+ {
+ IDLE,
+ SLEWING_FAST,
+ APPROACH,
+ SLEWING_SLOW,
+ SLEWING_MANUAL,
+ TRACKING
+ };
+ ScopeStatus_t ScopeStatus;
+
+ enum AxisStatus
+ {
+ STOPPED,
+ SLEWING
+ };
+
+ enum AxisDirection
+ {
+ FORWARD,
+ REVERSE
+ };
+
+ // Previous motion direction
+ // TODO: Switch to AltAz from N-S/W-E
+ typedef enum
+ {
+ PREVIOUS_NS_MOTION_NORTH = DIRECTION_NORTH,
+ PREVIOUS_NS_MOTION_SOUTH = DIRECTION_SOUTH,
+ PREVIOUS_NS_MOTION_UNKNOWN = -1
+ } PreviousNSMotion_t;
+ typedef enum
+ {
+ PREVIOUS_WE_MOTION_WEST = DIRECTION_WEST,
+ PREVIOUS_WE_MOTION_EAST = DIRECTION_EAST,
+ PREVIOUS_WE_MOTION_UNKNOWN = -1
+ } PreviousWEMotion_t;
+
+ // Public to enable setting from ISSnoop
+ void syncCoordWrapPosition();
+
+ protected:
+ virtual void ISGetProperties(const char *dev) override;
+ virtual bool initProperties() override;
+ virtual bool updateProperties() override;
+ virtual bool saveConfigItems(FILE *fp) override;
+ virtual bool Handshake() override;
+ virtual bool Disconnect() override;
+
+ virtual const char *getDefaultName() override;
+ INDI::IHorizontalCoordinates AltAzFromRaDec(double ra, double dec, double ts);
+
+ virtual bool Sync(double ra, double dec) override;
+ virtual bool Goto(double ra, double dec) override;
+ virtual bool Abort() override;
+ virtual bool Park() override;
+ virtual bool UnPark() override;
+
+ virtual IPState GuideNorth(uint32_t ms) override;
+ virtual IPState GuideSouth(uint32_t ms) override;
+ virtual IPState GuideEast(uint32_t ms) override;
+ virtual IPState GuideWest(uint32_t ms) override;
+
+ //virtual bool HandleGetAutoguideRate(INDI_HO_AXIS axis, uint8_t rate);
+ //virtual bool HandleSetAutoguideRate(INDI_EQ_AXIS axis);
+ //virtual bool HandleGuidePulse(INDI_EQ_AXIS axis);
+ //virtual bool HandleGuidePulseDone(INDI_EQ_AXIS axis, bool done);
+
+ // TODO: Switch to AltAz from N-S/W-E
+ virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) override;
+ virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) override;
+
+ virtual bool ReadScopeStatus() override;
+ virtual void TimerHit() override;
+ virtual bool updateLocation(double latitude, double longitude, double elevation) override;
+
+ /////////////////////////////////////////////////////////////////////////////////////
+ /// Motion Control
+ /////////////////////////////////////////////////////////////////////////////////////
+ bool stopAxis(INDI_HO_AXIS axis);
+ bool isSlewing();
+
+ /**
+ * @brief SlewTo Go to a 24bit encoder position.
+ * @param axis AZ or ALT
+ * @param steps Encoder microsteps
+ * @param fast If true, use fast command to reach target. If false, use slow command.
+ * @return True if successful, false otherwise.
+ */
+ bool slewTo(INDI_HO_AXIS axis, uint32_t steps, bool fast = true);
+
+ /**
+ * @brief SlewByRate Slew an axis using variable rate speed.
+ * @param axis AZ or ALT
+ * @param rate -9 to +9. 0 means stop.
+ * For AZ, negative means left while positive means right.
+ * For Alt, negative is down while positive is up.
+ * @return True if successful, false otherwise.
+ */
+ bool slewByRate(INDI_HO_AXIS axis, int8_t rate);
+
+ // Go to index position or level
+ bool goHome(INDI_HO_AXIS axis);
+ bool isHomingDone(INDI_HO_AXIS axis);
+ bool m_HomingProgress[2] = {false, false};
+
+ /////////////////////////////////////////////////////////////////////////////////////
+ /// Tracking
+ /////////////////////////////////////////////////////////////////////////////////////
+ bool SetTrackEnabled(bool enabled) override;
+ bool SetTrackMode(uint8_t mode) override;
+ bool SetTrackRate(double raRate, double deRate) override;
+ void resetTracking();
+
+ /**
+ * @brief TrackByRate Set axis tracking rate in arcsecs/sec.
+ * @param axis AZ or ALT
+ * @param rate arcsecs/s. Zero would stop tracking.
+ * For AZ, negative means left while positive means right.
+ * For Alt, negative is down while positive is up.
+ * @return True if successful, false otherwise.
+ */
+ bool trackByRate(INDI_HO_AXIS axis, int32_t rate);
+
+ /**
+ * @brief trackByRate Track using specific mode (sidereal, solar, or lunar)
+ * @param axis AZ or ALT
+ * @param mode sidereal, solar, or lunar
+ * @return True if successful, false otherwise.
+ */
+ bool trackByMode(INDI_HO_AXIS axis, uint8_t mode);
+ bool isTrackingRequested();
+
+ bool getStatus(INDI_HO_AXIS axis);
+ bool getEncoder(INDI_HO_AXIS axis);
+
+ /////////////////////////////////////////////////////////////////////////////////////
+ /// Coord Wrap
+ /////////////////////////////////////////////////////////////////////////////////////
+ bool setCordWrapEnabled(bool enable);
+ bool getCordWrapEnabled();
+ bool setCordWrapPosition(uint32_t steps);
+ uint32_t getCordWrapPosition();
+
+ private:
+ /////////////////////////////////////////////////////////////////////////////////////
+ /// Misc
+ /////////////////////////////////////////////////////////////////////////////////////
+ double getNorthAz();
+ bool isNorthHemisphere() const
+ {
+ return m_Location.latitude >= 0;
+ }
+ bool getVersion(AUXTargets target);
+ void getVersions();
+ void hex_dump(char *buf, AUXBuffer data, size_t size);
+
+
+ double AzimuthToDegrees(double degree);
+ double DegreesToAzimuth(double degree);
+
+ double EncodersToDegrees(uint32_t steps);
+ uint32_t DegreesToEncoders(double degrees);
+
+ double EncodersToHours(uint32_t steps);
+ uint32_t HoursToEncoders(double hour);
+
+ double EncodersToDE(uint32_t steps, TelescopePierSide pierSide);
+ double DEToEncoders(double de);
+
+ void EncodersToAltAz(INDI::IHorizontalCoordinates &coords);
+ void EncodersToRADE(INDI::IEquatorialCoordinates &coords, TelescopePierSide &pierSide);
+ void RADEToEncoders(const INDI::IEquatorialCoordinates &coords, uint32_t &haEncoder, uint32_t &deEncoder);
+
+ /**
+ * @brief mountToSkyCoords Convert mount coordinates to equatorial sky coordinates
+ * @return True if successful, false otherwise.
+ * @note This works for both Alt-Az and Equatorial Mounts.
+ */
+ bool mountToSkyCoords();
+ /////////////////////////////////////////////////////////////////////////////////////
+ /// Guiding
+ /////////////////////////////////////////////////////////////////////////////////////
+ bool guidePulse(INDI_EQ_AXIS axis, uint32_t ms, int8_t rate);
+
+
+ private:
+ // Axis Information
+ AxisStatus m_AxisStatus[2] {STOPPED, STOPPED};
+ AxisDirection m_AxisDirection[2] {FORWARD, FORWARD};
+
+ // Guiding offset in steps
+ // For each pulse, we modify the offset so that we can add it to our current tracking traget
+ int32_t m_GuideOffset[2] = {0, 0};
+ double m_TrackRates[2] = {TRACKRATE_SIDEREAL, 0};
+
+ // approach distance
+ double Approach {1};
+ TelescopePierSide m_TargetPierSide {PIER_UNKNOWN};
+
+ // Tracking targets
+ INDI::IEquatorialCoordinates m_SkyTrackingTarget { 0, 0 };
+ INDI::IEquatorialCoordinates m_SkyGOTOTarget { 0, 0 };
+
+ // Actual Sky Equatorial Coordinates
+ INDI::IEquatorialCoordinates m_SkyCurrentRADE {0, 0};
+
+ // Current Mount Alt/Az or RA/DE
+ INDI::IEquatorialCoordinates m_MountCurrentRADE {0, 0};
+ INDI::IHorizontalCoordinates m_MountCurrentAltAz {0, 0};
+
+ INDI::ElapsedTimer m_TrackingElapsedTimer;
+
+
+ /////////////////////////////////////////////////////////////////////////////////////
+ /// Auxiliary Command Communication
+ /////////////////////////////////////////////////////////////////////////////////////
+ bool sendAUXCommand(AUXCommand &command);
+ void closeConnection();
+ void emulateGPS(AUXCommand &m);
+ bool serialReadResponse(AUXCommand c);
+ bool tcpReadResponse();
+ bool readAUXResponse(AUXCommand c);
+ bool processResponse(AUXCommand &cmd);
+ int sendBuffer(AUXBuffer buf);
+ void formatVersionString(char *s, int n, uint8_t *verBuf);
+
+ // GPS Emulation
+ bool m_GPSEmulation {false};
+
+ // Firmware
+ uint8_t m_MainBoardVersion[4] {0};
+ uint8_t m_AltitudeVersion[4] {0};
+ uint8_t m_AzimuthVersion[4] {0};
+ uint8_t m_HCVersion[4] {0};
+ uint8_t m_BATVersion[4] {0};
+ uint8_t m_WiFiVersion[4] {0};
+ uint8_t m_GPSVersion[4] {0};
+
+ // Coord Wrap
+ bool m_CordWrapActive {false};
+ int32_t m_CordWrapPosition {0};
+ uint32_t m_RequestedCordwrapPos;
+
+ // Manual Slewing NSWE
+ bool m_ManualMotionActive { false };
+
+ // Debug
+ uint32_t DBG_CAUX {0};
+ uint32_t DBG_SERIAL {0};
+
+ ///////////////////////////////////////////////////////////////////////////////
+ /// Communication
+ ///////////////////////////////////////////////////////////////////////////////
+ int m_ModemControl {0};
+ void setRTS(bool rts);
+ bool waitCTS(float timeout);
+ bool detectRTSCTS();
+ bool detectHC(char *version, size_t size);
+ int response_data_size;
+ int aux_tty_read(char *buf, int bufsiz, int timeout, int *n);
+ int aux_tty_write (char *buf, int bufsiz, float timeout, int *n);
+ bool tty_set_speed(speed_t speed);
+
+ // connection
+ bool m_IsRTSCTS {false};
+ bool m_isHandController {false};
+
+ ///////////////////////////////////////////////////////////////////////////////
+ /// Celestron AUX Properties
+ ///////////////////////////////////////////////////////////////////////////////
+
+ // Firmware
+ INDI::PropertyText FirmwareTP {7};
+ enum {FW_HC, FW_MB, FW_AZM, FW_ALT, FW_WiFi, FW_BAT, FW_GPS};
+ // Mount type
+ INDI::PropertySwitch MountTypeSP {2};
+ enum
+ {
+ MOUNT_EQUATORIAL,
+ MOUNT_ALTAZ
+ };
+
+ // Mount Cord wrap Toogle
+ INDI::PropertySwitch CordWrapToggleSP {2};
+
+ // Mount Coord wrap Position
+ INDI::PropertySwitch CordWrapPositionSP {4};
+ enum { CORDWRAP_N, CORDWRAP_E, CORDWRAP_S, CORDWRAP_W };
+
+ // Cordwrap base (0-encoder/True directions)
+ // Use 0-encoders / Sky directions as base for parking and cordwrap
+ INDI::PropertySwitch CordWrapBaseSP {2};
+ enum {CW_BASE_ENC, CW_BASE_SKY};
+
+ // GPS emulator
+ INDI::PropertySwitch GPSEmuSP {2};
+ enum { GPSEMU_OFF, GPSEMU_ON };
+
+ // Horizontal Coords
+ INDI::PropertyNumber HorizontalCoordsNP {2};
+
+ // Guide Rate
+ INDI::PropertyNumber GuideRateNP {2};
+
+ // Encoders
+ INDI::PropertyNumber EncoderNP {2};
+ // Angles
+ INDI::PropertyNumber AngleNP {2};
+
+ int32_t m_LastTrackRate[2] = {-1, -1};
+ double m_TrackStartSteps[2] = {0, 0};
+ double m_LastOffset[2] = {0, 0};
+ uint8_t m_OffsetSwitchSettle[2] = {0, 0};
+ bool m_IsWedge {false};
+
+ // PID controllers
+ INDI::PropertyNumber Axis1PIDNP {3};
+ INDI::PropertyNumber Axis2PIDNP {3};
+ enum
+ {
+ Propotional,
+ Derivative,
+ Integral
+ };
+
+ std::unique_ptr<PID> m_Controllers[2];
+
+ INDI::PropertySwitch PortTypeSP {2};
+ enum
+ {
+ PORT_AUX_PC,
+ PORT_HC_USB,
+ };
+
+ int m_ConfigPortType {PORT_AUX_PC};
+
+ // Home/Level
+ INDI::PropertySwitch HomeSP {3};
+ enum
+ {
+ HOME_AXIS1,
+ HOME_AXIS2,
+ HOME_ALL
+ };
+ //INDI::PropertyNumber GainNP {2};
+ ///////////////////////////////////////////////////////////////////////////////
+ /// Static Const Private Variables
+ ///////////////////////////////////////////////////////////////////////////////
+
+ private:
+
+ // One definition rule (ODR) constants
+ // AUX commands use 24bit integer as a representation of angle in units of
+ // fractional revolutions. Thus 2^24 steps makes full revolution.
+ static constexpr int32_t STEPS_PER_REVOLUTION {16777216};
+ static constexpr double STEPS_PER_DEGREE {STEPS_PER_REVOLUTION / 360.0};
+ static constexpr double STEPS_PER_ARCSEC {STEPS_PER_DEGREE / 3600.0};
+ static constexpr double DEGREES_PER_STEP {360.0 / STEPS_PER_REVOLUTION};
+
+ static constexpr double STEPS_PER_HOUR {STEPS_PER_REVOLUTION / 24.0};
+ static constexpr double HOURS_PER_STEP {24.0 / STEPS_PER_REVOLUTION};
+
+ // Measured rate that would result in 1 step/sec
+ static constexpr uint32_t GAIN_STEPS {80};
+
+ // MC_SET_POS_GUIDERATE & MC_SET_NEG_GUIDERATE use 24bit number rate in
+ static constexpr uint8_t RATE_PER_ARCSEC {4};
+
+ static constexpr uint32_t BUFFER_SIZE {10240};
+ // seconds
+ static constexpr uint8_t READ_TIMEOUT {1};
+ // ms
+ static constexpr uint8_t CTS_TIMEOUT {100};
+ // Coord Wrap
+ static constexpr const char *CORDWRAP_TAB {"Coord Wrap"};
+ static constexpr const char *MOUNTINFO_TAB {"Mount Info"};
+ // Track modes
+ static constexpr uint16_t AUX_SIDEREAL {0xffff};
+ static constexpr uint16_t AUX_SOLAR {0xfffe};
+ static constexpr uint16_t AUX_LUNAR {0xfffd};
+
+
+};
diff --git a/indi-celestronaux/config.h.cmake b/indi-celestronaux/config.h.cmake
new file mode 100644
index 0000000..be71a44
--- /dev/null
+++ b/indi-celestronaux/config.h.cmake
@@ -0,0 +1,10 @@
+#ifndef CONFIG_H
+#define CONFIG_H
+
+/* Define INDI Data Dir */
+#cmakedefine INDI_DATA_DIR "@INDI_DATA_DIR@"
+/* Define Driver version */
+#define CAUX_VERSION_MAJOR @CAUX_VERSION_MAJOR@
+#define CAUX_VERSION_MINOR @CAUX_VERSION_MINOR@
+
+#endif // CONFIG_H
diff --git a/indi-celestronaux/indi-celestronaux.spec b/indi-celestronaux/indi-celestronaux.spec
new file mode 100644
index 0000000..20ba305
--- /dev/null
+++ b/indi-celestronaux/indi-celestronaux.spec
@@ -0,0 +1,79 @@
+%define __cmake_in_source_build %{_vpath_builddir}
+Name: indi-celestronaux
+Version:1.9.8.git
+Release: %(date -u +%%Y%%m%%d%%H%%M%%S)%{?dist}
+Summary: Instrument Neutral Distributed Interface 3rd party drivers
+
+License: LGPLv2
+# See COPYRIGHT file for a description of the licenses and files covered
+
+URL: https://indilib.org
+Source0: https://github.com/indilib/indi-3rdparty/archive/master.tar.gz
+
+BuildRequires: cmake
+BuildRequires: libfli-devel
+BuildRequires: libnova-devel
+BuildRequires: qt5-qtbase-devel
+BuildRequires: systemd
+BuildRequires: gphoto2-devel
+BuildRequires: LibRaw-devel
+BuildRequires: indi-libs
+BuildRequires: indi-devel
+BuildRequires: libtiff-devel
+BuildRequires: cfitsio-devel
+BuildRequires: zlib-devel
+BuildRequires: gsl-devel
+BuildRequires: libcurl-devel
+BuildRequires: libjpeg-turbo-devel
+BuildRequires: fftw-devel
+BuildRequires: libftdi-devel
+BuildRequires: gpsd-devel
+BuildRequires: libdc1394-devel
+BuildRequires: boost-devel
+BuildRequires: boost-regex
+
+BuildRequires: gmock
+
+BuildRequires: pkgconfig(fftw3)
+BuildRequires: pkgconfig(cfitsio)
+BuildRequires: pkgconfig(libcurl)
+BuildRequires: pkgconfig(gsl)
+BuildRequires: pkgconfig(libjpeg)
+BuildRequires: pkgconfig(libusb-1.0)
+BuildRequires: pkgconfig(zlib)
+
+
+%description
+INDI is a distributed control protocol designed to operate
+astronomical instrumentation. INDI is small, flexible, easy to parse,
+and scalable. It supports common DCS functions such as remote control,
+data acquisition, monitoring, and a lot more. This is a 3rd party driver.
+
+
+%prep -v
+%autosetup -v -p1 -n indi-3rdparty-master
+
+%build
+# This package tries to mix and match PIE and PIC which is wrong and will
+# trigger link errors when LTO is enabled.
+# Disable LTO
+%define _lto_cflags %{nil}
+
+cd indi-celestronaux
+%cmake -DINDI_DATA_DIR=/usr/share/indi .
+make VERBOSE=1 %{?_smp_mflags} -j4
+
+%install
+cd indi-celestronaux
+make DESTDIR=%{buildroot} install
+
+%files
+%license LICENSE
+%{_bindir}/*
+%{_datadir}/indi/indi_celestronaux.xml
+
+
+%changelog
+* Sun Jul 19 2020 Jim Howard <jh.xsnrg+fedora@gmail.com> 1.8.7.git-1
+- update to build from git for copr, credit to Sergio Pascual and Christian Dersch for prior work on spec files
+
diff --git a/indi-celestronaux/indi_celestronaux.xml.cmake b/indi-celestronaux/indi_celestronaux.xml.cmake
new file mode 100644
index 0000000..749b0e2
--- /dev/null
+++ b/indi-celestronaux/indi_celestronaux.xml.cmake
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<driversList>
+<devGroup group="Telescopes">
+ <device label="Celestron AUX" manufacturer="Celestron">
+ <driver name="Celestron AUX">indi_celestron_aux</driver>
+ <version>@CAUX_VERSION_MAJOR@.@CAUX_VERSION_MINOR@</version>
+ </device>
+ <device label="Celestron WiFi" manufacturer="Celestron">
+ <driver name="Celestron AUX">indi_celestron_aux</driver>
+ <version>@CAUX_VERSION_MAJOR@.@CAUX_VERSION_MINOR@</version>
+ </device>
+ <device label="Evolution WiFi" manufacturer="Celestron">
+ <driver name="Celestron AUX">indi_celestron_aux</driver>
+ <version>@CAUX_VERSION_MAJOR@.@CAUX_VERSION_MINOR@</version>
+ </device>
+ <device label="Evolution WiFi Wedge" manufacturer="Celestron">
+ <driver name="Celestron AUX">indi_celestron_aux</driver>
+ <version>@CAUX_VERSION_MAJOR@.@CAUX_VERSION_MINOR@</version>
+ </device>
+ <device label="CGEM II WiFi" manufacturer="Celestron">
+ <driver name="Celestron AUX">indi_celestron_aux</driver>
+ <version>@CAUX_VERSION_MAJOR@.@CAUX_VERSION_MINOR@</version>
+ </device>
+ <device label="CGX WiFi" manufacturer="Celestron">
+ <driver name="Celestron AUX">indi_celestron_aux</driver>
+ <version>@CAUX_VERSION_MAJOR@.@CAUX_VERSION_MINOR@</version>
+ </device>
+ <device label="Advanced VX WiFi" manufacturer="Celestron">
+ <driver name="Celestron AUX">indi_celestron_aux</driver>
+ <version>@CAUX_VERSION_MAJOR@.@CAUX_VERSION_MINOR@</version>
+ </device>
+</devGroup>
+</driversList>
diff --git a/indi-celestronaux/simulator/nse_simulator.py b/indi-celestronaux/simulator/nse_simulator.py
new file mode 100644
index 0000000..5a3ceb6
--- /dev/null
+++ b/indi-celestronaux/simulator/nse_simulator.py
@@ -0,0 +1,259 @@
+#!/bin/env python3
+
+import asyncio
+import signal
+import socket
+import sys
+from socket import SOL_SOCKET, SO_BROADCAST, SO_REUSEADDR
+from nse_telescope import NexStarScope, repr_angle
+
+import curses
+
+telescope=None
+
+async def broadcast(sport=2000, dport=55555, host='255.255.255.255', seconds_to_sleep=5):
+ sck = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ sck.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
+ sck.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
+ # Fake msg. The app does not care for the payload
+ msg = 110*b'X'
+ sck.bind(('',sport))
+ telescope.print_msg('Broadcasting to port {0}'.format(dport))
+ telescope.print_msg('sleeping for: {0} seconds'.format(seconds_to_sleep))
+ while True :
+ bn = sck.sendto(msg,(host,dport))
+ await asyncio.sleep(seconds_to_sleep)
+ telescope.print_msg('Stopping broadcast')
+
+async def timer(seconds_to_sleep=1,telescope=None):
+ from time import time
+ t=time()
+ while True :
+ await asyncio.sleep(seconds_to_sleep)
+ if telescope :
+ telescope.tick(time()-t)
+ t=time()
+
+async def handle_port2000(reader, writer):
+ '''
+ This function handles initial communication with the WiFly module and
+ delegates the real job of simulating the scope to the NexStarScope class.
+ It also handles all the dirty details of actual communication.
+ '''
+
+ # The WiFly module is initially in the transparent mode and just passes
+ # the data to the serial connection. Unless the '$$$' sequence is detected.
+ # Then it switches to the command mode until the exit command is issued.
+ # The $$$ should be guarded by the 1s silence.
+ transparent=True
+ retry = 5
+ global telescope
+ # Endless comm loop.
+ connected=False
+ while True :
+ data = await reader.read(1024)
+ if not data :
+ writer.close()
+ telescope.print_msg('Connection closed. Closing server.')
+ return
+ elif not connected :
+ telescope.print_msg('App from {0} connected.'.format(writer.get_extra_info('peername')))
+ connected=True
+ retry = 5
+ addr = writer.get_extra_info('peername')
+ #print("-> Scope received %r from %r." % (data, addr))
+ resp = b''
+ if transparent :
+ if data[:3]==b'$$$' :
+ # Enter command mode
+ transparent = False
+ telescope.print_msg('App from {0} connected.'.format(addr))
+ resp = b'CMD\r\n'
+ else :
+ # pass it on to the scope for handling
+ resp = telescope.handle_msg(data)
+ else :
+ # We are in command mode detect exit and get out.
+ # Otherwise just echo what we got and ack.
+ message = b''
+ try :
+ message = data.decode('ascii').strip()
+ except UnicodeError :
+ # The data is invalid ascii - ignore it
+ pass
+ if message == 'exit' :
+ # get out of the command mode
+ transparent = True
+ resp = data + b'\r\nEXIT\r\n'
+ else :
+ resp = data + b'\r\nAOK\r\n<2.40-CEL> '
+ if resp :
+ #print("<- Server sending: %r" % resp )
+ writer.write(resp)
+ await writer.drain()
+
+#def signal_handler(signal, frame):
+# loop.stop()
+# sys.exit(0)
+
+#signal.signal(signal.SIGINT, signal_handler)
+
+def to_be(n, size):
+ b=bytearray(size)
+ i=size-1
+ while i >= 0:
+ b[i] = n % 256
+ n = n >> 8
+ i -= 1
+ return b
+def from_be(b):
+ n=0
+ for i in range(len(b)):
+ n = (n << 8) + b[i]
+ return n
+def to_le(n, size):
+ b=bytearray(size)
+ i=0
+ while i < size:
+ b[i] = n % 256
+ n = n >> 8
+ i += 1
+ return b
+def from_le(b):
+ n=0
+ for i in range(len(b)-1, -1, -1):
+ n = (n << 8) + b[i]
+ return n
+
+
+def handle_stellarium_cmd(tel, d):
+ import time
+ p=0
+ while p < len(d)-2:
+ psize=from_le(d[p:p+2])
+ if (psize > len(d) - p):
+ break
+ ptype=from_le(d[p+2:p+4])
+ if ptype == 0:
+ micros=from_le(d[p+4:p+12])
+ if abs((micros/1000000.0) - int(time.time())) > 60.0:
+ tel.print_msg('Client clock differs for more than one minute: '+str(int(micros/1000000.0))+'/'+str(int(time.time())))
+ targetraint=from_le(d[p+12:p+16])
+ targetdecint=from_le(d[p+16:p+20])
+ if (targetdecint > (4294967296 / 2)):
+ targetdecint = - (4294967296 - targetdecint)
+ targetra=(targetraint * 24.0) / 4294967296.0
+ targetdec=(targetdecint * 360.0) / 4294967296.0
+ tel.print_msg('GoTo {} {}'.format(repr_angle(targetra/360),
+ repr_angle(targetdec/360)))
+ p+=psize
+ else:
+ # No such cmd
+ tel.print_msg('Stellarium: unknown command ({})'.format(ptype))
+ p+=psize
+ return p
+
+def make_stellarium_status(tel,obs):
+ import math
+ import time
+ import ephem
+ from math import pi
+
+ alt=tel.alt
+ azm=tel.azm
+ obs.date=ephem.now()
+ rajnow, decjnow=obs.radec_of(azm*2*pi, alt*2*pi)
+ rajnow/=2*pi
+ decjnow/=2*pi
+ status=0
+ msg=bytearray(24)
+ msg[0:2]=to_le(24, 2)
+ msg[2:4]=to_le(0, 2)
+ tstamp=int(time.time())
+ msg[4:12]=to_le(tstamp, 8)
+ msg[12:16]=to_le(int(math.floor(rajnow * 4294967296.0)), 4)
+ msg[16:20]=to_le(int(math.floor(decjnow * 4294967296.0)), 4)
+ msg[20:24]=to_le(status, 4)
+ return msg
+
+
+connections = []
+
+async def report_scope_pos(sleep=0.1, scope=None, obs=None):
+ while True:
+ await asyncio.sleep(sleep)
+ for tr in connections:
+ tr.write(make_stellarium_status(scope,obs))
+
+
+class StellariumServer(asyncio.Protocol):
+
+ def __init__(self, *arg, **kwarg):
+ import ephem
+ global telescope
+
+ self.obs = ephem.Observer()
+ self.obs.lon, self.obs.lat = '20:02', '50:05'
+ self.telescope=telescope
+ asyncio.Protocol.__init__(self,*arg,**kwarg)
+
+ def connection_made(self, transport):
+ peername = transport.get_extra_info('peername')
+ if self.telescope is not None:
+ self.telescope.print_msg('Stellarium from {}\n'.format(peername))
+ self.transport = transport
+ connections.append(transport)
+
+ def connection_lost(self, exc):
+ try:
+ connections.remove(self.transport)
+ self.telescope.print_msg('Stellarium connection closed\n')
+ except ValueError:
+ pass
+
+ def data_received(self,data):
+ if self.telescope is not None:
+ handle_stellarium_cmd(telescope,data)
+
+def main(stdscr):
+ import ephem
+
+ global telescope
+
+ obs = ephem.Observer()
+ obs.lon, obs.lat = '20:02', '50:05'
+
+ if len(sys.argv) >1 and sys.argv[1]=='t':
+ telescope = NexStarScope(stdscr=None)
+ else :
+ telescope = NexStarScope(stdscr=stdscr)
+
+ loop = asyncio.get_event_loop()
+
+ scope = loop.run_until_complete(
+ asyncio.start_server(handle_port2000, host='', port=2000))
+
+ stell = loop.run_until_complete(
+ loop.create_server(StellariumServer,host='',port=10001))
+
+ telescope.print_msg('NSE simulator strted on {}.'.format(scope.sockets[0].getsockname()))
+ telescope.print_msg('Hit CTRL-C to stop.')
+
+ asyncio.ensure_future(broadcast())
+ asyncio.ensure_future(timer(0.1,telescope))
+ asyncio.ensure_future(report_scope_pos(0.1,telescope,obs))
+
+ try :
+ loop.run_forever()
+ except KeyboardInterrupt :
+ pass
+ telescope.print_msg('Simulator shutting down')
+ scope.close()
+ loop.run_until_complete(scope.wait_closed())
+ stell.close()
+ loop.run_until_complete(stell.wait_closed())
+
+ #loop.run_until_complete(asyncio.wait([broadcast(), timer(0.2), scope]))
+ loop.close()
+
+curses.wrapper(main)
diff --git a/indi-celestronaux/simulator/nse_telescope.py b/indi-celestronaux/simulator/nse_telescope.py
new file mode 100644
index 0000000..bd54ba9
--- /dev/null
+++ b/indi-celestronaux/simulator/nse_telescope.py
@@ -0,0 +1,760 @@
+#!/bin/env python3
+
+import struct
+import sys
+from math import pi
+
+import curses
+from collections import deque
+import binascii
+
+# ID tables
+targets={'ANY':0x00,
+ 'MB' :0x01,
+ 'HC' :0x04,
+ 'UKN1':0x05,
+ 'HC+':0x0d,
+ 'AZM':0x10,
+ 'ALT':0x11,
+ 'APP':0x20,
+ 'GPS':0xb0,
+ 'UKN2': 0xb4,
+ 'WiFi':0xb5,
+ 'BAT':0xb6,
+ 'CHG':0xb7,
+ 'LIGHT':0xbf
+ }
+trg_names={value:key for key, value in targets.items()}
+
+control={
+ 'HC' :0x04,
+ 'HC+':0x0d,
+ 'APP':0x20,
+ }
+
+commands={
+ 'MC_GET_POSITION':0x01,
+ 'MC_GOTO_FAST':0x02,
+ 'MC_SET_POSITION':0x04,
+ 'MC_GET_???':0x05,
+ 'MC_SET_POS_GUIDERATE':0x06,
+ 'MC_SET_NEG_GUIDERATE':0x07,
+ 'MC_LEVEL_START':0x0b,
+ 'MC_SET_POS_BACKLASH':0x10,
+ 'MC_SET_NEG_BACKLASH':0x11,
+ 'MC_SLEW_DONE':0x13,
+ 'MC_GOTO_SLOW':0x17,
+ 'MC_AT_INDEX':0x18,
+ 'MC_SEEK_INDEX':0x19,
+ 'MC_SET_MAXRATE':0x20,
+ 'MC_GET_MAXRATE':0x21,
+ 'MC_ENABLE_MAXRATE':0x22,
+ 'MC_MAXRATE_ENABLED':0x23,
+ 'MC_MOVE_POS':0x24,
+ 'MC_MOVE_NEG':0x25,
+ 'MC_ENABLE_CORDWRAP':0x38,
+ 'MC_DISABLE_CORDWRAP':0x39,
+ 'MC_SET_CORDWRAP_POS':0x3a,
+ 'MC_POLL_CORDWRAP':0x3b,
+ 'MC_GET_CORDWRAP_POS':0x3c,
+ 'MC_GET_POS_BACKLASH':0x40,
+ 'MC_GET_NEG_BACKLASH':0x41,
+ 'MC_GET_AUTOGUIDE_RATE':0x47,
+ 'MC_GET_APPROACH':0xfc,
+ 'MC_SET_APPROACH':0xfd,
+ 'GET_VER':0xfe,
+ }
+cmd_names={value:key for key, value in commands.items()}
+
+ACK_CMDS=[0x02,0x04,0x06,0x24,]
+
+MC_ALT=0x11
+MC_AZM=0x10
+
+trg_cmds = {
+ 'BAT': {
+ 0x10:'GET_VOLTAGE',
+ 0x18:'GET_SET_CURRENT',
+ },
+ 'CHG': {
+ 0x10: 'GET_SET_MODE',
+ },
+ 'LIGHT': {
+ 0x10:'GET_SET_LEVEL',
+ },
+}
+
+RATES = {
+ 0 : 0.0,
+ 1 : 1/(360*60),
+ 2 : 2/(360*60),
+ 3 : 5/(360*60),
+ 4 : 15/(360*60),
+ 5 : 30/(360*60),
+ 6 : 1/360,
+ 7 : 2/360,
+ 8 : 5/360,
+ 9 : 10/360
+}
+
+def print_command(cmd):
+ if cmd[2] in (0x10, 0x20):
+ try :
+ return 'Command: %s->%s [%s] len:%d: data:%r' % (
+ trg_names[cmd[1]],
+ trg_names[cmd[2]],
+ cmd_names[cmd[3]], cmd[0], cmd[4:-1])
+ except KeyError :
+ pass
+ try :
+ return 'Command: %s->%s [%02x] len:%d: data:%r' % (
+ trg_names[cmd[1]],
+ trg_names[cmd[2]],
+ cmd[3], cmd[0], cmd[4:-1])
+ except KeyError :
+ pass
+
+ return 'Command: %02x->%02x [%02x] len:%d: data:%r' % (
+ cmd[1], cmd[2], cmd[3], cmd[0], cmd[4:-1])
+
+
+def decode_command(cmd):
+ return (cmd[3], cmd[1], cmd[2], cmd[0], cmd[4:-1], cmd[-1])
+
+def split_cmds(data):
+ # split the data to commands
+ # the initial byte b'\03b' is removed from commands
+ cmds = []
+ b = 0
+ while True :
+ try :
+ p = data.index(b';', b)
+ cmds.append(data[p+1:p+abs(int(data[p+1]))+3])
+ b += abs(int(data[p+1]))+3
+ except ValueError:
+ return cmds
+
+def make_checksum(data):
+ return ((~sum([c for c in bytes(data)]) + 1) ) & 0xFF
+
+
+def ack_cmd(cmd):
+ c,f,t,l,d,cs=decode_command(cmd)
+ rsp=b''
+ if c in ACK_CMDS :
+ rsp=b';\x03'+bytes((t,f,c))
+ rsp+=bytes((make_checksum(rsp[1:]),))
+ return rsp
+
+def f2dms(f):
+ '''
+ Convert fraction of the full rotation to DMS triple (degrees).
+ '''
+ s= 1 if f>0 else -1
+ d=360*abs(f)
+ dd=int(d)
+ mm=int((d-dd)*60)
+ ss=(d-dd-mm/60)*3600
+ return dd,mm,ss
+
+def parse_pos(d):
+ '''
+ Parse first three bytes into the DMS string
+ '''
+ if len(d)>=3 :
+ pos=struct.unpack('!i',b'\x00'+d[:3])[0]/2**24
+ return u'%03d°%02d\'%04.1f"' % f2dms(pos)
+ else :
+ return u''
+
+def repr_pos(alt,azm):
+ return u'(%03d°%02d\'%04.1f", %03d°%02d\'%04.1f")' % (f2dms(alt) + f2dms(azm))
+
+def repr_angle(a):
+ return u'%03d°%02d\'%04.1f"' % f2dms(a)
+
+
+def unpack_int3(d):
+ return struct.unpack('!i',b'\x00'+d[:3])[0]/2**24
+
+def pack_int3(f):
+ return struct.pack('!i',int(f*(2**24)))[1:]
+
+def unpack_int2(d):
+ return struct.unpack('!i',b'\x00\x00'+d[:2])[0]
+
+def pack_int2(v):
+ return struct.pack('!i',int(v))[-2:]
+
+
+
+class NexStarScope:
+
+ __mcfw_ver=(7,11,5100//256,5100%256)
+ __hcfw_ver=(5,28,5300//256,5300%256)
+ __mbfw_ver=(1,0,0,1)
+
+ trg=('MB', 'HC', 'UKN1', 'HC+', 'AZM', 'ALT', 'APP',
+ 'GPS', 'WiFi', 'BAT', 'CHG', 'LIGHT')
+
+ def __init__(self, ALT=0.0, AZM=0.0, tui=True, stdscr=None):
+ self.tui=tui
+ self.alt=ALT
+ self.azm=AZM
+ self.trg_alt=self.alt
+ self.trg_azm=self.azm
+ self.alt_rate=0
+ self.azm_rate=0
+ self.alt_approach=0
+ self.azm_approach=0
+ self.last_cmd=''
+ self.slewing=False
+ self.guiding=False
+ self.goto=False
+ self.alt_guiderate=0.0
+ self.azm_guiderate=0.0
+ self.alt_maxrate=4000
+ self.azm_maxrate=4000
+ self.use_maxrate=False
+ self.cmd_log=deque(maxlen=30)
+ self.msg_log=deque(maxlen=10)
+ self.bat_current=2468
+ self.bat_voltage=12345678
+ self.lt_logo=64
+ self.lt_tray=128
+ self.lt_wifi=255
+ self.charge=False
+ self.cordwrap = False
+ self.cordwrap_pos = 0
+ self._other_handlers = {
+ 0x10: NexStarScope.cmd_0x10,
+ 0x18: NexStarScope.cmd_0x18,
+ 0xfe: NexStarScope.fw_version,
+ }
+ self._mc_handlers = {
+ 0x01 : NexStarScope.get_position,
+ 0x02 : NexStarScope.goto_fast,
+ 0x04 : NexStarScope.set_position,
+ 0x05 : NexStarScope.cmd_0x05,
+ 0x06 : NexStarScope.set_pos_guiderate,
+ 0x07 : NexStarScope.set_neg_guiderate,
+ 0x0b : NexStarScope.level_start,
+ 0x10 : NexStarScope.set_pos_backlash,
+ 0x11 : NexStarScope.set_neg_backlash,
+ 0x13 : NexStarScope.slew_done,
+ 0x17 : NexStarScope.goto_slow,
+ 0x18 : NexStarScope.at_index,
+ 0x19 : NexStarScope.seek_index,
+ 0x20 : NexStarScope.set_maxrate,
+ 0x21 : NexStarScope.get_maxrate,
+ 0x22 : NexStarScope.enable_maxrate,
+ 0x23 : NexStarScope.maxrate_enabled,
+ 0x24 : NexStarScope.move_pos,
+ 0x25 : NexStarScope.move_neg,
+ 0x38 : NexStarScope.enable_cordwrap,
+ 0x39 : NexStarScope.disable_cordwrap,
+ 0x3a : NexStarScope.set_cordwrap_pos,
+ 0x3b : NexStarScope.get_cordwrap,
+ 0x3c : NexStarScope.get_cordwrap_pos,
+ 0x40 : NexStarScope.get_pos_backlash,
+ 0x41 : NexStarScope.get_neg_backlash,
+ 0x47 : NexStarScope.get_autoguide_rate,
+ 0xfc : NexStarScope.get_approach,
+ 0xfd : NexStarScope.set_approach,
+ 0xfe : NexStarScope.fw_version,
+ }
+ if tui : self.init_dsp(stdscr)
+
+ def send_ack(self, data, snd, rcv):
+ return b''
+
+ def set_maxrate(self, data, snd, rcv):
+ if rcv==0x10 :
+ self.alt_maxrate=unpack_int2(data)
+ else :
+ self.azm_maxrate=unpack_int2(data)
+ return b''
+
+ def get_maxrate(self, data, snd, rcv):
+ if len(data) == 0 :
+ #return pack_int2(self.alt_maxrate) + pack_int2(self.azm_maxrate)
+ return bytes.fromhex('0fa01194')
+ else :
+ return b''
+
+ def enable_maxrate(self, data, snd, rcv):
+ self.use_maxrate=bool(data[0])
+ return b''
+
+ def maxrate_enabled(self, data, snd, rcv):
+ if self.use_maxrate :
+ return b'\x01'
+ else :
+ return b'\x00'
+
+ def cmd_0x10(self, data, snd, rcv):
+ if rcv == 0xbf : # LIGHT
+ if len(data)==2 : # Set level
+ if data[0]==0 :
+ self.lt_tray=data[1]
+ elif data[0]==1 :
+ self.lt_logo=data[1]
+ else :
+ self.lt_wifi=data[1]
+ return b''
+ elif len(data)==1: # Get level
+ if data[0]==0 :
+ return bytes([int(self.lt_tray%256)])
+ elif data[0]==1 :
+ return bytes([int(self.lt_logo%256)])
+ else :
+ return bytes([int(self.lt_wifi%256)])
+ else :
+ return b''
+ elif rcv == 0xb7 : # CHG
+ if len(data):
+ self.charge = bool(data[0])
+ return b''
+ else :
+ return bytes([int(self.charge)])
+ elif rcv == 0xb6 : # BAT
+ self.bat_voltage*=0.99
+ v=struct.pack('!i',int(self.bat_voltage))
+ return bytes.fromhex('0102') + v
+ else :
+ return b''
+
+ def cmd_0x18(self, data, snd, rcv):
+ if rcv == 0xb6 : # BAT
+ if len(data):
+ i=data[0]*256+data[1]
+ i=min(5000,i)
+ i=max(2000,i)
+ self.bat_current=i
+ return struct.pack('!i',int(self.bat_current))[-2:]
+
+
+ def get_position(self, data, snd, rcv):
+ try :
+ trg = trg_names[rcv]
+ except KeyError :
+ trg = '???'
+ if trg == 'ALT':
+ return pack_int3(self.alt)
+ else :
+ return pack_int3(self.azm)
+
+ def goto_fast(self, data, snd, rcv):
+ self.last_cmd='GOTO_FAST'
+ self.slewing=True
+ self.goto=True
+ self.guiding=False
+ self.alt_guiderate=0
+ self.azm_guiderate=0
+ if rcv==MC_ALT :
+ r=self.alt_maxrate/(360e3)
+ else :
+ r=self.azm_maxrate/(360e3)
+ a=unpack_int3(data)
+ if trg_names[rcv] == 'ALT':
+ self.trg_alt=a
+ if a-self.alt < 0 :
+ r = -r
+ self.alt_rate = r
+ else :
+ self.trg_azm=a%1.0
+ if self.trg_azm - self.azm < 0 :
+ r = -r
+ if abs(self.trg_azm - self.azm) > 0.5 :
+ r = -r
+ self.azm_rate = r
+ return b''
+
+ def set_position(self,data, snd, rcv):
+ return b''
+
+ def cmd_0x05(self, data, snd, rcv):
+ return bytes.fromhex('1685')
+
+ def set_pos_guiderate(self, data, snd, rcv):
+ # The 1.1 factor is experimental to fit the actual hardware
+ a=1.1*(2**24/1000/360/60/60)*unpack_int3(data) # (transform to rot/sec)
+ self.guiding = a>0
+ if trg_names[rcv] == 'ALT':
+ self.alt_guiderate=a
+ else :
+ self.azm_guiderate=a
+ return b''
+
+ def set_neg_guiderate(self, data, snd, rcv):
+ # The 1.1 factor is experimental to fit the actual hardware
+ a=1.1*(2**24/1000/360/60/60)*unpack_int3(data) # (transform to rot/sec)
+ self.guiding = a>0
+ if trg_names[rcv] == 'ALT':
+ self.alt_guiderate=-a
+ else :
+ self.azm_guiderate=-a
+ return b''
+
+ def level_start(self, data, snd, rcv):
+ return b''
+
+ def set_pos_backlash(self, data, snd, rcv):
+ return b''
+
+ def set_neg_backlash(self, data, snd, rcv):
+ return b''
+
+ def goto_slow(self, data, snd, rcv):
+ self.last_cmd='GOTO_SLOW'
+ self.slewing=True
+ self.goto=True
+ self.guiding=False
+ self.alt_guiderate=0
+ self.azm_guiderate=0
+ r=0.2/360
+ a=unpack_int3(data)
+ if trg_names[rcv] == 'ALT':
+ self.trg_alt=a
+ if self.alt < a :
+ self.alt_rate = r
+ else :
+ self.alt_rate = -r
+ else :
+ self.trg_azm=a%1.0
+ f = 1 if abs(self.azm - self.trg_azm)<0.5 else -1
+ if self.azm < self.trg_azm :
+ self.azm_rate = f*r
+ else :
+ self.azm_rate = -f*r
+ return b''
+
+ def slew_done(self, data, snd, rcv):
+ if rcv == MC_ALT :
+ return b'\x00' if self.alt_rate else b'\xff'
+ if rcv == MC_AZM :
+ return b'\x00' if self.azm_rate else b'\xff'
+
+ def at_index(self, data, snd, rcv):
+ return b'\x00'
+
+ def seek_index(self, data, snd, rcv):
+ return b''
+
+ def move_pos(self, data, snd, rcv):
+ self.last_cmd='MOVE_POS'
+ self.slewing=True
+ self.goto=False
+ r=RATES[int(data[0])]
+ if trg_names[rcv] == 'ALT':
+ self.alt_rate = r
+ else :
+ self.azm_rate = r
+ return b''
+
+ def move_neg(self, data, snd, rcv):
+ self.last_cmd='MOVE_NEG'
+ self.slewing=True
+ self.goto=False
+ r=RATES[int(data[0])]
+ if trg_names[rcv] == 'ALT':
+ self.alt_rate = -r
+ else :
+ self.azm_rate = -r
+ return b''
+
+ def enable_cordwrap(self, data, snd, rcv):
+ self.cordwrap = True
+ return b''
+
+ def disable_cordwrap(self, data, snd, rcv):
+ self.cordwrap = False
+ return b''
+
+ def set_cordwrap_pos(self, data, snd, rcv):
+ self.cordwrap_pos=struct.unpack('!i',b'\x00'+data[:3])[0]
+ return b''
+
+ def get_cordwrap(self, data, snd, rcv):
+ return b'\xFF' if self.cordwrap else b'\x00'
+
+ def get_cordwrap_pos(self, data, snd, rcv):
+ return pack_int3(self.cordwrap_pos)
+
+ def get_pos_backlash(self, data, snd, rcv):
+ return b'\x00'
+
+ def get_neg_backlash(self, data, snd, rcv):
+ return b'\x00'
+
+ def get_autoguide_rate(self, data, snd, rcv):
+ return b'\xf0'
+
+ def get_approach(self, data, snd, rcv):
+ try :
+ trg = trg_names[rcv]
+ except KeyError :
+ trg = '???'
+ if trg == 'ALT':
+ return bytes((self.alt_approach,))
+ else :
+ return bytes((self.azm_approach,))
+
+ def set_approach(self, data, snd, rcv):
+ try :
+ trg = trg_names[rcv]
+ except KeyError :
+ trg = '???'
+ if trg == 'ALT':
+ self.alt_approach=data[0]
+ else :
+ self.azm_approach=data[0]
+ return b''
+
+ def fw_version(self, data, snd, rcv):
+ try :
+ trg = trg_names[rcv]
+ except KeyError :
+ trg = '???'
+ if trg in ('ALT','AZM'):
+ return bytes(NexStarScope.__mcfw_ver)
+ elif trg in ('MB', ):
+ return bytes(NexStarScope.__mbfw_ver)
+ elif trg in ('HC', 'HC+'):
+ return bytes(NexStarScope.__hcfw_ver)
+ else :
+ return b''
+
+ def init_dsp(self,stdscr):
+ self.scr=stdscr
+ if stdscr :
+ self.cmd_log_w=curses.newwin(self.cmd_log.maxlen+2,60,0,50)
+ self.state_w=curses.newwin(1,80,0,0)
+ self.state_w.border()
+ self.pos_w=curses.newwin(4,25,1,0)
+ self.pos_w.border()
+ self.trg_w=curses.newwin(4,25,1,25)
+ self.trg_w.border()
+ self.rate_w=curses.newwin(4,25,5,0)
+ self.guide_w=curses.newwin(4,25,5,25)
+ self.other_w=curses.newwin(8,50,9,0)
+ self.msg_w=curses.newwin(self.msg_log.maxlen+2,50,17,0)
+ stdscr.refresh()
+
+ def update_dsp(self):
+ if self.scr :
+ mode = 'Idle'
+ if self.guiding : mode = 'Guiding'
+ if self.slewing : mode = 'Slewing'
+ self.state_w.clear()
+ self.state_w.addstr(0,1,'State: %8s' % mode)
+ self.state_w.refresh()
+ self.pos_w.clear()
+ self.pos_w.border()
+ self.pos_w.addstr(0,1,'Position:')
+ self.pos_w.addstr(1,3,'Alt: ' + repr_angle(self.alt))
+ self.pos_w.addstr(2,3,'Azm: ' + repr_angle(self.azm))
+ self.pos_w.refresh()
+ self.trg_w.clear()
+ self.trg_w.border()
+ self.trg_w.addstr(0,1,'Target:')
+ self.trg_w.addstr(1,3,'Alt: ' + repr_angle(self.trg_alt))
+ self.trg_w.addstr(2,3,'Azm: ' + repr_angle(self.trg_azm))
+ self.trg_w.refresh()
+ self.rate_w.clear()
+ self.rate_w.border()
+ self.rate_w.addstr(0,1,'Move rate:')
+ self.rate_w.addstr(1,3,'Alt: %+8.4f °/s' % (self.alt_rate*360))
+ self.rate_w.addstr(2,3,'Azm: %+8.4f °/s' % (self.azm_rate*360))
+ self.rate_w.refresh()
+ self.guide_w.clear()
+ self.guide_w.border()
+ self.guide_w.addstr(0,1,'Guide rate:')
+ self.guide_w.addstr(1,3,'Alt: %+8.4f "/s' % (self.alt_guiderate*360*60*60))
+ self.guide_w.addstr(2,3,'Azm: %+8.4f "/s' % (self.azm_guiderate*360*60*60))
+ self.guide_w.refresh()
+ self.other_w.clear()
+ self.other_w.border()
+ self.other_w.addstr(0,1,'Other:')
+ self.other_w.addstr(1,3,'BAT: %9.6f V' % (self.bat_voltage/1e6))
+ self.other_w.addstr(2,3,'CHG: %5.3f A' % (self.bat_current/1e3))
+ self.other_w.addstr(3,3,'LIGHTS: Logo: %d Tray: %d WiFi: %d' % (self.lt_logo, self.lt_tray, self.lt_wifi))
+ self.other_w.addstr(4,3,'Charge: %s' % ('On' if self.charge else 'Auto'))
+ if self.use_maxrate :
+ self.other_w.addstr(5,1,'*')
+ self.other_w.addstr(5,3,'Max rate ALT:%.2f AZM:%.2f' % (self.alt_maxrate/1e3, self.azm_maxrate/1e3))
+ self.other_w.addstr(6,3,'Cordwrap: %3s' % ('On' if self.cordwrap else 'Off'))
+ self.other_w.addstr(6,20,'Pos: ' + repr_angle(self.cordwrap_pos))
+ self.other_w.refresh()
+ self.cmd_log_w.clear()
+ self.cmd_log_w.border()
+ self.cmd_log_w.addstr(0,1,'Commands log')
+ for n,cmd in enumerate(self.cmd_log) :
+ self.cmd_log_w.addstr(n+1,1,cmd)
+ self.cmd_log_w.refresh()
+ self.msg_w.border()
+ self.msg_w.addstr(0,1,'Msg:')
+ for n,cmd in enumerate(self.msg_log) :
+ self.msg_w.addstr(n+1,1,cmd)
+ self.msg_w.refresh()
+
+ def show_status(self):
+ if self.tui and self.scr:
+ self.update_dsp()
+ else :
+ mode = 'Idle'
+ if self.guiding : mode = 'Guiding'
+ if self.slewing : mode = 'Slewing'
+ print('\r%8s: %s -> %s S(%+5.2f %+5.2f) G(%+.4f %+.4f) CMD: %10s' % (
+ mode, repr_pos(self.alt, self.azm),
+ repr_pos(self.trg_alt, self.trg_azm),
+ self.alt_rate*360, self.azm_rate*360, # deg/sec
+ self.alt_guiderate*360*60*60, self.azm_guiderate*360*60*60, # arcsec/sec
+ self.last_cmd), end='')
+ sys.stdout.flush()
+
+ def tick(self, interval):
+ eps=1e-6 # 0.1" precission
+ maxrate = 5/360
+ if self.last_cmd=='GOTO_FAST' :
+ eps*=100
+
+ self.alt += (self.alt_rate + self.alt_guiderate)*interval
+ self.azm += (self.azm_rate + self.azm_guiderate)*interval
+ if self.slewing and self.goto:
+ # AZM
+ r=self.trg_azm - self.azm
+ if abs(r)>0.5 :
+ r = -r
+ s=1 if r>0 else -1
+ mr=min(maxrate,abs(self.azm_rate))
+ if mr*interval > abs(r) :
+ mr/=2
+ self.azm_rate=s*min(mr,abs(r))
+ self.azm_rate=s*mr
+
+ # ALT
+ r=self.trg_alt - self.alt
+ s=1 if r>0 else -1
+ mr=min(maxrate,abs(self.alt_rate))
+ if mr*interval > abs(r) :
+ mr/=2
+ self.alt_rate=s*min(mr,abs(r))
+ self.alt_rate=s*mr
+
+ if abs(self.azm_rate) < eps and abs(self.alt_rate) < eps :
+ self.slewing=False
+ self.goto=False
+ if abs(self.azm_rate) < eps :
+ self.azm_rate=0
+ if abs(self.alt_rate) < eps :
+ self.alt_rate=0
+ self.show_status()
+
+ @property
+ def alt(self):
+ return self.__alt
+
+ @alt.setter
+ def alt(self,ALT):
+ self.__alt=ALT
+ # Altitude movement limits
+ #self.__alt = min(self.__alt,0.23)
+ #self.__alt = max(self.__alt,-0.03)
+
+ @property
+ def azm(self):
+ return self.__azm
+
+ @azm.setter
+ def azm(self,AZM):
+ self.__azm=AZM % 1.0
+
+ @property
+ def trg_alt(self):
+ return self.__trg_alt
+
+ @trg_alt.setter
+ def trg_alt(self,ALT):
+ self.__trg_alt=ALT
+ # Altitude movement limits
+ #self.__trg_alt = min(self.__trg_alt,0.24)
+ #self.__trg_alt = max(self.__trg_alt,-0.01)
+
+ @property
+ def trg_azm(self):
+ return self.__trg_azm
+
+ @trg_azm.setter
+ def trg_azm(self,AZM):
+ self.__trg_azm=AZM % 1.0
+
+ def handle_cmd(self, cmd):
+ #print("-> Scope received %s." % (print_command(cmd)))
+ try :
+ c,f,t,l,d,s=decode_command(cmd)
+ except IndexError :
+ self.print_msg("Malformed command: %r" % (cmd,))
+ return b''
+ resp=b''
+ if make_checksum(cmd[:-1]) != s :
+ self.print_msg("Wrong checksum. Ignoring.")
+ else :
+ resp = b';' + cmd
+ if t in (0x10, 0x11):
+ handlers=self._mc_handlers
+ try :
+ s=('%s[%s] ' % (trg_names[t], cmd_names[c])) + ''.join('%02x' % b for b in d)
+ except KeyError :
+ s=('MC[%02x]' % c) + ' ' + ''.join('%02x' % b for b in d)
+ else :
+ handlers=self._other_handlers
+ try :
+ s=('%s[%s]' % (trg_names[t],trg_cmds[trg_names[t]][c])) + ' ' + ''.join('%02x' % b for b in d)
+ except KeyError :
+ s=('%02x[%02x]' % (t,c)) + ' ' + ''.join('%02x' % b for b in d)
+ sr=b''
+ if c in handlers :
+ r = handlers[c](self,d,f,t)
+ sr = r
+ r = bytes((len(r)+3,t,f,c)) + r
+ resp += b';' + r + bytes((make_checksum(r),))
+ #print('Response: %r' % resp)
+ else :
+ #print('Scope got unknown command %02x' % c)
+ #print("-> Scope received %s." % (print_command(cmd)))
+ s = '** ' + s
+ pass
+
+ if 'MC_GET_POSITION' in s :
+ return resp
+
+ s += '-> ' + ''.join('%02x' % x for x in sr)
+
+ if self.cmd_log :
+ if s != self.cmd_log[-1] :
+ self.cmd_log.append(s)
+ else :
+ self.cmd_log.append(s)
+
+ return resp
+
+ def print_msg(self, msg):
+ if self.msg_log :
+ if msg != self.msg_log[-1] :
+ self.msg_log.append(msg)
+ else :
+ self.msg_log.append(msg)
+
+
+
+ def handle_msg(self, msg):
+ '''
+ React to message. Get AUX command(s) in the message and react to it.
+ Return a message simulating real AUX scope response.
+ '''
+ return b''.join([self.handle_cmd(cmd) for cmd in split_cmds(msg)])
+
+
+
+